nseel-compiler.c 187 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700
  1. /*
  2. Expression Evaluator Library (NS-EEL) v2
  3. Copyright (C) 2004-2013 Cockos Incorporated
  4. Copyright (C) 1999-2003 Nullsoft, Inc.
  5. nseel-compiler.c
  6. This software is provided 'as-is', without any express or implied
  7. warranty. In no event will the authors be held liable for any damages
  8. arising from the use of this software.
  9. Permission is granted to anyone to use this software for any purpose,
  10. including commercial applications, and to alter it and redistribute it
  11. freely, subject to the following restrictions:
  12. 1. The origin of this software must not be misrepresented; you must not
  13. claim that you wrote the original software. If you use this software
  14. in a product, an acknowledgment in the product documentation would be
  15. appreciated but is not required.
  16. 2. Altered source versions must be plainly marked as such, and must not be
  17. misrepresented as being the original software.
  18. 3. This notice may not be removed or altered from any source distribution.
  19. */
  20. #include "ns-eel-int.h"
  21. #include "denormal.h"
  22. #include "wdlcstring.h"
  23. #include <string.h>
  24. #include <math.h>
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #if !defined(EEL_TARGET_PORTABLE) && !defined(_WIN32)
  28. #include <sys/mman.h>
  29. #include <stdint.h>
  30. #include <unistd.h>
  31. #endif
  32. #include "glue_x86.h"
  33. #ifdef _WIN64
  34. #include "glue_x86_64.h"
  35. #endif // _WIN64
  36. #define NSEEL_VARS_MALLOC_CHUNKSIZE 8
  37. //#define LOG_OPT
  38. //#define EEL_PRINT_FAILS
  39. //#define EEL_VALIDATE_WORKTABLE_USE
  40. //#define EEL_VALIDATE_FSTUBS
  41. #ifdef EEL_PRINT_FAILS
  42. #ifdef _WIN32
  43. #define RET_MINUS1_FAIL(x) { OutputDebugString(x); return -1; }
  44. #else
  45. #define RET_MINUS1_FAIL(x) { printf("%s\n",x); return -1; }
  46. #endif
  47. #else
  48. #define RET_MINUS1_FAIL(x) return -1;
  49. #endif
  50. #ifdef EEL_DUMP_OPS
  51. FILE *g_eel_dump_fp, *g_eel_dump_fp2;
  52. #endif
  53. #ifdef EEL_VALIDATE_WORKTABLE_USE
  54. #define MIN_COMPUTABLE_SIZE 0
  55. #define COMPUTABLE_EXTRA_SPACE 64 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking
  56. #else
  57. #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)
  58. #define COMPUTABLE_EXTRA_SPACE 16 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking
  59. #endif
  60. /*
  61. P1 is rightmost parameter
  62. P2 is second rightmost, if any
  63. P3 is third rightmost, if any
  64. registers on x86 are (RAX etc on x86-64)
  65. P1(ret) EAX
  66. P2 EDI
  67. P3 ECX
  68. WTP RSI
  69. x86_64: r12 is a pointer to ram_state.blocks
  70. x86_64: r13 is a pointer to closenessfactor
  71. registers on PPC are:
  72. P1(ret) r3
  73. P2 r14
  74. P3 r15
  75. WTP r16 (r17 has the original value)
  76. r13 is a pointer to ram_state.blocks
  77. ppc uses f31 and f30 and others for certain constants
  78. */
  79. #ifdef EEL_TARGET_PORTABLE
  80. #define EEL_DOESNT_NEED_EXEC_PERMS
  81. #include "glue_port.h"
  82. #elif defined(__ppc__)
  83. #include "glue_ppc.h"
  84. #elif defined(__aarch64__)
  85. #include "glue_aarch64.h"
  86. #elif defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7)
  87. #include "glue_arm.h"
  88. #elif defined(_WIN64) || defined(__LP64__)
  89. #include "glue_x86_64.h"
  90. #else
  91. #include "glue_x86.h"
  92. #endif
  93. #ifndef GLUE_INVSQRT_NEEDREPL
  94. #define GLUE_INVSQRT_NEEDREPL 0
  95. #endif
  96. // used by //#eel-no-optimize:xxx, in ctx->optimizeDisableFlags
  97. #define OPTFLAG_NO_OPTIMIZE 1
  98. #define OPTFLAG_NO_FPSTACK 2
  99. #define OPTFLAG_NO_INLINEFUNC 4
  100. #define OPTFLAG_FULL_DENORMAL_CHECKS 8 // if set, denormals/NaN are always filtered on assign
  101. #define OPTFLAG_NO_DENORMAL_CHECKS 16 // if set and FULL not set, denormals/NaN are never filtered on assign
  102. #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...)
  103. #define MAX_SUB_NAMESPACES 32
  104. typedef struct
  105. {
  106. const char *namespacePathToThis;
  107. const char *subParmInfo[MAX_SUB_NAMESPACES];
  108. } namespaceInformation;
  109. static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
  110. int *NSEEL_getstats()
  111. {
  112. return nseel_evallib_stats;
  113. }
  114. static int findLineNumber(const char *exp, int byteoffs)
  115. {
  116. int lc=0;
  117. while (byteoffs-->0 && *exp) if (*exp++ =='\n') lc++;
  118. return lc;
  119. }
  120. static int nseel_vms_referencing_globallist_cnt;
  121. nseel_globalVarItem *nseel_globalreg_list;
  122. static EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent);
  123. static void *__newBlock(llBlock **start,int size, int wantMprotect);
  124. #define OPCODE_IS_TRIVIAL(x) ((x)->opcodeType <= OPCODETYPE_VARPTRPTR)
  125. enum {
  126. OPCODETYPE_DIRECTVALUE=0,
  127. OPCODETYPE_DIRECTVALUE_TEMPSTRING, // like directvalue, but will generate a new tempstring value on generate
  128. OPCODETYPE_VALUE_FROM_NAMESPACENAME, // this.* or namespace.* are encoded this way
  129. OPCODETYPE_VARPTR,
  130. OPCODETYPE_VARPTRPTR,
  131. OPCODETYPE_FUNC1,
  132. OPCODETYPE_FUNC2,
  133. OPCODETYPE_FUNC3,
  134. OPCODETYPE_FUNCX,
  135. OPCODETYPE_MOREPARAMS,
  136. OPCODETYPE_INVALID,
  137. };
  138. struct opcodeRec
  139. {
  140. int opcodeType;
  141. int fntype;
  142. void *fn;
  143. union {
  144. struct opcodeRec *parms[3];
  145. struct {
  146. double directValue;
  147. EEL_F *valuePtr; // if direct value, valuePtr can be cached
  148. } dv;
  149. } parms;
  150. int namespaceidx;
  151. // OPCODETYPE_VALUE_FROM_NAMESPACENAME (relname is either empty or blah)
  152. // OPCODETYPE_VARPTR if it represents a global variable, will be nonempty
  153. // OPCODETYPE_FUNC* with fntype=FUNCTYPE_EELFUNC
  154. const char *relname;
  155. };
  156. static void *newTmpBlock(compileContext *ctx, int size)
  157. {
  158. const int align = 8;
  159. const int a1=align-1;
  160. char *p=(char*)__newBlock(&ctx->tmpblocks_head,size+a1, 0);
  161. return p+((align-(((INT_PTR)p)&a1))&a1);
  162. }
  163. static void *__newBlock_align(compileContext *ctx, int size, int align, int isForCode)
  164. {
  165. const int a1=align-1;
  166. char *p=(char*)__newBlock(
  167. (
  168. isForCode < 0 ? (isForCode == -2 ? &ctx->pblocks : &ctx->tmpblocks_head) :
  169. isForCode > 0 ? &ctx->blocks_head :
  170. &ctx->blocks_head_data) ,size+a1, isForCode>0);
  171. return p+((align-(((INT_PTR)p)&a1))&a1);
  172. }
  173. static opcodeRec *newOpCode(compileContext *ctx, const char *str, int opType)
  174. {
  175. const size_t strszfull = str ? strlen(str) : 0;
  176. const size_t str_sz = wdl_min(NSEEL_MAX_VARIABLE_NAMELEN, strszfull);
  177. opcodeRec *rec = (opcodeRec*)__newBlock_align(ctx,
  178. (int) (sizeof(opcodeRec) + (str_sz>0 ? str_sz+1 : 0)),
  179. 8, ctx->isSharedFunctions ? 0 : -1);
  180. if (rec)
  181. {
  182. memset(rec,0,sizeof(*rec));
  183. rec->opcodeType = opType;
  184. if (str_sz > 0)
  185. {
  186. char *p = (char *)(rec+1);
  187. memcpy(p,str,str_sz);
  188. p[str_sz]=0;
  189. rec->relname = p;
  190. }
  191. else
  192. {
  193. rec->relname = "";
  194. }
  195. }
  196. return rec;
  197. }
  198. #define newCodeBlock(x,a) __newBlock_align(ctx,x,a,1)
  199. #define newDataBlock(x,a) __newBlock_align(ctx,x,a,0)
  200. #define newCtxDataBlock(x,a) __newBlock_align(ctx,x,a,-2)
  201. static void freeBlocks(llBlock **start);
  202. static int __growbuf_resize(eel_growbuf *buf, int newsize)
  203. {
  204. if (newsize<0)
  205. {
  206. free(buf->ptr);
  207. buf->ptr=NULL;
  208. buf->alloc=buf->size=0;
  209. return 0;
  210. }
  211. if (newsize > buf->alloc)
  212. {
  213. const int newalloc = newsize + 4096 + newsize/2;
  214. void *newptr = realloc(buf->ptr,newalloc);
  215. if (!newptr)
  216. {
  217. newptr = malloc(newalloc);
  218. if (!newptr) return 1;
  219. if (buf->ptr && buf->size) memcpy(newptr,buf->ptr,buf->size);
  220. free(buf->ptr);
  221. buf->ptr=newptr;
  222. }
  223. else
  224. buf->ptr = newptr;
  225. buf->alloc=newalloc;
  226. }
  227. buf->size = newsize;
  228. return 0;
  229. }
  230. #ifndef DECL_ASMFUNC
  231. #define DECL_ASMFUNC(x) \
  232. void nseel_asm_##x(void); \
  233. void nseel_asm_##x##_end(void);
  234. void _asm_megabuf(void);
  235. void _asm_megabuf_end(void);
  236. void _asm_gmegabuf(void);
  237. void _asm_gmegabuf_end(void);
  238. #endif
  239. DECL_ASMFUNC(booltofp)
  240. DECL_ASMFUNC(fptobool)
  241. DECL_ASMFUNC(fptobool_rev)
  242. DECL_ASMFUNC(sin)
  243. DECL_ASMFUNC(cos)
  244. DECL_ASMFUNC(tan)
  245. DECL_ASMFUNC(1pdd)
  246. DECL_ASMFUNC(2pdd)
  247. DECL_ASMFUNC(2pdds)
  248. DECL_ASMFUNC(1pp)
  249. DECL_ASMFUNC(2pp)
  250. DECL_ASMFUNC(sqr)
  251. DECL_ASMFUNC(sqrt)
  252. DECL_ASMFUNC(log)
  253. DECL_ASMFUNC(log10)
  254. DECL_ASMFUNC(abs)
  255. DECL_ASMFUNC(min)
  256. DECL_ASMFUNC(max)
  257. DECL_ASMFUNC(min_fp)
  258. DECL_ASMFUNC(max_fp)
  259. DECL_ASMFUNC(sig)
  260. DECL_ASMFUNC(sign)
  261. DECL_ASMFUNC(band)
  262. DECL_ASMFUNC(bor)
  263. DECL_ASMFUNC(bnot)
  264. DECL_ASMFUNC(bnotnot)
  265. DECL_ASMFUNC(if)
  266. DECL_ASMFUNC(fcall)
  267. DECL_ASMFUNC(repeat)
  268. DECL_ASMFUNC(repeatwhile)
  269. DECL_ASMFUNC(equal)
  270. DECL_ASMFUNC(equal_exact)
  271. DECL_ASMFUNC(notequal_exact)
  272. DECL_ASMFUNC(notequal)
  273. DECL_ASMFUNC(below)
  274. DECL_ASMFUNC(above)
  275. DECL_ASMFUNC(beloweq)
  276. DECL_ASMFUNC(aboveeq)
  277. DECL_ASMFUNC(assign)
  278. DECL_ASMFUNC(assign_fromfp)
  279. DECL_ASMFUNC(assign_fast)
  280. DECL_ASMFUNC(assign_fast_fromfp)
  281. DECL_ASMFUNC(add)
  282. DECL_ASMFUNC(sub)
  283. DECL_ASMFUNC(add_op)
  284. DECL_ASMFUNC(sub_op)
  285. DECL_ASMFUNC(add_op_fast)
  286. DECL_ASMFUNC(sub_op_fast)
  287. DECL_ASMFUNC(mul)
  288. DECL_ASMFUNC(div)
  289. DECL_ASMFUNC(mul_op)
  290. DECL_ASMFUNC(div_op)
  291. DECL_ASMFUNC(mul_op_fast)
  292. DECL_ASMFUNC(div_op_fast)
  293. DECL_ASMFUNC(mod)
  294. DECL_ASMFUNC(shl)
  295. DECL_ASMFUNC(shr)
  296. DECL_ASMFUNC(mod_op)
  297. DECL_ASMFUNC(or)
  298. DECL_ASMFUNC(or0)
  299. DECL_ASMFUNC(xor)
  300. DECL_ASMFUNC(xor_op)
  301. DECL_ASMFUNC(and)
  302. DECL_ASMFUNC(or_op)
  303. DECL_ASMFUNC(and_op)
  304. DECL_ASMFUNC(uplus)
  305. DECL_ASMFUNC(uminus)
  306. DECL_ASMFUNC(invsqrt)
  307. DECL_ASMFUNC(dbg_getstackptr)
  308. #ifdef NSEEL_EEL1_COMPAT_MODE
  309. DECL_ASMFUNC(exec2)
  310. #endif
  311. DECL_ASMFUNC(stack_push)
  312. DECL_ASMFUNC(stack_pop)
  313. DECL_ASMFUNC(stack_pop_fast) // just returns value, doesn't mod param
  314. DECL_ASMFUNC(stack_peek)
  315. DECL_ASMFUNC(stack_peek_int)
  316. DECL_ASMFUNC(stack_peek_top)
  317. DECL_ASMFUNC(stack_exch)
  318. static void *NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx)
  319. {
  320. if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->gram_blocks);
  321. return data;
  322. }
  323. static void *NSEEL_PProc_Stack(void *data, int data_size, compileContext *ctx)
  324. {
  325. codeHandleType *ch=ctx->tmpCodeHandle;
  326. if (data_size>0)
  327. {
  328. UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1);
  329. UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
  330. ch->want_stack=1;
  331. if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
  332. data=EEL_GLUE_set_immediate(data, stackptr);
  333. data=EEL_GLUE_set_immediate(data, m1); // and
  334. data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or
  335. }
  336. return data;
  337. }
  338. static void *NSEEL_PProc_Stack_PeekInt(void *data, int data_size, compileContext *ctx, INT_PTR offs)
  339. {
  340. codeHandleType *ch=ctx->tmpCodeHandle;
  341. if (data_size>0)
  342. {
  343. UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1);
  344. UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
  345. ch->want_stack=1;
  346. if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
  347. data=EEL_GLUE_set_immediate(data, stackptr);
  348. data=EEL_GLUE_set_immediate(data, offs);
  349. data=EEL_GLUE_set_immediate(data, m1); // and
  350. data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or
  351. }
  352. return data;
  353. }
  354. static void *NSEEL_PProc_Stack_PeekTop(void *data, int data_size, compileContext *ctx)
  355. {
  356. codeHandleType *ch=ctx->tmpCodeHandle;
  357. if (data_size>0)
  358. {
  359. UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
  360. ch->want_stack=1;
  361. if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
  362. data=EEL_GLUE_set_immediate(data, stackptr);
  363. }
  364. return data;
  365. }
  366. #if defined(_MSC_VER) && _MSC_VER >= 1400
  367. //static double __floor(double a) { return floor(a); }
  368. //static double __ceil(double a) { return ceil(a); }
  369. #define floor __floor
  370. #define ceil __ceil
  371. #endif
  372. #ifdef NSEEL_EEL1_COMPAT_MODE
  373. static double eel1band(double a, double b)
  374. {
  375. return (fabs(a)>NSEEL_CLOSEFACTOR && fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0;
  376. }
  377. static double eel1bor(double a, double b)
  378. {
  379. return (fabs(a)>NSEEL_CLOSEFACTOR || fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0;
  380. }
  381. static double eel1sigmoid(double x, double constraint)
  382. {
  383. double t = (1+exp(-x * (constraint)));
  384. return fabs(t)>NSEEL_CLOSEFACTOR ? 1.0/t : 0;
  385. }
  386. #endif
  387. #define FUNCTIONTYPE_PARAMETERCOUNTMASK 0xff
  388. #define BIF_NPARAMS_MASK 0x7ffff00
  389. #define BIF_RETURNSONSTACK 0x0000100
  390. #define BIF_LASTPARMONSTACK 0x0000200
  391. #define BIF_RETURNSBOOL 0x0000400
  392. #define BIF_LASTPARM_ASBOOL 0x0000800
  393. // 0x00?0000 -- taken by FP stack flags
  394. #define BIF_TAKES_VARPARM 0x0400000
  395. #define BIF_TAKES_VARPARM_EX 0x0C00000 // this is like varparm but check count exactly
  396. #define BIF_WONTMAKEDENORMAL 0x0100000
  397. #define BIF_CLEARDENORMAL 0x0200000
  398. #if defined(GLUE_HAS_FXCH) && GLUE_MAX_FPSTACK_SIZE > 0
  399. #define BIF_SECONDLASTPARMST 0x0001000 // use with BIF_LASTPARMONSTACK only (last two parameters get passed on fp stack)
  400. #define BIF_LAZYPARMORDERING 0x0002000 // allow optimizer to avoid fxch when using BIF_TWOPARMSONFPSTACK_LAZY etc
  401. #define BIF_REVERSEFPORDER 0x0004000 // force a fxch (reverse order of last two parameters on fp stack, used by comparison functions)
  402. #ifndef BIF_FPSTACKUSE
  403. #define BIF_FPSTACKUSE(x) (((x)>=0&&(x)<8) ? ((7-(x))<<16):0)
  404. #endif
  405. #ifndef BIF_GETFPSTACKUSE
  406. #define BIF_GETFPSTACKUSE(x) (7 - (((x)>>16)&7))
  407. #endif
  408. #else
  409. // do not support fp stack use unless GLUE_HAS_FXCH and GLUE_MAX_FPSTACK_SIZE>0
  410. #define BIF_SECONDLASTPARMST 0
  411. #define BIF_LAZYPARMORDERING 0
  412. #define BIF_REVERSEFPORDER 0
  413. #define BIF_FPSTACKUSE(x) 0
  414. #define BIF_GETFPSTACKUSE(x) 0
  415. #endif
  416. #define BIF_TWOPARMSONFPSTACK (BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK)
  417. #define BIF_TWOPARMSONFPSTACK_LAZY (BIF_LAZYPARMORDERING|BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK)
  418. #ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG
  419. static double sqrt_fabs(double a) { return sqrt(fabs(a)); }
  420. #endif
  421. EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F f);
  422. #define FNPTR_HAS_CONDITIONAL_EXEC(op) \
  423. (op->fntype == FN_LOGICAL_AND || \
  424. op->fntype == FN_LOGICAL_OR || \
  425. op->fntype == FN_IF_ELSE || \
  426. op->fntype == FN_WHILE || \
  427. op->fntype == FN_LOOP)
  428. static functionType fnTable1[] = {
  429. #ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG
  430. { "sin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sin} },
  431. { "cos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&cos} },
  432. { "tan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&tan} },
  433. { "sqrt", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sqrt_fabs}, },
  434. { "log", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log} },
  435. { "log10", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log10} },
  436. #else
  437. { "sin", nseel_asm_sin,nseel_asm_sin_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL|BIF_FPSTACKUSE(1) },
  438. { "cos", nseel_asm_cos,nseel_asm_cos_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL|BIF_FPSTACKUSE(1) },
  439. { "tan", nseel_asm_tan,nseel_asm_tan_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) },
  440. { "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_WONTMAKEDENORMAL },
  441. { "log", nseel_asm_log,nseel_asm_log_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), },
  442. { "log10", nseel_asm_log10,nseel_asm_log10_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), },
  443. #endif
  444. { "asin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&asin}, },
  445. { "acos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&acos}, },
  446. { "atan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&atan}, },
  447. { "atan2", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&atan2}, },
  448. { "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, },
  449. { "abs", nseel_asm_abs,nseel_asm_abs_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(0)|BIF_WONTMAKEDENORMAL },
  450. { "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) },
  451. { "min", nseel_asm_min,nseel_asm_min_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL },
  452. { "max", nseel_asm_max,nseel_asm_max_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL },
  453. { "sign", nseel_asm_sign,nseel_asm_sign_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL, },
  454. { "rand", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&nseel_int_rand}, },
  455. //{ "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&floor} },
  456. //{ "ceil", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&ceil} },
  457. { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), {GLUE_INVSQRT_NEEDREPL} },
  458. { "__dbg_getstackptr", nseel_asm_dbg_getstackptr,nseel_asm_dbg_getstackptr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1), },
  459. #ifdef NSEEL_EEL1_COMPAT_MODE
  460. { "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&eel1sigmoid}, },
  461. // these differ from _and/_or, they always evaluate both...
  462. { "band", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1band}, },
  463. { "bor", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1bor}, },
  464. {"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL},
  465. {"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL},
  466. #endif // end EEL1 compat
  467. {"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM},
  468. {"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM},
  469. {"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM},
  470. {"__memtop",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemTop},NSEEL_PProc_RAM},
  471. {"mem_set_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_SetValues},NSEEL_PProc_RAM},
  472. {"mem_get_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_GetValues},NSEEL_PProc_RAM},
  473. {"stack_push",nseel_asm_stack_push,nseel_asm_stack_push_end,1|BIF_FPSTACKUSE(0),{0,},NSEEL_PProc_Stack},
  474. {"stack_pop",nseel_asm_stack_pop,nseel_asm_stack_pop_end,1|BIF_FPSTACKUSE(1),{0,},NSEEL_PProc_Stack},
  475. {"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},
  476. {"stack_exch",nseel_asm_stack_exch,nseel_asm_stack_exch_end,1|BIF_FPSTACKUSE(1), {0,},NSEEL_PProc_Stack_PeekTop},
  477. };
  478. static eel_function_table default_user_funcs;
  479. static int functable_lowerbound(functionType *list, int list_sz, const char *name, int *ismatch)
  480. {
  481. int a = 0, c = list_sz;
  482. while (a != c)
  483. {
  484. const int b = (a+c)/2;
  485. const int cmp = stricmp(name,list[b].name);
  486. if (cmp > 0) a = b+1;
  487. else if (cmp < 0) c = b;
  488. else
  489. {
  490. *ismatch = 1;
  491. return b;
  492. }
  493. }
  494. *ismatch = 0;
  495. return a;
  496. }
  497. static int funcTypeCmp(const void *a, const void *b) { return stricmp(((functionType*)a)->name,((functionType*)b)->name); }
  498. functionType *nseel_getFunctionByName(compileContext *ctx, const char *name, int *mchk)
  499. {
  500. eel_function_table *tab = ctx && ctx->registered_func_tab ? ctx->registered_func_tab : &default_user_funcs;
  501. static char sorted;
  502. const int fn1size = (int) (sizeof(fnTable1)/sizeof(fnTable1[0]));
  503. int idx,match;
  504. if (!sorted)
  505. {
  506. NSEEL_HOSTSTUB_EnterMutex();
  507. if (!sorted) qsort(fnTable1,fn1size,sizeof(fnTable1[0]),funcTypeCmp);
  508. sorted=1;
  509. NSEEL_HOSTSTUB_LeaveMutex();
  510. }
  511. idx=functable_lowerbound(fnTable1,fn1size,name,&match);
  512. if (match) return fnTable1+idx;
  513. if ((!ctx || !(ctx->current_compile_flags&NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS)) && tab->list)
  514. {
  515. idx=functable_lowerbound(tab->list,tab->list_size,name,&match);
  516. if (match)
  517. {
  518. if (mchk)
  519. {
  520. while (idx>0 && !stricmp(tab->list[idx-1].name,name)) idx--;
  521. *mchk = tab->list_size - 1 - idx;
  522. }
  523. return tab->list + idx;
  524. }
  525. }
  526. return NULL;
  527. }
  528. int NSEEL_init() // returns 0 on success
  529. {
  530. #ifdef EEL_VALIDATE_FSTUBS
  531. int a;
  532. for (a=0;a < sizeof(fnTable1)/sizeof(fnTable1[0]);a++)
  533. {
  534. char *code_startaddr = (char*)fnTable1[a].afunc;
  535. char *endp = (char *)fnTable1[a].func_e;
  536. // validate
  537. int sz=0;
  538. char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz);
  539. if (f+sz > endp)
  540. {
  541. #ifdef _WIN32
  542. OutputDebugString("bad eel function stub\n");
  543. #else
  544. printf("bad eel function stub\n");
  545. #endif
  546. *(char *)NULL = 0;
  547. }
  548. }
  549. #ifdef _WIN32
  550. OutputDebugString("eel function stub (builtin) validation complete\n");
  551. #else
  552. printf("eel function stub (builtin) validation complete\n");
  553. #endif
  554. #endif
  555. NSEEL_quit();
  556. return 0;
  557. }
  558. void NSEEL_quit()
  559. {
  560. free(default_user_funcs.list);
  561. default_user_funcs.list = NULL;
  562. default_user_funcs.list_size = 0;
  563. }
  564. 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)
  565. {
  566. const int sz = (int) ((char *)_asm_generic2parm_retd_end-(char *)_asm_generic2parm_retd);
  567. NSEEL_addfunctionex2(name,min_np|(want_exact?BIF_TAKES_VARPARM_EX:BIF_TAKES_VARPARM),(char *)_asm_generic2parm_retd,sz,pproc,fptr,NULL,destination);
  568. }
  569. 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
  570. {
  571. char *stub=NULL;
  572. int stubsz=0;
  573. #define DOSTUB(np) { \
  574. stub = (ret_type == 1 ? (char*)_asm_generic##np##parm_retd : (char*)_asm_generic##np##parm); \
  575. stubsz = (int) ((ret_type == 1 ? (char*)_asm_generic##np##parm_retd_end : (char *)_asm_generic##np##parm_end) - stub); \
  576. }
  577. if (np == 1) DOSTUB(1)
  578. else if (np == 2) DOSTUB(2)
  579. else if (np == 3) DOSTUB(3)
  580. #undef DOSTUB
  581. if (stub) NSEEL_addfunctionex2(name,np|(ret_type == -1 ? BIF_RETURNSBOOL:0), stub, stubsz, pproc,fptr,NULL,destination);
  582. }
  583. 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)
  584. {
  585. const int list_size_chunk = 128;
  586. functionType *r;
  587. if (!destination) destination = &default_user_funcs;
  588. if (!destination->list || !(destination->list_size & (list_size_chunk-1)))
  589. {
  590. void *nv = realloc(destination->list, (destination->list_size + list_size_chunk)*sizeof(functionType));
  591. if (!nv) return;
  592. destination->list = (functionType *)nv;
  593. }
  594. if (destination->list)
  595. {
  596. int match,idx;
  597. idx=functable_lowerbound(destination->list,destination->list_size,name,&match);
  598. #ifdef EEL_VALIDATE_FSTUBS
  599. {
  600. char *endp = code_startaddr+code_len;
  601. // validate
  602. int sz=0;
  603. char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz);
  604. if (f+sz > endp)
  605. {
  606. #ifdef _WIN32
  607. OutputDebugString("bad eel function stub\n");
  608. #else
  609. printf("bad eel function stub\n");
  610. #endif
  611. *(char *)NULL = 0;
  612. }
  613. #ifdef _WIN32
  614. OutputDebugString(name);
  615. OutputDebugString(" - validated eel function stub\n");
  616. #else
  617. printf("eel function stub validation complete for %s\n",name);
  618. #endif
  619. }
  620. #endif
  621. r = destination->list + idx;
  622. if (idx < destination->list_size)
  623. memmove(r + 1, r, (destination->list_size - idx) * sizeof(functionType));
  624. destination->list_size++;
  625. memset(r, 0, sizeof(functionType));
  626. if (!(nparms & BIF_RETURNSBOOL))
  627. {
  628. if (code_startaddr == (void *)&_asm_generic1parm_retd ||
  629. code_startaddr == (void *)&_asm_generic2parm_retd ||
  630. code_startaddr == (void *)&_asm_generic3parm_retd)
  631. {
  632. nparms |= BIF_RETURNSONSTACK;
  633. }
  634. }
  635. r->nParams = nparms;
  636. r->name = name;
  637. r->afunc = code_startaddr;
  638. r->func_e = code_startaddr + code_len;
  639. r->pProc = pproc;
  640. r->replptrs[0] = fptr;
  641. r->replptrs[1] = fptr2;
  642. }
  643. }
  644. //---------------------------------------------------------------------------------------------------------------
  645. static void freeBlocks(llBlock **start)
  646. {
  647. llBlock *s=*start;
  648. *start=0;
  649. while (s)
  650. {
  651. llBlock *llB = s->next;
  652. free(s);
  653. s=llB;
  654. }
  655. }
  656. //---------------------------------------------------------------------------------------------------------------
  657. static void *__newBlock(llBlock **start, int size, int wantMprotect)
  658. {
  659. #if !defined(EEL_DOESNT_NEED_EXEC_PERMS) && defined(_WIN32)
  660. DWORD ov;
  661. UINT_PTR offs,eoffs;
  662. #endif
  663. llBlock *llb;
  664. int alloc_size;
  665. if (*start && (LLB_DSIZE - (*start)->sizeused) >= size)
  666. {
  667. void *t=(*start)->block+(*start)->sizeused;
  668. (*start)->sizeused+=(size+7)&~7;
  669. return t;
  670. }
  671. alloc_size=sizeof(llBlock);
  672. if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE;
  673. llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh)
  674. if (!llb) return NULL;
  675. #ifndef EEL_DOESNT_NEED_EXEC_PERMS
  676. if (wantMprotect)
  677. {
  678. #ifdef _WIN32
  679. offs=((UINT_PTR)llb)&~4095;
  680. eoffs=((UINT_PTR)llb + alloc_size + 4095)&~4095;
  681. VirtualProtect((LPVOID)offs,eoffs-offs,PAGE_EXECUTE_READWRITE,&ov);
  682. // MessageBox(NULL,"vprotecting, yay\n","a",0);
  683. #else
  684. {
  685. static int pagesize = 0;
  686. if (!pagesize)
  687. {
  688. pagesize=sysconf(_SC_PAGESIZE);
  689. if (!pagesize) pagesize=4096;
  690. }
  691. uintptr_t offs,eoffs;
  692. offs=((uintptr_t)llb)&~(pagesize-1);
  693. eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1);
  694. mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC);
  695. }
  696. #endif
  697. }
  698. #endif
  699. llb->sizeused=(size+7)&~7;
  700. llb->next = *start;
  701. *start = llb;
  702. return llb->block;
  703. }
  704. //---------------------------------------------------------------------------------------------------------------
  705. opcodeRec *nseel_createCompiledValue(compileContext *ctx, EEL_F value)
  706. {
  707. opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE);
  708. if (r)
  709. {
  710. r->parms.dv.directValue = value;
  711. }
  712. return r;
  713. }
  714. opcodeRec *nseel_createCompiledValuePtr(compileContext *ctx, EEL_F *addrValue, const char *namestr)
  715. {
  716. opcodeRec *r=newOpCode(ctx,namestr,OPCODETYPE_VARPTR);
  717. if (!r) return 0;
  718. r->parms.dv.valuePtr=addrValue;
  719. return r;
  720. }
  721. static int validate_varname_for_function(compileContext *ctx, const char *name)
  722. {
  723. if (!ctx->function_curName || !ctx->function_globalFlag) return 1;
  724. if (ctx->function_localTable_Size[2] > 0 && ctx->function_localTable_Names[2])
  725. {
  726. char * const * const namelist = ctx->function_localTable_Names[2];
  727. const int namelist_sz = ctx->function_localTable_Size[2];
  728. int i;
  729. const size_t name_len = strlen(name);
  730. for (i=0;i<namelist_sz;i++)
  731. {
  732. const char *nmchk=namelist[i];
  733. const size_t l = strlen(nmchk);
  734. if (l > 1 && nmchk[l-1] == '*')
  735. {
  736. if (name_len >= l && !strnicmp(nmchk,name,l-1) && name[l-1]=='.') return 1;
  737. }
  738. else
  739. {
  740. if (name_len == l && !stricmp(nmchk,name)) return 1;
  741. }
  742. }
  743. }
  744. return 0;
  745. }
  746. opcodeRec *nseel_resolve_named_symbol(compileContext *ctx, opcodeRec *rec, int parmcnt, int *errOut)
  747. {
  748. const int isFunctionMode = parmcnt >= 0;
  749. int rel_prefix_len=0;
  750. int rel_prefix_idx=-2;
  751. int i;
  752. char match_parmcnt[4]={-1,-1,-1,-1}; // [3] is guess
  753. unsigned char match_parmcnt_pos=0;
  754. char *sname = (char *)rec->relname;
  755. int is_string_prefix = parmcnt < 0 && sname[0] == '#';
  756. const char *prevent_function_calls = NULL;
  757. if (errOut) *errOut = 0;
  758. if (sname) sname += is_string_prefix;
  759. if (rec->opcodeType != OPCODETYPE_VARPTR || !sname || !sname[0]) return NULL;
  760. if (!isFunctionMode && !is_string_prefix && !strnicmp(sname,"reg",3) && isdigit(sname[3]) && isdigit(sname[4]) && !sname[5])
  761. {
  762. EEL_F *a=get_global_var(ctx,sname,1);
  763. if (a)
  764. {
  765. rec->parms.dv.valuePtr = a;
  766. sname[0]=0; // for dump_ops compat really, but this shouldn't be needed anyway
  767. }
  768. return rec;
  769. }
  770. if (ctx->function_curName)
  771. {
  772. if (!strnicmp(sname,"this.",5))
  773. {
  774. rel_prefix_len=5;
  775. rel_prefix_idx=-1;
  776. }
  777. else if (!stricmp(sname,"this"))
  778. {
  779. rel_prefix_len=4;
  780. rel_prefix_idx=-1;
  781. }
  782. // scan for parameters/local variables before user functions
  783. if (rel_prefix_idx < -1 &&
  784. ctx->function_localTable_Size[0] > 0 &&
  785. ctx->function_localTable_Names[0] &&
  786. ctx->function_localTable_ValuePtrs)
  787. {
  788. char * const * const namelist = ctx->function_localTable_Names[0];
  789. const int namelist_sz = ctx->function_localTable_Size[0];
  790. for (i=0; i < namelist_sz; i++)
  791. {
  792. const char *p = namelist[i];
  793. if (p)
  794. {
  795. if (!isFunctionMode && !is_string_prefix && !strnicmp(p,sname,NSEEL_MAX_VARIABLE_NAMELEN))
  796. {
  797. rec->opcodeType = OPCODETYPE_VARPTRPTR;
  798. rec->parms.dv.valuePtr=(EEL_F *)(ctx->function_localTable_ValuePtrs+i);
  799. rec->parms.dv.directValue=0.0;
  800. return rec;
  801. }
  802. else
  803. {
  804. const size_t plen = strlen(p);
  805. if (plen > 1 && p[plen-1] == '*' && !strnicmp(p,sname,plen-1) && ((sname[plen-1] == '.'&&sname[plen]) || !sname[plen-1]))
  806. {
  807. rel_prefix_len=(int) (sname[plen-1] ? plen : plen-1);
  808. rel_prefix_idx=i;
  809. break;
  810. }
  811. }
  812. }
  813. }
  814. }
  815. // if instance name set, translate sname or sname.* into "this.sname.*"
  816. if (rel_prefix_idx < -1 &&
  817. ctx->function_localTable_Size[1] > 0 &&
  818. ctx->function_localTable_Names[1])
  819. {
  820. char * const * const namelist = ctx->function_localTable_Names[1];
  821. const int namelist_sz = ctx->function_localTable_Size[1];
  822. const char *full_sname = rec->relname; // include # in checks
  823. for (i=0; i < namelist_sz; i++)
  824. {
  825. const char *p = namelist[i];
  826. if (p && *p)
  827. {
  828. const size_t tl = strlen(p);
  829. if (!strnicmp(p,full_sname,tl) && (full_sname[tl] == 0 || full_sname[tl] == '.'))
  830. {
  831. rel_prefix_len=0; // treat as though this. prefixes is present
  832. rel_prefix_idx=-1;
  833. break;
  834. }
  835. }
  836. }
  837. }
  838. if (rel_prefix_idx >= -1)
  839. {
  840. ctx->function_usesNamespaces=1;
  841. }
  842. } // ctx->function_curName
  843. if (!isFunctionMode)
  844. {
  845. // instance variables
  846. if (rel_prefix_idx >= -1)
  847. {
  848. rec->opcodeType = OPCODETYPE_VALUE_FROM_NAMESPACENAME;
  849. rec->namespaceidx = rel_prefix_idx;
  850. if (rel_prefix_len > 0)
  851. {
  852. if (is_string_prefix) sname[-1] = '#';
  853. memmove(sname, sname+rel_prefix_len, strlen(sname + rel_prefix_len) + 1);
  854. }
  855. }
  856. else
  857. {
  858. // no namespace index, so it must be a global
  859. if (!validate_varname_for_function(ctx,rec->relname))
  860. {
  861. if (errOut) *errOut = 1;
  862. if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
  863. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"global '%s' inaccessible",rec->relname);
  864. return NULL;
  865. }
  866. }
  867. return rec;
  868. }
  869. if (ctx->func_check)
  870. prevent_function_calls = ctx->func_check(sname,ctx->func_check_user);
  871. ////////// function mode
  872. // first off, while() and loop() are special and can't be overridden
  873. //
  874. if (parmcnt == 1 && !stricmp("while",sname) && !prevent_function_calls)
  875. {
  876. rec->opcodeType = OPCODETYPE_FUNC1;
  877. rec->fntype = FN_WHILE;
  878. return rec;
  879. }
  880. if (parmcnt == 2 && !stricmp("loop",sname) && !prevent_function_calls)
  881. {
  882. rec->opcodeType = OPCODETYPE_FUNC2;
  883. rec->fntype = FN_LOOP;
  884. return rec;
  885. }
  886. //
  887. // resolve user function names before builtin functions -- this allows the user to override default functions
  888. if (!(ctx->current_compile_flags & NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS))
  889. {
  890. _codeHandleFunctionRec *best=NULL;
  891. size_t bestlen=0;
  892. const char * const ourcall = sname+rel_prefix_len;
  893. const size_t ourcall_len = strlen(ourcall);
  894. int pass;
  895. for (pass=0;pass<2;pass++)
  896. {
  897. _codeHandleFunctionRec *fr = pass ? ctx->functions_common : ctx->functions_local;
  898. // sname is [namespace.[ns.]]function, find best match of function that matches the right end
  899. while (fr)
  900. {
  901. int this_np = fr->num_params;
  902. const char *thisfunc = fr->fname;
  903. const size_t thisfunc_len = strlen(thisfunc);
  904. if (this_np < 1) this_np=1;
  905. if (thisfunc_len == ourcall_len && !stricmp(thisfunc,ourcall))
  906. {
  907. if (this_np == parmcnt)
  908. {
  909. bestlen = thisfunc_len;
  910. best = fr;
  911. break; // found exact match, finished
  912. }
  913. else
  914. {
  915. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = fr->num_params;
  916. }
  917. }
  918. if (thisfunc_len > bestlen && thisfunc_len < ourcall_len && ourcall[ourcall_len - thisfunc_len - 1] == '.' && !stricmp(thisfunc,ourcall + ourcall_len - thisfunc_len))
  919. {
  920. if (this_np == parmcnt)
  921. {
  922. bestlen = thisfunc_len;
  923. best = fr;
  924. }
  925. else
  926. if (match_parmcnt[3]<0) match_parmcnt[3]=fr->num_params;
  927. }
  928. fr=fr->next;
  929. }
  930. if (fr) break; // found exact match, finished
  931. }
  932. if (best)
  933. {
  934. switch (parmcnt)
  935. {
  936. case 0:
  937. case 1: rec->opcodeType = OPCODETYPE_FUNC1; break;
  938. case 2: rec->opcodeType = OPCODETYPE_FUNC2; break;
  939. case 3: rec->opcodeType = OPCODETYPE_FUNC3; break;
  940. default: rec->opcodeType = OPCODETYPE_FUNCX; break;
  941. }
  942. if (ourcall != rec->relname) memmove((char *)rec->relname, ourcall, strlen(ourcall)+1);
  943. if (ctx->function_curName && rel_prefix_idx<0)
  944. {
  945. // if no namespace specified, and this.commonprefix.func() called, remove common prefixes and set prefixidx to be this
  946. const char *p=ctx->function_curName;
  947. if (*p) p++;
  948. while (*p && *p != '.') p++;
  949. if (*p && p[1]) // we have a dot!
  950. {
  951. while (p[1]) p++; // go to last char of string, which doesn't allow possible trailing dot to be checked
  952. while (--p > ctx->function_curName) // do not check possible leading dot
  953. {
  954. if (*p == '.')
  955. {
  956. const size_t cmplen = p+1-ctx->function_curName;
  957. if (!strnicmp(rec->relname,ctx->function_curName,cmplen) && rec->relname[cmplen])
  958. {
  959. const char *src=rec->relname + cmplen;
  960. memmove((char *)rec->relname, src, strlen(src)+1);
  961. rel_prefix_idx=-1;
  962. ctx->function_usesNamespaces=1;
  963. break;
  964. }
  965. }
  966. }
  967. }
  968. }
  969. if (ctx->function_curName && rel_prefix_idx < -1 &&
  970. strchr(rec->relname,'.') && !validate_varname_for_function(ctx,rec->relname))
  971. {
  972. if (errOut) *errOut = 1;
  973. if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
  974. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"namespaced function '%s' inaccessible",rec->relname);
  975. return NULL;
  976. }
  977. rec->namespaceidx = rel_prefix_idx;
  978. rec->fntype = FUNCTYPE_EELFUNC;
  979. rec->fn = best;
  980. return rec;
  981. }
  982. }
  983. if (prevent_function_calls)
  984. {
  985. if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
  986. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s': %s",sname, prevent_function_calls);
  987. if (errOut) *errOut = 0;
  988. return NULL;
  989. }
  990. #ifdef NSEEL_EEL1_COMPAT_MODE
  991. if (!stricmp(sname,"assign"))
  992. {
  993. if (parmcnt == 2)
  994. {
  995. rec->opcodeType = OPCODETYPE_FUNC2;
  996. rec->fntype = FN_ASSIGN;
  997. return rec;
  998. }
  999. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
  1000. }
  1001. else if (!stricmp(sname,"if"))
  1002. {
  1003. if (parmcnt == 3)
  1004. {
  1005. rec->opcodeType = OPCODETYPE_FUNC3;
  1006. rec->fntype = FN_IF_ELSE;
  1007. return rec;
  1008. }
  1009. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 3;
  1010. }
  1011. else if (!stricmp(sname,"equal"))
  1012. {
  1013. if (parmcnt == 2)
  1014. {
  1015. rec->opcodeType = OPCODETYPE_FUNC2;
  1016. rec->fntype = FN_EQ;
  1017. return rec;
  1018. }
  1019. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
  1020. }
  1021. else if (!stricmp(sname,"below"))
  1022. {
  1023. if (parmcnt == 2)
  1024. {
  1025. rec->opcodeType = OPCODETYPE_FUNC2;
  1026. rec->fntype = FN_LT;
  1027. return rec;
  1028. }
  1029. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
  1030. }
  1031. else if (!stricmp(sname,"above"))
  1032. {
  1033. if (parmcnt == 2)
  1034. {
  1035. rec->opcodeType = OPCODETYPE_FUNC2;
  1036. rec->fntype = FN_GT;
  1037. return rec;
  1038. }
  1039. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
  1040. }
  1041. else if (!stricmp(sname,"bnot"))
  1042. {
  1043. if (parmcnt == 1)
  1044. {
  1045. rec->opcodeType = OPCODETYPE_FUNC1;
  1046. rec->fntype = FN_NOT;
  1047. return rec;
  1048. }
  1049. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
  1050. }
  1051. else if (!stricmp(sname,"megabuf"))
  1052. {
  1053. if (parmcnt == 1)
  1054. {
  1055. rec->opcodeType = OPCODETYPE_FUNC1;
  1056. rec->fntype = FN_MEMORY;
  1057. return rec;
  1058. }
  1059. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
  1060. }
  1061. else if (!stricmp(sname,"gmegabuf"))
  1062. {
  1063. if (parmcnt == 1)
  1064. {
  1065. rec->opcodeType = OPCODETYPE_FUNC1;
  1066. rec->fntype = FN_GMEMORY;
  1067. return rec;
  1068. }
  1069. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
  1070. }
  1071. else
  1072. #endif
  1073. // convert legacy pow() to FN_POW
  1074. if (!stricmp("pow",sname))
  1075. {
  1076. if (parmcnt == 2)
  1077. {
  1078. rec->opcodeType = OPCODETYPE_FUNC2;
  1079. rec->fntype = FN_POW;
  1080. return rec;
  1081. }
  1082. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
  1083. }
  1084. else if (!stricmp("__denormal_likely",sname) || !stricmp("__denormal_unlikely",sname))
  1085. {
  1086. if (parmcnt == 1)
  1087. {
  1088. rec->opcodeType = OPCODETYPE_FUNC1;
  1089. rec->fntype = !stricmp("__denormal_likely",sname) ? FN_DENORMAL_LIKELY : FN_DENORMAL_UNLIKELY;
  1090. return rec;
  1091. }
  1092. }
  1093. {
  1094. int chkamt=0;
  1095. functionType *f=nseel_getFunctionByName(ctx,sname,&chkamt);
  1096. if (f) while (chkamt-->=0)
  1097. {
  1098. const int pc_needed=(f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK);
  1099. if ((f->nParams&BIF_TAKES_VARPARM_EX)==BIF_TAKES_VARPARM ? (parmcnt >= pc_needed) : (parmcnt == pc_needed))
  1100. {
  1101. rec->fntype = FUNCTYPE_FUNCTIONTYPEREC;
  1102. rec->fn = (void *)f;
  1103. switch (parmcnt)
  1104. {
  1105. case 0:
  1106. case 1: rec->opcodeType = OPCODETYPE_FUNC1; break;
  1107. case 2: rec->opcodeType = OPCODETYPE_FUNC2; break;
  1108. case 3: rec->opcodeType = OPCODETYPE_FUNC3; break;
  1109. default: rec->opcodeType = OPCODETYPE_FUNCX; break;
  1110. }
  1111. return rec;
  1112. }
  1113. if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = (f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK);
  1114. f++;
  1115. if (stricmp(f->name,sname)) break;
  1116. }
  1117. }
  1118. if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
  1119. if (match_parmcnt[3] >= 0)
  1120. {
  1121. if (match_parmcnt_pos<3) match_parmcnt[match_parmcnt_pos] = match_parmcnt[3];
  1122. match_parmcnt_pos++;
  1123. }
  1124. if (!match_parmcnt_pos)
  1125. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' undefined",sname);
  1126. else
  1127. {
  1128. int x;
  1129. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' needs ",sname);
  1130. for (x = 0; x < match_parmcnt_pos; x++)
  1131. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"%s%d",x==0?"" : x == match_parmcnt_pos-1?" or ":",",match_parmcnt[x]);
  1132. lstrcatn(ctx->last_error_string," parms",sizeof(ctx->last_error_string));
  1133. }
  1134. if (errOut) *errOut = match_parmcnt_pos > 0 ? parmcnt<match_parmcnt[0]?2:(match_parmcnt[0] < 2 ? 4:1) : 0;
  1135. return NULL;
  1136. }
  1137. opcodeRec *nseel_setCompiledFunctionCallParameters(compileContext *ctx, opcodeRec *fn, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3, opcodeRec *postCode, int *errOut)
  1138. {
  1139. opcodeRec *r;
  1140. int np=0,x;
  1141. if (!fn || fn->opcodeType != OPCODETYPE_VARPTR || !fn->relname || !fn->relname[0])
  1142. {
  1143. return NULL;
  1144. }
  1145. fn->parms.parms[0] = code1;
  1146. fn->parms.parms[1] = code2;
  1147. fn->parms.parms[2] = code3;
  1148. for (x=0;x<3;x++)
  1149. {
  1150. opcodeRec *prni=fn->parms.parms[x];
  1151. while (prni && np < NSEEL_MAX_EELFUNC_PARAMETERS)
  1152. {
  1153. const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
  1154. np++;
  1155. if (!isMP) break;
  1156. prni = prni->parms.parms[1];
  1157. }
  1158. }
  1159. r = nseel_resolve_named_symbol(ctx, fn, np<1 ? 1 : np ,errOut);
  1160. if (postCode && r)
  1161. {
  1162. if (code1 && r->opcodeType == OPCODETYPE_FUNC1 && r->fntype == FN_WHILE)
  1163. {
  1164. // change while(x) (postcode) to be
  1165. // while ((x) ? (postcode;1) : 0);
  1166. r->parms.parms[0] =
  1167. nseel_createIfElse(ctx,r->parms.parms[0],
  1168. nseel_createSimpleCompiledFunction(ctx,FN_JOIN_STATEMENTS,2,postCode,nseel_createCompiledValue(ctx,1.0f)),
  1169. NULL); // NULL defaults to 0.0
  1170. }
  1171. else
  1172. {
  1173. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"syntax error following function");
  1174. *errOut = -1;
  1175. return NULL;
  1176. }
  1177. }
  1178. return r;
  1179. }
  1180. struct eelStringSegmentRec *nseel_createStringSegmentRec(compileContext *ctx, const char *str, int len)
  1181. {
  1182. struct eelStringSegmentRec *r = newTmpBlock(ctx,sizeof(struct eelStringSegmentRec));
  1183. if (r)
  1184. {
  1185. r->_next=0;
  1186. r->str_start=str;
  1187. r->str_len = len;
  1188. }
  1189. return r;
  1190. }
  1191. opcodeRec *nseel_eelMakeOpcodeFromStringSegments(compileContext *ctx, struct eelStringSegmentRec *rec)
  1192. {
  1193. if (ctx && ctx->onString)
  1194. {
  1195. return nseel_createCompiledValue(ctx, ctx->onString(ctx->caller_this,rec));
  1196. }
  1197. return NULL;
  1198. }
  1199. opcodeRec *nseel_createMoreParametersOpcode(compileContext *ctx, opcodeRec *code1, opcodeRec *code2)
  1200. {
  1201. opcodeRec *r=code1 && code2 ? newOpCode(ctx,NULL,OPCODETYPE_MOREPARAMS) : NULL;
  1202. if (r)
  1203. {
  1204. r->parms.parms[0] = code1;
  1205. r->parms.parms[1] = code2;
  1206. }
  1207. return r;
  1208. }
  1209. opcodeRec *nseel_createIfElse(compileContext *ctx, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3)
  1210. {
  1211. opcodeRec *r=code1 ? newOpCode(ctx,NULL,OPCODETYPE_FUNC3) : NULL;
  1212. if (r)
  1213. {
  1214. if (!code2) code2 = nseel_createCompiledValue(ctx,0.0);
  1215. if (!code3) code3 = nseel_createCompiledValue(ctx,0.0);
  1216. if (!code2||!code3) return NULL;
  1217. r->fntype = FN_IF_ELSE;
  1218. r->parms.parms[0] = code1;
  1219. r->parms.parms[1] = code2;
  1220. r->parms.parms[2] = code3;
  1221. }
  1222. return r;
  1223. }
  1224. opcodeRec *nseel_createMemoryAccess(compileContext *ctx, opcodeRec *code1, opcodeRec *code2)
  1225. {
  1226. if (code1 && code1->opcodeType == OPCODETYPE_VARPTR && !stricmp(code1->relname,"gmem"))
  1227. {
  1228. return nseel_createSimpleCompiledFunction(ctx, FN_GMEMORY,1,code2?code2:nseel_createCompiledValue(ctx,0.0),0);
  1229. }
  1230. if (code2 && (code2->opcodeType != OPCODETYPE_DIRECTVALUE || code2->parms.dv.directValue != 0.0))
  1231. {
  1232. code1 = nseel_createSimpleCompiledFunction(ctx,FN_ADD,2,code1,code2);
  1233. }
  1234. return nseel_createSimpleCompiledFunction(ctx, FN_MEMORY,1,code1,0);
  1235. }
  1236. opcodeRec *nseel_createSimpleCompiledFunction(compileContext *ctx, int fn, int np, opcodeRec *code1, opcodeRec *code2)
  1237. {
  1238. opcodeRec *r=code1 && (np<2 || code2) ? newOpCode(ctx,NULL,np>=2 ? OPCODETYPE_FUNC2:OPCODETYPE_FUNC1) : NULL;
  1239. if (r)
  1240. {
  1241. r->fntype = fn;
  1242. r->parms.parms[0] = code1;
  1243. r->parms.parms[1] = code2;
  1244. if (fn == FN_JOIN_STATEMENTS)
  1245. {
  1246. r->fn = r; // for joins, fn is temporarily used for _tail pointers
  1247. if (code1 && code1->opcodeType == OPCODETYPE_FUNC2 && code1->fntype == fn)
  1248. {
  1249. opcodeRec *t = (opcodeRec *)code1->fn;
  1250. // keep joins in the form of dosomething->morestuff.
  1251. // in this instance, code1 is previous stuff to do, code2 is new stuff to do
  1252. r->parms.parms[0] = t->parms.parms[1];
  1253. code1->fn = (t->parms.parms[1] = r);
  1254. return code1;
  1255. }
  1256. }
  1257. }
  1258. return r;
  1259. }
  1260. // these are bitmasks; on request you can tell what is supported, and compileOpcodes will return one of them
  1261. #define RETURNVALUE_IGNORE 0 // ignore return value
  1262. #define RETURNVALUE_NORMAL 1 // pointer
  1263. #define RETURNVALUE_FPSTACK 2
  1264. #define RETURNVALUE_BOOL 4 // P1 is nonzero if true
  1265. #define RETURNVALUE_BOOL_REVERSED 8 // P1 is zero if true
  1266. #define RETURNVALUE_CACHEABLE 16 // only to be used when (at least) RETURNVALUE_NORMAL is set
  1267. static int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTable, const namespaceInformation *namespacePathToThis,
  1268. int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput);
  1269. static unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis,
  1270. int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput);
  1271. _codeHandleFunctionRec *eel_createFunctionNamespacedInstance(compileContext *ctx, _codeHandleFunctionRec *fr, const char *nameptr)
  1272. {
  1273. size_t n;
  1274. _codeHandleFunctionRec *subfr =
  1275. fr->isCommonFunction ?
  1276. ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) :
  1277. newCtxDataBlock(sizeof(_codeHandleFunctionRec),8) : // if common function, but derived version is in non-common context, set ownership to VM rather than us
  1278. newTmpBlock(ctx,sizeof(_codeHandleFunctionRec));
  1279. if (!subfr) return 0;
  1280. // fr points to functionname()'s rec, nameptr to blah.functionname()
  1281. *subfr = *fr;
  1282. n = strlen(nameptr);
  1283. if (n > sizeof(subfr->fname)-1) n=sizeof(subfr->fname)-1;
  1284. memcpy(subfr->fname,nameptr,n);
  1285. subfr->fname[n]=0;
  1286. subfr->next = NULL;
  1287. subfr->startptr=0; // make sure this code gets recompiled (with correct member ptrs) for this instance!
  1288. subfr->startptr_size=-1;
  1289. // subfr->derivedCopies already points to the right place
  1290. fr->derivedCopies = subfr;
  1291. return subfr;
  1292. }
  1293. static void combineNamespaceFields(char *nm, const namespaceInformation *namespaceInfo, const char *relname, int thisctx) // nm must be NSEEL_MAX_VARIABLE_NAMELEN+1 bytes
  1294. {
  1295. const char *prefix = namespaceInfo ?
  1296. thisctx<0 ? (thisctx == -1 ? namespaceInfo->namespacePathToThis : NULL) : (thisctx < MAX_SUB_NAMESPACES ? namespaceInfo->subParmInfo[thisctx] : NULL)
  1297. : NULL;
  1298. int lfp = 0, lrn=relname ? (int)strlen(relname) : 0;
  1299. if (prefix) while (prefix[lfp] && prefix[lfp] != ':' && lfp < NSEEL_MAX_VARIABLE_NAMELEN) lfp++;
  1300. if (!relname) relname = "";
  1301. while (*relname == '.') // if relname begins with ., then remove a chunk of context from prefix
  1302. {
  1303. relname++;
  1304. while (lfp>0 && prefix[lfp-1] != '.') lfp--;
  1305. if (lfp>0) lfp--;
  1306. }
  1307. if (lfp > NSEEL_MAX_VARIABLE_NAMELEN-3) lfp=NSEEL_MAX_VARIABLE_NAMELEN-3;
  1308. if (lfp>0) memcpy(nm,prefix,lfp);
  1309. if (lrn > NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0)) lrn=NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0);
  1310. if (lrn > 0)
  1311. {
  1312. if (lfp>0) nm[lfp++] = '.';
  1313. memcpy(nm+lfp,relname,lrn);
  1314. lfp+=lrn;
  1315. }
  1316. nm[lfp++]=0;
  1317. }
  1318. //---------------------------------------------------------------------------------------------------------------
  1319. static void *nseel_getBuiltinFunctionAddress(compileContext *ctx,
  1320. int fntype, void *fn,
  1321. NSEEL_PPPROC *pProc, void ***replList,
  1322. void **endP, int *abiInfo, int preferredReturnValues, const EEL_F *hasConstParm1, const EEL_F *hasConstParm2)
  1323. {
  1324. const EEL_F *firstConstParm = hasConstParm1 ? hasConstParm1 : hasConstParm2;
  1325. static void *pow_replptrs[4]={&pow,};
  1326. switch (fntype)
  1327. {
  1328. #define RF(x) *endP = nseel_asm_##x##_end; return (void*)nseel_asm_##x
  1329. case FN_MUL_OP:
  1330. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1331. RF(mul_op);
  1332. case FN_DIV_OP:
  1333. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1334. RF(div_op);
  1335. case FN_OR_OP:
  1336. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1337. RF(or_op);
  1338. case FN_XOR_OP:
  1339. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1340. RF(xor_op);
  1341. case FN_AND_OP:
  1342. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1343. RF(and_op);
  1344. case FN_MOD_OP:
  1345. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1346. RF(mod_op);
  1347. case FN_ADD_OP:
  1348. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1349. RF(add_op);
  1350. case FN_SUB_OP:
  1351. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1352. RF(sub_op);
  1353. case FN_POW_OP:
  1354. *abiInfo=BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL;
  1355. *replList = pow_replptrs;
  1356. RF(2pdds);
  1357. case FN_POW:
  1358. *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
  1359. *replList = pow_replptrs;
  1360. RF(2pdd);
  1361. case FN_ADD:
  1362. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2);
  1363. // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL
  1364. if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL;
  1365. RF(add);
  1366. case FN_SUB:
  1367. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2);
  1368. // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL
  1369. if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL;
  1370. RF(sub);
  1371. case FN_MULTIPLY:
  1372. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2);
  1373. // for x*constant-greater-than-eq-1, we can set BIF_WONTMAKEDENORMAL
  1374. if (firstConstParm && fabs(*firstConstParm) >= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL;
  1375. RF(mul);
  1376. case FN_DIVIDE:
  1377. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2);
  1378. // for x/constant-less-than-eq-1, we can set BIF_WONTMAKEDENORMAL
  1379. if (firstConstParm && fabs(*firstConstParm) <= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL;
  1380. RF(div);
  1381. case FN_MOD:
  1382. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
  1383. RF(mod);
  1384. case FN_ASSIGN:
  1385. *abiInfo = BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
  1386. RF(assign);
  1387. case FN_AND: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(and);
  1388. case FN_OR: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(or);
  1389. case FN_XOR:
  1390. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1391. RF(xor);
  1392. case FN_SHR:
  1393. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1394. RF(shr);
  1395. case FN_SHL:
  1396. *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
  1397. RF(shl);
  1398. #ifndef EEL_TARGET_PORTABLE
  1399. case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(uplus);
  1400. #else
  1401. case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnotnot);
  1402. #endif
  1403. case FN_UMINUS: *abiInfo = BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL; RF(uminus);
  1404. case FN_NOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnot);
  1405. case FN_EQ:
  1406. *abiInfo = BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1407. RF(equal);
  1408. case FN_EQ_EXACT:
  1409. *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1410. RF(equal_exact);
  1411. case FN_NE:
  1412. *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1413. RF(notequal);
  1414. case FN_NE_EXACT:
  1415. *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1416. RF(notequal_exact);
  1417. case FN_LOGICAL_AND:
  1418. *abiInfo = BIF_RETURNSBOOL;
  1419. RF(band);
  1420. case FN_LOGICAL_OR:
  1421. *abiInfo = BIF_RETURNSBOOL;
  1422. RF(bor);
  1423. #ifdef GLUE_HAS_FXCH
  1424. case FN_GT:
  1425. *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1426. RF(above);
  1427. case FN_GTE:
  1428. *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2);
  1429. RF(beloweq);
  1430. case FN_LT:
  1431. *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2);
  1432. RF(above);
  1433. case FN_LTE:
  1434. *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
  1435. RF(beloweq);
  1436. #else
  1437. case FN_GT:
  1438. *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
  1439. RF(above);
  1440. case FN_GTE:
  1441. *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
  1442. RF(aboveeq);
  1443. case FN_LT:
  1444. *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
  1445. RF(below);
  1446. case FN_LTE:
  1447. *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
  1448. RF(beloweq);
  1449. #endif
  1450. #undef RF
  1451. #define RF(x) *endP = _asm_##x##_end; return (void*)_asm_##x
  1452. case FN_MEMORY:
  1453. {
  1454. static void *replptrs[4]={&__NSEEL_RAMAlloc,};
  1455. *replList = replptrs;
  1456. *abiInfo = BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
  1457. #ifdef GLUE_MEM_NEEDS_PPROC
  1458. *pProc = NSEEL_PProc_RAM;
  1459. #endif
  1460. RF(megabuf);
  1461. }
  1462. break;
  1463. case FN_GMEMORY:
  1464. {
  1465. static void *replptrs[4]={&__NSEEL_RAMAllocGMEM,};
  1466. *replList = replptrs;
  1467. *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
  1468. *pProc=NSEEL_PProc_GRAM;
  1469. RF(gmegabuf);
  1470. }
  1471. break;
  1472. #undef RF
  1473. case FUNCTYPE_FUNCTIONTYPEREC:
  1474. if (fn)
  1475. {
  1476. functionType *p=(functionType *)fn;
  1477. // if prefers fpstack or bool, or ignoring value, then use fp-stack versions
  1478. if ((preferredReturnValues&(RETURNVALUE_BOOL|RETURNVALUE_FPSTACK)) || !preferredReturnValues)
  1479. {
  1480. 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 };
  1481. 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 };
  1482. if (p->afunc == (void*)nseel_asm_min) p = &min2;
  1483. else if (p->afunc == (void*)nseel_asm_max) p = &max2;
  1484. }
  1485. *replList=p->replptrs;
  1486. *pProc=p->pProc;
  1487. *endP = p->func_e;
  1488. *abiInfo = p->nParams & BIF_NPARAMS_MASK;
  1489. if (firstConstParm)
  1490. {
  1491. const char *name=p->name;
  1492. if (!strcmp(name,"min") && *firstConstParm < -1.0e-10) *abiInfo |= BIF_CLEARDENORMAL;
  1493. else if (!strcmp(name,"max") && *firstConstParm > 1.0e-10) *abiInfo |= BIF_CLEARDENORMAL;
  1494. }
  1495. return p->afunc;
  1496. }
  1497. break;
  1498. }
  1499. return 0;
  1500. }
  1501. static void *nseel_getEELFunctionAddress(compileContext *ctx,
  1502. opcodeRec *op,
  1503. int *customFuncParmSize, int *customFuncLocalStorageSize,
  1504. EEL_F ***customFuncLocalStorage, int *computTableTop,
  1505. void **endP, int *isRaw, int wantCodeGenerated,
  1506. const namespaceInformation *namespacePathToThis, int *rvMode, int *fpStackUse, int *canHaveDenormalOutput,
  1507. opcodeRec **ordered_parmptrs, int num_ordered_parmptrs
  1508. ) // if wantCodeGenerated is false, can return bogus pointers in raw mode
  1509. {
  1510. _codeHandleFunctionRec *fn = (_codeHandleFunctionRec*)op->fn;
  1511. namespaceInformation local_namespace={NULL};
  1512. char prefix_buf[NSEEL_MAX_VARIABLE_NAMELEN+1], nm[NSEEL_MAX_FUNCSIG_NAME+1];
  1513. if (!fn) return NULL;
  1514. // op->relname ptr is [whatever.]funcname
  1515. if (fn->parameterAsNamespaceMask || fn->usesNamespaces)
  1516. {
  1517. if (wantCodeGenerated)
  1518. {
  1519. char *p = prefix_buf;
  1520. combineNamespaceFields(nm,namespacePathToThis,op->relname,op->namespaceidx);
  1521. lstrcpyn_safe(prefix_buf,nm,sizeof(prefix_buf));
  1522. local_namespace.namespacePathToThis = prefix_buf;
  1523. // nm is full path of function, prefix_buf will be the path not including function name (unless function name only)
  1524. while (*p) p++;
  1525. while (p >= prefix_buf && *p != '.') p--;
  1526. if (p > prefix_buf) *p=0;
  1527. }
  1528. if (fn->parameterAsNamespaceMask)
  1529. {
  1530. int x;
  1531. for(x=0;x<MAX_SUB_NAMESPACES && x < fn->num_params;x++)
  1532. {
  1533. if (fn->parameterAsNamespaceMask & (((unsigned int)1)<<x))
  1534. {
  1535. if (wantCodeGenerated)
  1536. {
  1537. const char *rn=NULL;
  1538. char tmp[NSEEL_MAX_VARIABLE_NAMELEN+1];
  1539. if (x < num_ordered_parmptrs && ordered_parmptrs[x])
  1540. {
  1541. if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VARPTR)
  1542. {
  1543. rn=ordered_parmptrs[x]->relname;
  1544. }
  1545. else if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VALUE_FROM_NAMESPACENAME)
  1546. {
  1547. const char *p=ordered_parmptrs[x]->relname;
  1548. if (*p == '#') p++;
  1549. combineNamespaceFields(tmp,namespacePathToThis,p,ordered_parmptrs[x]->namespaceidx);
  1550. rn = tmp;
  1551. }
  1552. }
  1553. if (!rn)
  1554. {
  1555. // todo: figure out how to give correct line number/offset (ugh)
  1556. snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"parameter %d to %.120s() must be namespace",x+1,fn->fname);
  1557. return NULL;
  1558. }
  1559. lstrcatn(nm,":",sizeof(nm));
  1560. local_namespace.subParmInfo[x] = nm+strlen(nm);
  1561. lstrcatn(nm,rn,sizeof(nm));
  1562. }
  1563. ordered_parmptrs[x] = NULL; // prevent caller from bothering generating parameters
  1564. }
  1565. }
  1566. }
  1567. if (wantCodeGenerated)
  1568. {
  1569. _codeHandleFunctionRec *fr = fn;
  1570. // find namespace-adjusted function (if generating code, otherwise assume size is the same)
  1571. fn = 0; // if this gets re-set, it will be the new function
  1572. while (fr && !fn)
  1573. {
  1574. if (!stricmp(fr->fname,nm)) fn = fr;
  1575. fr=fr->derivedCopies;
  1576. }
  1577. if (!fn) // generate copy of function
  1578. {
  1579. fn = eel_createFunctionNamespacedInstance(ctx,(_codeHandleFunctionRec*)op->fn,nm);
  1580. }
  1581. }
  1582. }
  1583. if (!fn) return NULL;
  1584. if (!fn->startptr && fn->opcodes && fn->startptr_size != 0)
  1585. {
  1586. int sz = fn->startptr_size;
  1587. if (sz < 0)
  1588. {
  1589. fn->tmpspace_req=0;
  1590. fn->rvMode = RETURNVALUE_IGNORE;
  1591. fn->canHaveDenormalOutput=0;
  1592. sz = compileOpcodes(ctx,fn->opcodes,NULL,128*1024*1024,&fn->tmpspace_req,
  1593. wantCodeGenerated ? &local_namespace : NULL,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,
  1594. &fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
  1595. if (sz<0) return NULL;
  1596. fn->startptr_size = sz;
  1597. }
  1598. if (!wantCodeGenerated)
  1599. {
  1600. // don't compile anything for now, just give stats
  1601. if (computTableTop) *computTableTop += fn->tmpspace_req;
  1602. *customFuncParmSize = fn->num_params;
  1603. *customFuncLocalStorage = fn->localstorage;
  1604. *customFuncLocalStorageSize = fn->localstorage_size;
  1605. *rvMode = fn->rvMode;
  1606. *fpStackUse = fn->fpStackUsage;
  1607. if (canHaveDenormalOutput) *canHaveDenormalOutput=fn->canHaveDenormalOutput;
  1608. if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC))
  1609. {
  1610. *isRaw = 1;
  1611. *endP = ((char *)1) + sz;
  1612. return (char *)1;
  1613. }
  1614. *endP = (void*)nseel_asm_fcall_end;
  1615. return (void*)nseel_asm_fcall;
  1616. }
  1617. if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC))
  1618. {
  1619. void *p=newTmpBlock(ctx,sz);
  1620. fn->tmpspace_req=0;
  1621. if (p)
  1622. {
  1623. fn->canHaveDenormalOutput=0;
  1624. if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++;
  1625. sz=compileOpcodes(ctx,fn->opcodes,(unsigned char*)p,sz,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
  1626. if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--;
  1627. // recompile function with native context pointers
  1628. if (sz>0)
  1629. {
  1630. fn->startptr_size=sz;
  1631. fn->startptr=p;
  1632. }
  1633. }
  1634. }
  1635. else
  1636. {
  1637. unsigned char *codeCall;
  1638. fn->tmpspace_req=0;
  1639. fn->fpStackUsage=0;
  1640. fn->canHaveDenormalOutput=0;
  1641. if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++;
  1642. codeCall=compileCodeBlockWithRet(ctx,fn->opcodes,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
  1643. if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--;
  1644. if (codeCall)
  1645. {
  1646. void *f=GLUE_realAddress(nseel_asm_fcall,nseel_asm_fcall_end,&sz);
  1647. fn->startptr = newTmpBlock(ctx,sz);
  1648. if (fn->startptr)
  1649. {
  1650. memcpy(fn->startptr,f,sz);
  1651. EEL_GLUE_set_immediate(fn->startptr,(INT_PTR)codeCall);
  1652. fn->startptr_size = sz;
  1653. }
  1654. }
  1655. }
  1656. }
  1657. if (fn->startptr)
  1658. {
  1659. if (computTableTop) *computTableTop += fn->tmpspace_req;
  1660. *customFuncParmSize = fn->num_params;
  1661. *customFuncLocalStorage = fn->localstorage;
  1662. *customFuncLocalStorageSize = fn->localstorage_size;
  1663. *rvMode = fn->rvMode;
  1664. *fpStackUse = fn->fpStackUsage;
  1665. if (canHaveDenormalOutput) *canHaveDenormalOutput= fn->canHaveDenormalOutput;
  1666. *endP = (char*)fn->startptr + fn->startptr_size;
  1667. *isRaw=1;
  1668. return fn->startptr;
  1669. }
  1670. return 0;
  1671. }
  1672. // returns true if does something (other than calculating and throwing away a value)
  1673. static char optimizeOpcodes(compileContext *ctx, opcodeRec *op, int needsResult)
  1674. {
  1675. opcodeRec *lastJoinOp=NULL;
  1676. char retv, retv_parm[3], joined_retv=0;
  1677. while (op && op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS)
  1678. {
  1679. if (!optimizeOpcodes(ctx,op->parms.parms[0], 0) || OPCODE_IS_TRIVIAL(op->parms.parms[0]))
  1680. {
  1681. // direct value, can skip ourselves
  1682. memcpy(op,op->parms.parms[1],sizeof(*op));
  1683. }
  1684. else
  1685. {
  1686. joined_retv |= 1;
  1687. lastJoinOp = op;
  1688. op = op->parms.parms[1];
  1689. }
  1690. }
  1691. goto start_over;
  1692. #define RESTART_DIRECTVALUE(X) { op->parms.dv.directValue = (X); goto start_over_directvalue; }
  1693. start_over_directvalue:
  1694. op->opcodeType = OPCODETYPE_DIRECTVALUE;
  1695. op->parms.dv.valuePtr=NULL;
  1696. start_over: // when an opcode changed substantially in optimization, goto here to reprocess it
  1697. retv = retv_parm[0]=retv_parm[1]=retv_parm[2]=0;
  1698. if (!op || // should never really happen
  1699. OPCODE_IS_TRIVIAL(op) || // should happen often (vars)
  1700. op->opcodeType < 0 || op->opcodeType >= OPCODETYPE_INVALID // should never happen (assert would be appropriate heh)
  1701. ) return joined_retv;
  1702. if (!needsResult)
  1703. {
  1704. if (op->fntype == FUNCTYPE_EELFUNC)
  1705. {
  1706. needsResult=1; // assume eel functions are non-const for now
  1707. }
  1708. else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
  1709. {
  1710. functionType *pfn = (functionType *)op->fn;
  1711. if (!pfn || !(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) needsResult=1;
  1712. }
  1713. else if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX)
  1714. {
  1715. needsResult=1;
  1716. }
  1717. }
  1718. if (op->opcodeType>=OPCODETYPE_FUNC2) retv_parm[1] = optimizeOpcodes(ctx,op->parms.parms[1], needsResult);
  1719. if (op->opcodeType>=OPCODETYPE_FUNC3) retv_parm[2] = optimizeOpcodes(ctx,op->parms.parms[2], needsResult);
  1720. retv_parm[0] = optimizeOpcodes(ctx,op->parms.parms[0], needsResult ||
  1721. (FNPTR_HAS_CONDITIONAL_EXEC(op) && (retv_parm[1] || retv_parm[2] || op->opcodeType <= OPCODETYPE_FUNC1)) );
  1722. if (op->opcodeType != OPCODETYPE_MOREPARAMS)
  1723. {
  1724. if (op->fntype >= 0 && op->fntype < FUNCTYPE_SIMPLEMAX)
  1725. {
  1726. if (op->opcodeType == OPCODETYPE_FUNC1) // within FUNCTYPE_SIMPLE
  1727. {
  1728. if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
  1729. {
  1730. switch (op->fntype)
  1731. {
  1732. case FN_NOTNOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 1.0 : 0.0);
  1733. case FN_NOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 0.0 : 1.0);
  1734. case FN_UMINUS: RESTART_DIRECTVALUE(- op->parms.parms[0]->parms.dv.directValue);
  1735. }
  1736. }
  1737. else if (op->fntype == FN_NOT || op->fntype == FN_NOTNOT)
  1738. {
  1739. if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1)
  1740. {
  1741. switch (op->parms.parms[0]->fntype)
  1742. {
  1743. case FN_UMINUS:
  1744. case FN_NOTNOT: // ignore any NOTNOTs UMINUS or UPLUS, they would have no effect anyway
  1745. op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
  1746. goto start_over;
  1747. case FN_NOT:
  1748. op->fntype = op->fntype==FN_NOT ? FN_NOTNOT : FN_NOT; // switch between FN_NOT and FN_NOTNOT
  1749. op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
  1750. goto start_over;
  1751. }
  1752. }
  1753. else if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC2)
  1754. {
  1755. int repl_type = -1;
  1756. switch (op->parms.parms[0]->fntype)
  1757. {
  1758. case FN_EQ: repl_type = FN_NE; break;
  1759. case FN_NE: repl_type = FN_EQ; break;
  1760. case FN_EQ_EXACT: repl_type = FN_NE_EXACT; break;
  1761. case FN_NE_EXACT: repl_type = FN_EQ_EXACT; break;
  1762. case FN_LT: repl_type = FN_GTE; break;
  1763. case FN_LTE: repl_type = FN_GT; break;
  1764. case FN_GT: repl_type = FN_LTE; break;
  1765. case FN_GTE: repl_type = FN_LT; break;
  1766. }
  1767. if (repl_type != -1)
  1768. {
  1769. const int oldtype = op->fntype;
  1770. memcpy(op,op->parms.parms[0],sizeof(*op));
  1771. if (oldtype == FN_NOT) op->fntype = repl_type;
  1772. goto start_over;
  1773. }
  1774. }
  1775. }
  1776. }
  1777. else if (op->opcodeType == OPCODETYPE_FUNC2) // within FUNCTYPE_SIMPLE
  1778. {
  1779. const int dv0 = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
  1780. const int dv1 = op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
  1781. if (dv0 && dv1)
  1782. {
  1783. int reval = -1;
  1784. switch (op->fntype)
  1785. {
  1786. case FN_MOD:
  1787. {
  1788. int a = (int) op->parms.parms[1]->parms.dv.directValue;
  1789. if (a)
  1790. {
  1791. a = (int) op->parms.parms[0]->parms.dv.directValue % a;
  1792. if (a<0) a=-a;
  1793. }
  1794. RESTART_DIRECTVALUE((EEL_F)a);
  1795. }
  1796. break;
  1797. case FN_SHL: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) << ((int)op->parms.parms[1]->parms.dv.directValue));
  1798. case FN_SHR: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) >> ((int)op->parms.parms[1]->parms.dv.directValue));
  1799. case FN_POW: RESTART_DIRECTVALUE(pow(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue));
  1800. case FN_DIVIDE: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue / op->parms.parms[1]->parms.dv.directValue);
  1801. case FN_MULTIPLY: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue * op->parms.parms[1]->parms.dv.directValue);
  1802. case FN_ADD: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue + op->parms.parms[1]->parms.dv.directValue);
  1803. case FN_SUB: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue);
  1804. case FN_AND: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) & ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
  1805. case FN_OR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) | ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
  1806. case FN_XOR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) ^ ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
  1807. case FN_EQ: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) < NSEEL_CLOSEFACTOR; break;
  1808. case FN_NE: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break;
  1809. case FN_EQ_EXACT: reval = op->parms.parms[0]->parms.dv.directValue == op->parms.parms[1]->parms.dv.directValue; break;
  1810. case FN_NE_EXACT: reval = op->parms.parms[0]->parms.dv.directValue != op->parms.parms[1]->parms.dv.directValue; break;
  1811. case FN_LT: reval = op->parms.parms[0]->parms.dv.directValue < op->parms.parms[1]->parms.dv.directValue; break;
  1812. case FN_LTE: reval = op->parms.parms[0]->parms.dv.directValue <= op->parms.parms[1]->parms.dv.directValue; break;
  1813. case FN_GT: reval = op->parms.parms[0]->parms.dv.directValue > op->parms.parms[1]->parms.dv.directValue; break;
  1814. case FN_GTE: reval = op->parms.parms[0]->parms.dv.directValue >= op->parms.parms[1]->parms.dv.directValue; break;
  1815. 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;
  1816. 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;
  1817. }
  1818. if (reval >= 0) RESTART_DIRECTVALUE((EEL_F) reval);
  1819. }
  1820. else if (dv0 || dv1)
  1821. {
  1822. double dvalue = op->parms.parms[!dv0]->parms.dv.directValue;
  1823. switch (op->fntype)
  1824. {
  1825. case FN_OR:
  1826. case FN_XOR:
  1827. if (!(WDL_INT64)dvalue)
  1828. {
  1829. // replace with or0
  1830. static functionType fr={"or0",nseel_asm_or0, nseel_asm_or0_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_LASTPARMONSTACK|BIF_RETURNSONSTACK|BIF_CLEARDENORMAL, {0}, NULL};
  1831. op->opcodeType = OPCODETYPE_FUNC1;
  1832. op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
  1833. op->fn = &fr;
  1834. if (dv0) op->parms.parms[0] = op->parms.parms[1];
  1835. goto start_over;
  1836. }
  1837. break;
  1838. case FN_SUB:
  1839. if (dv0)
  1840. {
  1841. if (dvalue == 0.0)
  1842. {
  1843. op->opcodeType = OPCODETYPE_FUNC1;
  1844. op->fntype = FN_UMINUS;
  1845. op->parms.parms[0] = op->parms.parms[1];
  1846. goto start_over;
  1847. }
  1848. break;
  1849. }
  1850. // fall through, if dv1 we can remove +0.0
  1851. case FN_ADD:
  1852. if (dvalue == 0.0)
  1853. {
  1854. memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
  1855. goto start_over;
  1856. }
  1857. break;
  1858. case FN_AND:
  1859. if ((WDL_INT64)dvalue) break;
  1860. dvalue = 0.0; // treat x&0 as x*0, which optimizes to 0
  1861. // fall through
  1862. case FN_MULTIPLY:
  1863. if (dvalue == 0.0) // remove multiply by 0.0 (using 0.0 direct value as replacement), unless the nonzero side did something
  1864. {
  1865. if (!retv_parm[!!dv0])
  1866. {
  1867. memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything
  1868. goto start_over;
  1869. }
  1870. else
  1871. {
  1872. // this is 0.0 * oldexpressionthatmustbeprocessed or oldexpressionthatmustbeprocessed*0.0
  1873. op->fntype = FN_JOIN_STATEMENTS;
  1874. if (dv0) // 0.0*oldexpression, reverse the order so that 0 is returned
  1875. {
  1876. // set to (oldexpression;0)
  1877. opcodeRec *tmp = op->parms.parms[1];
  1878. op->parms.parms[1] = op->parms.parms[0];
  1879. op->parms.parms[0] = tmp;
  1880. }
  1881. goto start_over;
  1882. }
  1883. }
  1884. else if (dvalue == 1.0) // remove multiply by 1.0 (using non-1.0 value as replacement)
  1885. {
  1886. memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
  1887. goto start_over;
  1888. }
  1889. break;
  1890. case FN_POW:
  1891. if (dv1)
  1892. {
  1893. // x^0 = 1
  1894. if (fabs(dvalue) < 1e-30)
  1895. {
  1896. RESTART_DIRECTVALUE(1.0);
  1897. }
  1898. // x^1 = x
  1899. if (fabs(dvalue-1.0) < 1e-30)
  1900. {
  1901. memcpy(op,op->parms.parms[0],sizeof(*op));
  1902. goto start_over;
  1903. }
  1904. }
  1905. else if (dv0)
  1906. {
  1907. // pow(constant, x) = exp((x) * ln(constant)), if constant>0
  1908. // opcodeRec *parm0 = op->parms.parms[0];
  1909. if (dvalue > 0.0)
  1910. {
  1911. static functionType expcpy={ "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, };
  1912. // 1^x = 1
  1913. if (fabs(dvalue-1.0) < 1e-30)
  1914. {
  1915. RESTART_DIRECTVALUE(1.0);
  1916. }
  1917. dvalue=log(dvalue);
  1918. if (fabs(dvalue-1.0) < 1e-9)
  1919. {
  1920. // caller wanted e^x
  1921. op->parms.parms[0]=op->parms.parms[1];
  1922. }
  1923. else
  1924. {
  1925. // it would be nice to replace 10^x with exp(log(10)*x) or 2^x with exp(log(2),x), but
  1926. // doing so breaks rounding. we could maybe only allow 10^x, which is used for dB conversion,
  1927. // but for now we should just force the programmer do it exp(log(10)*x) themselves.
  1928. break;
  1929. /*
  1930. parm0->opcodeType = OPCODETYPE_FUNC2;
  1931. parm0->fntype = FN_MULTIPLY;
  1932. parm0->parms.parms[0] = nseel_createCompiledValue(ctx,dvalue);
  1933. parm0->parms.parms[1] = op->parms.parms[1];
  1934. */
  1935. }
  1936. op->opcodeType = OPCODETYPE_FUNC1;
  1937. op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
  1938. op->fn = &expcpy;
  1939. goto start_over;
  1940. }
  1941. }
  1942. break;
  1943. case FN_MOD:
  1944. if (dv1)
  1945. {
  1946. const int a = (int) dvalue;
  1947. if (!a)
  1948. {
  1949. RESTART_DIRECTVALUE(0.0);
  1950. }
  1951. }
  1952. break;
  1953. case FN_DIVIDE:
  1954. if (dv1)
  1955. {
  1956. if (dvalue == 1.0) // remove divide by 1.0 (using non-1.0 value as replacement)
  1957. {
  1958. memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
  1959. goto start_over;
  1960. }
  1961. else
  1962. {
  1963. // change to a multiply
  1964. if (dvalue == 0.0)
  1965. {
  1966. op->fntype = FN_MULTIPLY;
  1967. goto start_over;
  1968. }
  1969. else
  1970. {
  1971. double d = 1.0/dvalue;
  1972. WDL_DenormalDoubleAccess *p = (WDL_DenormalDoubleAccess*)&d;
  1973. // allow conversion to multiply if reciprocal is exact
  1974. // we could also just look to see if the last few digits of the mantissa were 0, which would probably be good
  1975. // enough, but if the user really wants it they should do * (1/x) instead to force precalculation of reciprocal.
  1976. if (!p->w.lw && !(p->w.hw & 0xfffff))
  1977. {
  1978. op->fntype = FN_MULTIPLY;
  1979. op->parms.parms[1]->parms.dv.directValue = d;
  1980. op->parms.parms[1]->parms.dv.valuePtr=NULL;
  1981. goto start_over;
  1982. }
  1983. }
  1984. }
  1985. }
  1986. else if (dvalue == 0.0)
  1987. {
  1988. if (!retv_parm[!!dv0])
  1989. {
  1990. // if 0/x set to always 0.
  1991. // this is 0.0 / (oldexpression that can be eliminated)
  1992. memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything
  1993. }
  1994. else
  1995. {
  1996. opcodeRec *tmp;
  1997. // this is 0.0 / oldexpressionthatmustbeprocessed
  1998. op->fntype = FN_JOIN_STATEMENTS;
  1999. tmp = op->parms.parms[1];
  2000. op->parms.parms[1] = op->parms.parms[0];
  2001. op->parms.parms[0] = tmp;
  2002. // set to (oldexpression;0)
  2003. }
  2004. goto start_over;
  2005. }
  2006. break;
  2007. case FN_EQ:
  2008. if (dvalue == 0.0)
  2009. {
  2010. // convert x == 0.0 to !x
  2011. op->opcodeType=OPCODETYPE_FUNC1;
  2012. op->fntype = FN_NOT;
  2013. if (dv0) op->parms.parms[0]=op->parms.parms[1];
  2014. goto start_over;
  2015. }
  2016. break;
  2017. case FN_NE:
  2018. if (dvalue == 0.0)
  2019. {
  2020. // convert x != 0.0 to !!
  2021. op->opcodeType=OPCODETYPE_FUNC1;
  2022. op->fntype = FN_NOTNOT;
  2023. if (dv0) op->parms.parms[0]=op->parms.parms[1];
  2024. goto start_over;
  2025. }
  2026. break;
  2027. case FN_LOGICAL_AND:
  2028. if (dv0)
  2029. {
  2030. // dvalue && expr
  2031. if (fabs(dvalue) < NSEEL_CLOSEFACTOR)
  2032. {
  2033. // 0 && expr, replace with 0
  2034. RESTART_DIRECTVALUE(0.0);
  2035. }
  2036. else
  2037. {
  2038. // 1 && expr, replace with 0 != expr
  2039. op->fntype = FN_NE;
  2040. op->parms.parms[0]->parms.dv.valuePtr=NULL;
  2041. op->parms.parms[0]->parms.dv.directValue = 0.0;
  2042. }
  2043. }
  2044. else
  2045. {
  2046. // expr && dvalue
  2047. if (fabs(dvalue) < NSEEL_CLOSEFACTOR)
  2048. {
  2049. // expr && 0
  2050. if (!retv_parm[0])
  2051. {
  2052. // expr has no consequence, drop it
  2053. RESTART_DIRECTVALUE(0.0);
  2054. }
  2055. else
  2056. {
  2057. // replace with (expr; 0)
  2058. op->fntype = FN_JOIN_STATEMENTS;
  2059. op->parms.parms[1]->parms.dv.valuePtr=NULL;
  2060. op->parms.parms[1]->parms.dv.directValue = 0.0;
  2061. }
  2062. }
  2063. else
  2064. {
  2065. // expr && 1, replace with expr != 0
  2066. op->fntype = FN_NE;
  2067. op->parms.parms[1]->parms.dv.valuePtr=NULL;
  2068. op->parms.parms[1]->parms.dv.directValue = 0.0;
  2069. }
  2070. }
  2071. goto start_over;
  2072. case FN_LOGICAL_OR:
  2073. if (dv0)
  2074. {
  2075. // dvalue || expr
  2076. if (fabs(dvalue) >= NSEEL_CLOSEFACTOR)
  2077. {
  2078. // 1 || expr, replace with 1
  2079. RESTART_DIRECTVALUE(1.0);
  2080. }
  2081. else
  2082. {
  2083. // 0 || expr, replace with 0 != expr
  2084. op->fntype = FN_NE;
  2085. op->parms.parms[0]->parms.dv.valuePtr=NULL;
  2086. op->parms.parms[0]->parms.dv.directValue = 0.0;
  2087. }
  2088. }
  2089. else
  2090. {
  2091. // expr || dvalue
  2092. if (fabs(dvalue) >= NSEEL_CLOSEFACTOR)
  2093. {
  2094. // expr || 1
  2095. if (!retv_parm[0])
  2096. {
  2097. // expr has no consequence, drop it and return 1
  2098. RESTART_DIRECTVALUE(1.0);
  2099. }
  2100. else
  2101. {
  2102. // replace with (expr; 1)
  2103. op->fntype = FN_JOIN_STATEMENTS;
  2104. op->parms.parms[1]->parms.dv.valuePtr=NULL;
  2105. op->parms.parms[1]->parms.dv.directValue = 1.0;
  2106. }
  2107. }
  2108. else
  2109. {
  2110. // expr || 0, replace with expr != 0
  2111. op->fntype = FN_NE;
  2112. op->parms.parms[1]->parms.dv.valuePtr=NULL;
  2113. op->parms.parms[1]->parms.dv.directValue = 0.0;
  2114. }
  2115. }
  2116. goto start_over;
  2117. }
  2118. } // dv0 || dv1
  2119. // general optimization of two parameters
  2120. switch (op->fntype)
  2121. {
  2122. case FN_MULTIPLY:
  2123. {
  2124. opcodeRec *first_parm = op->parms.parms[0],*second_parm = op->parms.parms[1];
  2125. if (second_parm->opcodeType == first_parm->opcodeType)
  2126. {
  2127. switch(first_parm->opcodeType)
  2128. {
  2129. case OPCODETYPE_VALUE_FROM_NAMESPACENAME:
  2130. if (first_parm->namespaceidx != second_parm->namespaceidx) break;
  2131. // fall through
  2132. case OPCODETYPE_VARPTR:
  2133. if (first_parm->relname && second_parm->relname && !stricmp(second_parm->relname,first_parm->relname)) second_parm=NULL;
  2134. break;
  2135. case OPCODETYPE_VARPTRPTR:
  2136. if (first_parm->parms.dv.valuePtr && first_parm->parms.dv.valuePtr==second_parm->parms.dv.valuePtr) second_parm=NULL;
  2137. break;
  2138. }
  2139. if (!second_parm) // switch from x*x to sqr(x)
  2140. {
  2141. static functionType sqrcpy={ "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) };
  2142. op->opcodeType = OPCODETYPE_FUNC1;
  2143. op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
  2144. op->fn = &sqrcpy;
  2145. goto start_over;
  2146. }
  2147. }
  2148. }
  2149. break;
  2150. case FN_POW:
  2151. {
  2152. opcodeRec *first_parm = op->parms.parms[0];
  2153. if (first_parm->opcodeType == op->opcodeType && first_parm->fntype == FN_POW)
  2154. {
  2155. // since first_parm is a pow too, we can multiply the exponents.
  2156. // set our base to be the base of the inner pow
  2157. op->parms.parms[0] = first_parm->parms.parms[0];
  2158. // make the old extra pow be a multiply of the exponents
  2159. first_parm->fntype = FN_MULTIPLY;
  2160. first_parm->parms.parms[0] = op->parms.parms[1];
  2161. // put that as the exponent
  2162. op->parms.parms[1] = first_parm;
  2163. goto start_over;
  2164. }
  2165. }
  2166. break;
  2167. case FN_LOGICAL_AND:
  2168. case FN_LOGICAL_OR:
  2169. if (op->parms.parms[0]->fntype == FN_NOTNOT)
  2170. {
  2171. // remove notnot, unnecessary for input to &&/|| operators
  2172. op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
  2173. goto start_over;
  2174. }
  2175. if (op->parms.parms[1]->fntype == FN_NOTNOT)
  2176. {
  2177. // remove notnot, unnecessary for input to &&/|| operators
  2178. op->parms.parms[1] = op->parms.parms[1]->parms.parms[0];
  2179. goto start_over;
  2180. }
  2181. break;
  2182. }
  2183. }
  2184. else if (op->opcodeType==OPCODETYPE_FUNC3) // within FUNCTYPE_SIMPLE
  2185. {
  2186. if (op->fntype == FN_IF_ELSE)
  2187. {
  2188. if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
  2189. {
  2190. int s = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR;
  2191. memcpy(op,op->parms.parms[s ? 1 : 2],sizeof(opcodeRec));
  2192. goto start_over;
  2193. }
  2194. if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1)
  2195. {
  2196. if (op->parms.parms[0]->fntype == FN_NOTNOT)
  2197. {
  2198. // remove notnot, unnecessary for input to ? operator
  2199. op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
  2200. goto start_over;
  2201. }
  2202. }
  2203. }
  2204. }
  2205. if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX) retv|=1;
  2206. // FUNCTYPE_SIMPLE
  2207. }
  2208. else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC && op->fn)
  2209. {
  2210. /*
  2211. probably worth doing reduction on:
  2212. _divop (constant change to multiply)
  2213. _and
  2214. _or
  2215. abs
  2216. maybe:
  2217. min
  2218. max
  2219. also, optimize should (recursively or maybe iteratively?) search transitive functions (mul/div) for more constant reduction possibilities
  2220. */
  2221. functionType *pfn = (functionType *)op->fn;
  2222. if (!(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) retv|=1;
  2223. if (op->opcodeType==OPCODETYPE_FUNC1) // within FUNCTYPE_FUNCTIONTYPEREC
  2224. {
  2225. if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
  2226. {
  2227. int suc=1;
  2228. EEL_F v = op->parms.parms[0]->parms.dv.directValue;
  2229. #define DOF(x) if (!strcmp(pfn->name,#x)) v = x(v); else
  2230. #define DOF2(x,y) if (!strcmp(pfn->name,#x)) v = x(y); else
  2231. DOF(sin)
  2232. DOF(cos)
  2233. DOF(tan)
  2234. DOF(asin)
  2235. DOF(acos)
  2236. DOF(atan)
  2237. DOF2(sqrt, fabs(v))
  2238. DOF(exp)
  2239. DOF(log)
  2240. DOF(log10)
  2241. /* else */ suc=0;
  2242. #undef DOF
  2243. #undef DOF2
  2244. if (suc)
  2245. {
  2246. RESTART_DIRECTVALUE(v);
  2247. }
  2248. }
  2249. }
  2250. else if (op->opcodeType==OPCODETYPE_FUNC2) // within FUNCTYPE_FUNCTIONTYPEREC
  2251. {
  2252. const int dv0=op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
  2253. const int dv1=op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
  2254. if (dv0 && dv1)
  2255. {
  2256. if (!strcmp(pfn->name,"atan2"))
  2257. {
  2258. RESTART_DIRECTVALUE(atan2(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue));
  2259. }
  2260. }
  2261. }
  2262. // FUNCTYPE_FUNCTIONTYPEREC
  2263. }
  2264. else
  2265. {
  2266. // unknown or eel func, assume non-const
  2267. retv |= 1;
  2268. }
  2269. }
  2270. // if we need results, or our function has effects itself, then finish
  2271. if (retv || needsResult)
  2272. {
  2273. return retv || joined_retv || retv_parm[0] || retv_parm[1] || retv_parm[2];
  2274. }
  2275. // we don't need results here, and our function is const, which means we can remove it
  2276. {
  2277. int cnt=0, idx1=0, idx2=0, x;
  2278. for (x=0;x<3;x++) if (retv_parm[x]) { if (!cnt++) idx1=x; else idx2=x; }
  2279. if (!cnt) // none of the parameters do anything, remove this opcode
  2280. {
  2281. if (lastJoinOp)
  2282. {
  2283. // replace previous join with its first linked opcode, removing this opcode completely
  2284. memcpy(lastJoinOp,lastJoinOp->parms.parms[0],sizeof(*lastJoinOp));
  2285. }
  2286. else if (op->opcodeType != OPCODETYPE_DIRECTVALUE)
  2287. {
  2288. // allow caller to easily detect this as trivial and remove it
  2289. op->opcodeType = OPCODETYPE_DIRECTVALUE;
  2290. op->parms.dv.valuePtr=NULL;
  2291. op->parms.dv.directValue=0.0;
  2292. }
  2293. // return joined_retv below
  2294. }
  2295. else
  2296. {
  2297. // if parameters are non-const, and we're a conditional, preserve our function
  2298. if (FNPTR_HAS_CONDITIONAL_EXEC(op)) return 1;
  2299. // otherwise, condense into either the non-const statement, or a join
  2300. if (cnt==1)
  2301. {
  2302. memcpy(op,op->parms.parms[idx1],sizeof(*op));
  2303. }
  2304. else if (cnt == 2)
  2305. {
  2306. op->opcodeType = OPCODETYPE_FUNC2;
  2307. op->fntype = FN_JOIN_STATEMENTS;
  2308. op->fn = op;
  2309. op->parms.parms[0] = op->parms.parms[idx1];
  2310. op->parms.parms[1] = op->parms.parms[idx2];
  2311. op->parms.parms[2] = NULL;
  2312. }
  2313. else
  2314. {
  2315. // todo need to create a new opcodeRec here, for now just leave as is
  2316. // (non-conditional const 3 parameter functions are rare anyway)
  2317. }
  2318. return 1;
  2319. }
  2320. }
  2321. return joined_retv;
  2322. }
  2323. static int generateValueToReg(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int whichReg, const namespaceInformation *functionPrefix, int allowCache)
  2324. {
  2325. EEL_F *b=NULL;
  2326. if (op->opcodeType==OPCODETYPE_VALUE_FROM_NAMESPACENAME)
  2327. {
  2328. char nm[NSEEL_MAX_VARIABLE_NAMELEN+1];
  2329. const char *p = op->relname;
  2330. combineNamespaceFields(nm,functionPrefix,p+(*p == '#'),op->namespaceidx);
  2331. if (!nm[0]) return -1;
  2332. if (*p == '#')
  2333. {
  2334. if (ctx->isGeneratingCommonFunction)
  2335. b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F));
  2336. else
  2337. b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F));
  2338. if (!b) RET_MINUS1_FAIL("error creating storage for str")
  2339. if (!ctx->onNamedString) return -1; // should never happen, will not generate OPCODETYPE_VALUE_FROM_NAMESPACENAME with # prefix if !onNamedString
  2340. *b = ctx->onNamedString(ctx->caller_this,nm);
  2341. }
  2342. else
  2343. {
  2344. b = nseel_int_register_var(ctx,nm,0,NULL);
  2345. if (!b) RET_MINUS1_FAIL("error registering var")
  2346. }
  2347. }
  2348. else
  2349. {
  2350. if (op->opcodeType != OPCODETYPE_DIRECTVALUE) allowCache=0;
  2351. if (op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING && ctx->onNamedString)
  2352. {
  2353. op->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,"");
  2354. op->parms.dv.valuePtr = NULL;
  2355. }
  2356. b=op->parms.dv.valuePtr;
  2357. if (!b && op->opcodeType == OPCODETYPE_VARPTR && op->relname && op->relname[0])
  2358. {
  2359. op->parms.dv.valuePtr = b = nseel_int_register_var(ctx,op->relname,0,NULL);
  2360. }
  2361. if (b && op->opcodeType == OPCODETYPE_VARPTRPTR) b = *(EEL_F **)b;
  2362. if (!b && allowCache)
  2363. {
  2364. int n=50; // only scan last X items
  2365. opcodeRec *r = ctx->directValueCache;
  2366. while (r && n--)
  2367. {
  2368. if (r->parms.dv.directValue == op->parms.dv.directValue && (b=r->parms.dv.valuePtr)) break;
  2369. r=(opcodeRec*)r->fn;
  2370. }
  2371. }
  2372. if (!b)
  2373. {
  2374. ctx->l_stats[3]++;
  2375. if (ctx->isGeneratingCommonFunction)
  2376. b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F));
  2377. else
  2378. b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F));
  2379. if (!b) RET_MINUS1_FAIL("error allocating data block")
  2380. if (op->opcodeType != OPCODETYPE_VARPTRPTR) op->parms.dv.valuePtr = b;
  2381. #if EEL_F_SIZE == 8
  2382. *b = denormal_filter_double2(op->parms.dv.directValue);
  2383. #else
  2384. *b = denormal_filter_float2(op->parms.dv.directValue);
  2385. #endif
  2386. if (allowCache)
  2387. {
  2388. op->fn = ctx->directValueCache;
  2389. ctx->directValueCache = op;
  2390. }
  2391. }
  2392. }
  2393. GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut,(INT_PTR)b,whichReg);
  2394. return GLUE_MOV_PX_DIRECTVALUE_SIZE;
  2395. }
  2396. unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis,
  2397. int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput)
  2398. {
  2399. unsigned char *p, *newblock2;
  2400. // generate code call
  2401. int funcsz=compileOpcodes(ctx,rec,NULL,1024*1024*128,NULL,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, NULL);
  2402. if (funcsz<0) return NULL;
  2403. p = newblock2 = newCodeBlock(funcsz+ sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
  2404. if (!newblock2) return NULL;
  2405. #if GLUE_FUNC_ENTER_SIZE > 0
  2406. memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE);
  2407. p += GLUE_FUNC_ENTER_SIZE;
  2408. #endif
  2409. *fpStackUsage=0;
  2410. funcsz=compileOpcodes(ctx,rec,p, funcsz, computTableSize,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, canHaveDenormalOutput);
  2411. if (funcsz<0) return NULL;
  2412. p+=funcsz;
  2413. #if GLUE_FUNC_LEAVE_SIZE > 0
  2414. memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE);
  2415. p+=GLUE_FUNC_LEAVE_SIZE;
  2416. #endif
  2417. memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
  2418. #if defined(__arm__) || defined(__aarch64__)
  2419. __clear_cache(newblock2,p);
  2420. #endif
  2421. ctx->l_stats[2]+=funcsz+2;
  2422. return newblock2;
  2423. }
  2424. static int compileNativeFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
  2425. int *rvMode, int *fpStackUsage, int preferredReturnValues, int *canHaveDenormalOutput)
  2426. {
  2427. // builtin function generation
  2428. int func_size=0;
  2429. int cfunc_abiinfo=0;
  2430. int local_fpstack_use=0; // how many items we have pushed onto the fp stack
  2431. int parm_size=0;
  2432. int restore_stack_amt=0;
  2433. void *func_e=NULL;
  2434. NSEEL_PPPROC preProc=0;
  2435. void **repl=NULL;
  2436. int n_params= 1 + op->opcodeType - OPCODETYPE_FUNC1;
  2437. const int parm0_dv = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
  2438. const int parm1_dv = n_params > 1 && op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
  2439. void *func = nseel_getBuiltinFunctionAddress(ctx, op->fntype, op->fn, &preProc,&repl,&func_e,&cfunc_abiinfo,preferredReturnValues,
  2440. parm0_dv ? &op->parms.parms[0]->parms.dv.directValue : NULL,
  2441. parm1_dv ? &op->parms.parms[1]->parms.dv.directValue : NULL
  2442. );
  2443. if (!func) RET_MINUS1_FAIL("error getting funcaddr")
  2444. *fpStackUsage=BIF_GETFPSTACKUSE(cfunc_abiinfo);
  2445. *rvMode = RETURNVALUE_NORMAL;
  2446. if (cfunc_abiinfo & BIF_TAKES_VARPARM)
  2447. {
  2448. #if defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7)
  2449. const int max_params=16384; // arm uses up to two instructions, should be good for at leaast 64k (16384*4)
  2450. #elif defined(__ppc__)
  2451. const int max_params=4096; // 32kb max offset addressing for stack, so 4096*4 = 16384, should be safe
  2452. #elif defined(__aarch64__)
  2453. const int max_params=32768;
  2454. #else
  2455. const int max_params=32768; // sanity check, the stack is free to grow on x86/x86-64
  2456. #endif
  2457. int x;
  2458. // this mode is less efficient in that it creates a list of pointers on the stack to pass to the function
  2459. // but it is more flexible and works for >3 parameters.
  2460. if (op->opcodeType == OPCODETYPE_FUNCX)
  2461. {
  2462. n_params=0;
  2463. for (x=0;x<3;x++)
  2464. {
  2465. opcodeRec *prni=op->parms.parms[x];
  2466. while (prni)
  2467. {
  2468. const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
  2469. n_params++;
  2470. if (!isMP||n_params>=max_params) break;
  2471. prni = prni->parms.parms[1];
  2472. }
  2473. }
  2474. }
  2475. restore_stack_amt = (sizeof(void *) * n_params + 15)&~15;
  2476. if (restore_stack_amt)
  2477. {
  2478. int offs = restore_stack_amt;
  2479. while (offs > 0)
  2480. {
  2481. int amt = offs;
  2482. if (amt > 4096) amt=4096;
  2483. if (bufOut_len < parm_size+GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm")
  2484. if (bufOut) GLUE_MOVE_STACK(bufOut+parm_size, - amt);
  2485. parm_size += GLUE_MOVE_STACK_SIZE;
  2486. offs -= amt;
  2487. if (offs>0) // make sure this page is in memory
  2488. {
  2489. if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0))
  2490. RET_MINUS1_FAIL("insufficient size for varparm stackchk")
  2491. if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut+parm_size,0);
  2492. parm_size += GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0);
  2493. }
  2494. }
  2495. }
  2496. if (op->opcodeType == OPCODETYPE_FUNCX)
  2497. {
  2498. n_params=0;
  2499. for (x=0;x<3;x++)
  2500. {
  2501. opcodeRec *prni=op->parms.parms[x];
  2502. while (prni)
  2503. {
  2504. const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
  2505. opcodeRec *r = isMP ? prni->parms.parms[0] : prni;
  2506. if (r)
  2507. {
  2508. int canHaveDenorm=0;
  2509. int rvt=RETURNVALUE_NORMAL;
  2510. int subfpstackuse=0, use_offs;
  2511. int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
  2512. if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
  2513. if (lsz<0) RET_MINUS1_FAIL("call coc for varparmX failed")
  2514. if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparmX gave bad type back");
  2515. parm_size += lsz;
  2516. use_offs = n_params*(int) sizeof(void *);
  2517. if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs))
  2518. RET_MINUS1_FAIL("call coc for varparmX size");
  2519. if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs);
  2520. parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs);
  2521. if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
  2522. }
  2523. else RET_MINUS1_FAIL("zero parameter varparmX")
  2524. n_params++;
  2525. if (!isMP||n_params>=max_params) break;
  2526. prni = prni->parms.parms[1];
  2527. }
  2528. }
  2529. }
  2530. else for (x=0;x<n_params;x++)
  2531. {
  2532. opcodeRec *r = op->parms.parms[x];
  2533. if (r)
  2534. {
  2535. int canHaveDenorm=0;
  2536. int subfpstackuse=0;
  2537. int rvt=RETURNVALUE_NORMAL;
  2538. int use_offs;
  2539. int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
  2540. if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
  2541. if (lsz<0) RET_MINUS1_FAIL("call coc for varparm123 failed")
  2542. if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparm123 gave bad type back");
  2543. parm_size += lsz;
  2544. use_offs = x*(int)sizeof(void *);
  2545. if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs))
  2546. RET_MINUS1_FAIL("call coc for varparm123 size");
  2547. if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs);
  2548. parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs);
  2549. if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
  2550. }
  2551. else RET_MINUS1_FAIL("zero parameter for varparm123");
  2552. }
  2553. if (bufOut_len < parm_size+GLUE_MOV_PX_DIRECTVALUE_SIZE+GLUE_MOVE_PX_STACKPTR_SIZE) RET_MINUS1_FAIL("insufficient size for varparm p1")
  2554. if (bufOut) GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut+parm_size, (INT_PTR)n_params,1);
  2555. parm_size+=GLUE_MOV_PX_DIRECTVALUE_SIZE;
  2556. if (bufOut) GLUE_MOVE_PX_STACKPTR_GEN(bufOut+parm_size, 0);
  2557. parm_size+=GLUE_MOVE_PX_STACKPTR_SIZE;
  2558. }
  2559. else // not varparm
  2560. {
  2561. int pn;
  2562. #ifdef GLUE_HAS_FXCH
  2563. int need_fxch=0;
  2564. #endif
  2565. int last_nt_parm=-1, last_nt_parm_type=-1;
  2566. if (op->opcodeType == OPCODETYPE_FUNCX)
  2567. {
  2568. // this is not yet supported (calling conventions will need to be sorted, among other things)
  2569. RET_MINUS1_FAIL("funcx for native functions requires BIF_TAKES_VARPARM or BIF_TAKES_VARPARM_EX")
  2570. }
  2571. if (parm0_dv)
  2572. {
  2573. if (func == nseel_asm_stack_pop)
  2574. {
  2575. func = GLUE_realAddress(nseel_asm_stack_pop_fast,nseel_asm_stack_pop_fast_end,&func_size);
  2576. if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on popfast size":"failed on popfast addr")
  2577. if (bufOut)
  2578. {
  2579. memcpy(bufOut,func,func_size);
  2580. NSEEL_PProc_Stack(bufOut,func_size,ctx);
  2581. }
  2582. return func_size;
  2583. }
  2584. else if (func == nseel_asm_stack_peek)
  2585. {
  2586. int f = (int) op->parms.parms[0]->parms.dv.directValue;
  2587. if (!f)
  2588. {
  2589. func = GLUE_realAddress(nseel_asm_stack_peek_top,nseel_asm_stack_peek_top_end,&func_size);
  2590. if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peek size":"failed on peek addr")
  2591. if (bufOut)
  2592. {
  2593. memcpy(bufOut,func,func_size);
  2594. NSEEL_PProc_Stack_PeekTop(bufOut,func_size,ctx);
  2595. }
  2596. return func_size;
  2597. }
  2598. else
  2599. {
  2600. func = GLUE_realAddress(nseel_asm_stack_peek_int,nseel_asm_stack_peek_int_end,&func_size);
  2601. if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peekint size":"failed on peekint addr")
  2602. if (bufOut)
  2603. {
  2604. memcpy(bufOut,func,func_size);
  2605. NSEEL_PProc_Stack_PeekInt(bufOut,func_size,ctx,f*sizeof(EEL_F));
  2606. }
  2607. return func_size;
  2608. }
  2609. }
  2610. }
  2611. // end of built-in function specific special casing
  2612. // first pass, calculate any non-trivial parameters
  2613. for (pn=0; pn < n_params; pn++)
  2614. {
  2615. if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
  2616. {
  2617. int canHaveDenorm=0;
  2618. int subfpstackuse=0;
  2619. int lsz=0;
  2620. int rvt=RETURNVALUE_NORMAL;
  2621. int may_need_fppush=-1;
  2622. if (last_nt_parm>=0)
  2623. {
  2624. if (last_nt_parm_type==RETURNVALUE_FPSTACK)
  2625. {
  2626. may_need_fppush= parm_size;
  2627. }
  2628. else
  2629. {
  2630. // push last result
  2631. if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1)) RET_MINUS1_FAIL("failed on size, pushp1")
  2632. if (bufOut) memcpy(bufOut + parm_size, &GLUE_PUSH_P1, sizeof(GLUE_PUSH_P1));
  2633. parm_size += sizeof(GLUE_PUSH_P1);
  2634. }
  2635. }
  2636. if (func == nseel_asm_bnot) rvt=RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL;
  2637. else if (pn == n_params - 1)
  2638. {
  2639. if (cfunc_abiinfo&BIF_LASTPARMONSTACK) rvt=RETURNVALUE_FPSTACK;
  2640. else if (cfunc_abiinfo&BIF_LASTPARM_ASBOOL) rvt=RETURNVALUE_BOOL;
  2641. else if (func == nseel_asm_assign) rvt=RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL;
  2642. }
  2643. else if (pn == n_params -2 && (cfunc_abiinfo&BIF_SECONDLASTPARMST))
  2644. {
  2645. rvt=RETURNVALUE_FPSTACK;
  2646. }
  2647. lsz = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
  2648. if (lsz<0) RET_MINUS1_FAIL("call coc failed")
  2649. if (func == nseel_asm_bnot && rvt==RETURNVALUE_BOOL_REVERSED)
  2650. {
  2651. // remove bnot, compileOpcodes() used fptobool_rev
  2652. #ifndef EEL_TARGET_PORTABLE
  2653. func = nseel_asm_uplus;
  2654. func_e = nseel_asm_uplus_end;
  2655. #else
  2656. func = nseel_asm_bnotnot;
  2657. func_e = nseel_asm_bnotnot_end;
  2658. #endif
  2659. rvt = RETURNVALUE_BOOL;
  2660. }
  2661. if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
  2662. parm_size += lsz;
  2663. if (may_need_fppush>=0)
  2664. {
  2665. if (local_fpstack_use+subfpstackuse >= (GLUE_MAX_FPSTACK_SIZE-1) || (ctx->optimizeDisableFlags&OPTFLAG_NO_FPSTACK))
  2666. {
  2667. if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK))
  2668. RET_MINUS1_FAIL("failed on size, popfpstacktostack")
  2669. if (bufOut)
  2670. {
  2671. memmove(bufOut + may_need_fppush + sizeof(GLUE_POP_FPSTACK_TOSTACK), bufOut + may_need_fppush, parm_size - may_need_fppush);
  2672. memcpy(bufOut + may_need_fppush, &GLUE_POP_FPSTACK_TOSTACK, sizeof(GLUE_POP_FPSTACK_TOSTACK));
  2673. }
  2674. parm_size += sizeof(GLUE_POP_FPSTACK_TOSTACK);
  2675. }
  2676. else
  2677. {
  2678. local_fpstack_use++;
  2679. }
  2680. }
  2681. if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
  2682. last_nt_parm = pn;
  2683. last_nt_parm_type = rvt;
  2684. if (pn == n_params - 1 && func == nseel_asm_assign)
  2685. {
  2686. if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS) &&
  2687. (!canHaveDenorm || (ctx->optimizeDisableFlags & OPTFLAG_NO_DENORMAL_CHECKS)))
  2688. {
  2689. if (rvt == RETURNVALUE_FPSTACK)
  2690. {
  2691. cfunc_abiinfo |= BIF_LASTPARMONSTACK;
  2692. func = nseel_asm_assign_fast_fromfp;
  2693. func_e = nseel_asm_assign_fast_fromfp_end;
  2694. }
  2695. else
  2696. {
  2697. func = nseel_asm_assign_fast;
  2698. func_e = nseel_asm_assign_fast_end;
  2699. }
  2700. }
  2701. else
  2702. {
  2703. if (rvt == RETURNVALUE_FPSTACK)
  2704. {
  2705. cfunc_abiinfo |= BIF_LASTPARMONSTACK;
  2706. func = nseel_asm_assign_fromfp;
  2707. func_e = nseel_asm_assign_fromfp_end;
  2708. }
  2709. }
  2710. }
  2711. }
  2712. }
  2713. pn = last_nt_parm;
  2714. if (pn >= 0) // if the last thing executed doesn't go to the last parameter, move it there
  2715. {
  2716. if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2)
  2717. {
  2718. // do nothing, things are in the right place
  2719. }
  2720. else if (pn != n_params-1)
  2721. {
  2722. // generate mov p1->pX
  2723. if (bufOut_len < parm_size + GLUE_SET_PX_FROM_P1_SIZE) RET_MINUS1_FAIL("size, pxfromp1")
  2724. if (bufOut) GLUE_SET_PX_FROM_P1(bufOut + parm_size,n_params - 1 - pn);
  2725. parm_size += GLUE_SET_PX_FROM_P1_SIZE;
  2726. }
  2727. }
  2728. // pop any pushed parameters
  2729. while (--pn >= 0)
  2730. {
  2731. if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
  2732. {
  2733. if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2)
  2734. {
  2735. if (!local_fpstack_use)
  2736. {
  2737. if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_STACK_TO_FPSTACK)) RET_MINUS1_FAIL("size, popstacktofpstack 2")
  2738. if (bufOut) memcpy(bufOut+parm_size,GLUE_POP_STACK_TO_FPSTACK,sizeof(GLUE_POP_STACK_TO_FPSTACK));
  2739. parm_size += sizeof(GLUE_POP_STACK_TO_FPSTACK);
  2740. #ifdef GLUE_HAS_FXCH
  2741. need_fxch = 1;
  2742. #endif
  2743. }
  2744. else
  2745. {
  2746. local_fpstack_use--;
  2747. }
  2748. }
  2749. else
  2750. {
  2751. if (bufOut_len < parm_size + GLUE_POP_PX_SIZE) RET_MINUS1_FAIL("size, poppx")
  2752. if (bufOut) GLUE_POP_PX(bufOut + parm_size,n_params - 1 - pn);
  2753. parm_size += GLUE_POP_PX_SIZE;
  2754. }
  2755. }
  2756. }
  2757. // finally, set trivial pointers
  2758. for (pn=0; pn < n_params; pn++)
  2759. {
  2760. if (OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
  2761. {
  2762. if (pn == n_params-2 && (cfunc_abiinfo&(BIF_SECONDLASTPARMST))) // second to last parameter
  2763. {
  2764. int a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis,
  2765. RETURNVALUE_FPSTACK,NULL,NULL,canHaveDenormalOutput);
  2766. if (a<0) RET_MINUS1_FAIL("coc call here 2")
  2767. parm_size+=a;
  2768. #ifdef GLUE_HAS_FXCH
  2769. need_fxch = 1;
  2770. #endif
  2771. }
  2772. 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)
  2773. {
  2774. int rvt=0, a;
  2775. int wantFpStack = func == nseel_asm_assign;
  2776. #ifdef GLUE_PREFER_NONFP_DV_ASSIGNS // x86-64, and maybe others, prefer to avoid the fp stack for a simple copy
  2777. if (wantFpStack &&
  2778. (op->parms.parms[pn]->opcodeType != OPCODETYPE_DIRECTVALUE ||
  2779. (op->parms.parms[pn]->parms.dv.directValue != 1.0 && op->parms.parms[pn]->parms.dv.directValue != 0.0)))
  2780. {
  2781. wantFpStack=-1; // cacheable but non-FP stack
  2782. }
  2783. #endif
  2784. a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis,
  2785. func == nseel_asm_bnot ? (RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL) :
  2786. (cfunc_abiinfo & BIF_LASTPARMONSTACK) ? RETURNVALUE_FPSTACK :
  2787. (cfunc_abiinfo & BIF_LASTPARM_ASBOOL) ? RETURNVALUE_BOOL :
  2788. wantFpStack < 0 ? (RETURNVALUE_CACHEABLE|RETURNVALUE_NORMAL) :
  2789. wantFpStack ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) :
  2790. RETURNVALUE_NORMAL,
  2791. &rvt, NULL,canHaveDenormalOutput);
  2792. if (a<0) RET_MINUS1_FAIL("coc call here 3")
  2793. if (func == nseel_asm_bnot && rvt == RETURNVALUE_BOOL_REVERSED)
  2794. {
  2795. // remove bnot, compileOpcodes() used fptobool_rev
  2796. #ifndef EEL_TARGET_PORTABLE
  2797. func = nseel_asm_uplus;
  2798. func_e = nseel_asm_uplus_end;
  2799. #else
  2800. func = nseel_asm_bnotnot;
  2801. func_e = nseel_asm_bnotnot_end;
  2802. #endif
  2803. rvt = RETURNVALUE_BOOL;
  2804. }
  2805. parm_size+=a;
  2806. #ifdef GLUE_HAS_FXCH
  2807. need_fxch = 0;
  2808. #endif
  2809. if (func == nseel_asm_assign)
  2810. {
  2811. if (rvt == RETURNVALUE_FPSTACK)
  2812. {
  2813. if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS))
  2814. {
  2815. func = nseel_asm_assign_fast_fromfp;
  2816. func_e = nseel_asm_assign_fast_fromfp_end;
  2817. }
  2818. else
  2819. {
  2820. func = nseel_asm_assign_fromfp;
  2821. func_e = nseel_asm_assign_fromfp_end;
  2822. }
  2823. }
  2824. else if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS))
  2825. {
  2826. // assigning a value (from a variable or other non-computer), can use a fast assign (no denormal/result checking)
  2827. func = nseel_asm_assign_fast;
  2828. func_e = nseel_asm_assign_fast_end;
  2829. }
  2830. }
  2831. }
  2832. else
  2833. {
  2834. if (bufOut_len < parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE) RET_MINUS1_FAIL("size, pxdvsz")
  2835. if (bufOut)
  2836. {
  2837. 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")
  2838. }
  2839. parm_size += GLUE_MOV_PX_DIRECTVALUE_SIZE;
  2840. }
  2841. }
  2842. }
  2843. #ifdef GLUE_HAS_FXCH
  2844. if ((cfunc_abiinfo&(BIF_SECONDLASTPARMST)) && !(cfunc_abiinfo&(BIF_LAZYPARMORDERING))&&
  2845. ((!!need_fxch)^!!(cfunc_abiinfo&BIF_REVERSEFPORDER))
  2846. )
  2847. {
  2848. // emit fxch
  2849. if (bufOut_len < sizeof(GLUE_FXCH)) RET_MINUS1_FAIL("len,fxch")
  2850. if (bufOut)
  2851. {
  2852. memcpy(bufOut+parm_size,GLUE_FXCH,sizeof(GLUE_FXCH));
  2853. }
  2854. parm_size+=sizeof(GLUE_FXCH);
  2855. }
  2856. #endif
  2857. if (!*canHaveDenormalOutput)
  2858. {
  2859. // if add_op or sub_op, and constant non-denormal input, safe to omit denormal checks
  2860. if (func == (void*)nseel_asm_add_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD)
  2861. {
  2862. func = nseel_asm_add_op_fast;
  2863. func_e = nseel_asm_add_op_fast_end;
  2864. }
  2865. else if (func == (void*)nseel_asm_sub_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD)
  2866. {
  2867. func = nseel_asm_sub_op_fast;
  2868. func_e = nseel_asm_sub_op_fast_end;
  2869. }
  2870. // or if mul/div by a fixed value of >= or <= 1.0
  2871. else if (func == (void *)nseel_asm_mul_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= 1.0)
  2872. {
  2873. func = nseel_asm_mul_op_fast;
  2874. func_e = nseel_asm_mul_op_fast_end;
  2875. }
  2876. else if (func == (void *)nseel_asm_div_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) <= 1.0)
  2877. {
  2878. func = nseel_asm_div_op_fast;
  2879. func_e = nseel_asm_div_op_fast_end;
  2880. }
  2881. }
  2882. } // not varparm
  2883. if (cfunc_abiinfo & (BIF_CLEARDENORMAL | BIF_RETURNSBOOL) ) *canHaveDenormalOutput=0;
  2884. else if (!(cfunc_abiinfo & BIF_WONTMAKEDENORMAL)) *canHaveDenormalOutput=1;
  2885. func = GLUE_realAddress(func,func_e,&func_size);
  2886. if (!func) RET_MINUS1_FAIL("failrealladdrfunc")
  2887. if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("funcsz")
  2888. if (bufOut)
  2889. {
  2890. unsigned char *p=bufOut + parm_size;
  2891. memcpy(p, func, func_size);
  2892. if (preProc) p=preProc(p,func_size,ctx);
  2893. if (repl)
  2894. {
  2895. if (repl[0]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[0]);
  2896. if (repl[1]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[1]);
  2897. if (repl[2]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[2]);
  2898. if (repl[3]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[3]);
  2899. }
  2900. }
  2901. if (restore_stack_amt)
  2902. {
  2903. int rem = restore_stack_amt;
  2904. while (rem > 0)
  2905. {
  2906. int amt = rem;
  2907. if (amt > 4096) amt=4096;
  2908. rem -= amt;
  2909. if (bufOut_len < parm_size + func_size + GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm")
  2910. if (bufOut) GLUE_MOVE_STACK(bufOut + parm_size + func_size, amt);
  2911. parm_size += GLUE_MOVE_STACK_SIZE;
  2912. }
  2913. }
  2914. if (cfunc_abiinfo&BIF_RETURNSONSTACK) *rvMode = RETURNVALUE_FPSTACK;
  2915. else if (cfunc_abiinfo&BIF_RETURNSBOOL) *rvMode=RETURNVALUE_BOOL;
  2916. return parm_size + func_size;
  2917. }
  2918. static int compileEelFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
  2919. int *rvMode, int *fpStackUse, int *canHaveDenormalOutput)
  2920. {
  2921. int func_size=0, parm_size=0;
  2922. int pn;
  2923. int last_nt_parm=-1,last_nt_parm_mode=0;
  2924. void *func_e=NULL;
  2925. int n_params;
  2926. opcodeRec *parmptrs[NSEEL_MAX_EELFUNC_PARAMETERS];
  2927. int cfp_numparams=-1;
  2928. int cfp_statesize=0;
  2929. EEL_F **cfp_ptrs=NULL;
  2930. int func_raw=0;
  2931. int do_parms;
  2932. int x;
  2933. void *func;
  2934. for (x=0; x < 3; x ++) parmptrs[x] = op->parms.parms[x];
  2935. if (op->opcodeType == OPCODETYPE_FUNCX)
  2936. {
  2937. n_params=0;
  2938. for (x=0;x<3;x++)
  2939. {
  2940. opcodeRec *prni=op->parms.parms[x];
  2941. while (prni && n_params < NSEEL_MAX_EELFUNC_PARAMETERS)
  2942. {
  2943. const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
  2944. parmptrs[n_params++] = isMP ? prni->parms.parms[0] : prni;
  2945. if (!isMP) break;
  2946. prni = prni->parms.parms[1];
  2947. }
  2948. }
  2949. }
  2950. else
  2951. {
  2952. n_params = 1 + op->opcodeType - OPCODETYPE_FUNC1;
  2953. }
  2954. *fpStackUse = 0;
  2955. func = nseel_getEELFunctionAddress(ctx, op,
  2956. &cfp_numparams,&cfp_statesize,&cfp_ptrs,
  2957. computTableSize,
  2958. &func_e, &func_raw,
  2959. !!bufOut,namespacePathToThis,rvMode,fpStackUse,canHaveDenormalOutput, parmptrs, n_params);
  2960. if (func_raw) func_size = (int) ((char*)func_e - (char*)func);
  2961. else if (func) func = GLUE_realAddress(func,func_e,&func_size);
  2962. if (!func) RET_MINUS1_FAIL("eelfuncaddr")
  2963. *fpStackUse += 1;
  2964. if (cfp_numparams>0 && n_params != cfp_numparams)
  2965. {
  2966. RET_MINUS1_FAIL("eelfuncnp")
  2967. }
  2968. // user defined function
  2969. do_parms = cfp_numparams>0 && cfp_ptrs && cfp_statesize>0;
  2970. // if function local/parameter state is zero, we need to allocate storage for it
  2971. if (cfp_statesize>0 && cfp_ptrs && !cfp_ptrs[0])
  2972. {
  2973. EEL_F *pstate = newDataBlock(sizeof(EEL_F)*cfp_statesize,8);
  2974. if (!pstate) RET_MINUS1_FAIL("eelfuncdb")
  2975. for (pn=0;pn<cfp_statesize;pn++)
  2976. {
  2977. pstate[pn]=0;
  2978. cfp_ptrs[pn] = pstate + pn;
  2979. }
  2980. }
  2981. // first process parameters that are non-trivial
  2982. for (pn=0; pn < n_params; pn++)
  2983. {
  2984. int needDenorm=0;
  2985. int lsz,sUse=0;
  2986. if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after
  2987. if (last_nt_parm >= 0 && do_parms)
  2988. {
  2989. if (last_nt_parm_mode == RETURNVALUE_FPSTACK)
  2990. {
  2991. if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK)) RET_MINUS1_FAIL("eelfunc_size popfpstacktostack")
  2992. if (bufOut) memcpy(bufOut + parm_size,GLUE_POP_FPSTACK_TOSTACK,sizeof(GLUE_POP_FPSTACK_TOSTACK));
  2993. parm_size+=sizeof(GLUE_POP_FPSTACK_TOSTACK);
  2994. }
  2995. else
  2996. {
  2997. if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1PTR_AS_VALUE)) RET_MINUS1_FAIL("eelfunc_size pushp1ptrasval")
  2998. // push
  2999. if (bufOut) memcpy(bufOut + parm_size,&GLUE_PUSH_P1PTR_AS_VALUE,sizeof(GLUE_PUSH_P1PTR_AS_VALUE));
  3000. parm_size+=sizeof(GLUE_PUSH_P1PTR_AS_VALUE);
  3001. }
  3002. }
  3003. last_nt_parm_mode=0;
  3004. lsz = compileOpcodes(ctx,parmptrs[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis,
  3005. do_parms ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) : RETURNVALUE_IGNORE,&last_nt_parm_mode,&sUse, &needDenorm);
  3006. // todo: if needDenorm, denorm convert when copying parameter
  3007. if (lsz<0) RET_MINUS1_FAIL("eelfunc, coc fail")
  3008. if (last_nt_parm_mode == RETURNVALUE_FPSTACK) sUse++;
  3009. if (sUse > *fpStackUse) *fpStackUse=sUse;
  3010. parm_size += lsz;
  3011. last_nt_parm = pn;
  3012. }
  3013. // pop non-trivial results into place
  3014. if (last_nt_parm >=0 && do_parms)
  3015. {
  3016. while (--pn >= 0)
  3017. {
  3018. if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after
  3019. if (pn == last_nt_parm)
  3020. {
  3021. if (last_nt_parm_mode == RETURNVALUE_FPSTACK)
  3022. {
  3023. // pop to memory directly
  3024. const int cpsize = GLUE_POP_FPSTACK_TO_PTR(NULL,NULL);
  3025. if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size popfpstacktoptr")
  3026. if (bufOut) GLUE_POP_FPSTACK_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
  3027. parm_size += cpsize;
  3028. }
  3029. else
  3030. {
  3031. // copy direct p1ptr to mem
  3032. const int cpsize = GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL);
  3033. if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size copyvalueatp1toptr")
  3034. if (bufOut) GLUE_COPY_VALUE_AT_P1_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
  3035. parm_size += cpsize;
  3036. }
  3037. }
  3038. else
  3039. {
  3040. const int popsize = GLUE_POP_VALUE_TO_ADDR(NULL,NULL);
  3041. if (bufOut_len < parm_size + popsize) RET_MINUS1_FAIL("eelfunc size pop value to addr")
  3042. if (bufOut) GLUE_POP_VALUE_TO_ADDR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
  3043. parm_size+=popsize;
  3044. }
  3045. }
  3046. }
  3047. // finally, set any trivial parameters
  3048. if (do_parms)
  3049. {
  3050. const int cpsize = GLUE_MOV_PX_DIRECTVALUE_SIZE + GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL);
  3051. for (pn=0; pn < n_params; pn++)
  3052. {
  3053. if (!parmptrs[pn] || !OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // set trivial values, we already set nontrivials
  3054. if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size trivial set")
  3055. if (bufOut)
  3056. {
  3057. if (generateValueToReg(ctx,parmptrs[pn],bufOut + parm_size,0,namespacePathToThis, 1)<0) RET_MINUS1_FAIL("eelfunc gvr fail")
  3058. GLUE_COPY_VALUE_AT_P1_TO_PTR(bufOut + parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE,cfp_ptrs[pn]);
  3059. }
  3060. parm_size += cpsize;
  3061. }
  3062. }
  3063. if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("eelfunc size combined")
  3064. if (bufOut) memcpy(bufOut + parm_size, func, func_size);
  3065. return parm_size + func_size;
  3066. // end of EEL function generation
  3067. }
  3068. #ifdef DUMP_OPS_DURING_COMPILE
  3069. void dumpOp(compileContext *ctx, opcodeRec *op, int start);
  3070. #endif
  3071. #ifdef EEL_DUMP_OPS
  3072. void dumpOpcodeTree(compileContext *ctx, FILE *fp, opcodeRec *op, int indent_amt)
  3073. {
  3074. const char *fname="";
  3075. fprintf(fp,"%*sOP TYPE %d", indent_amt, "",
  3076. op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING ? 10000 : // remap around OPCODETYPE_DIRECTVALUE_TEMPSTRING
  3077. op->opcodeType > OPCODETYPE_DIRECTVALUE_TEMPSTRING ? op->opcodeType - 1 :
  3078. op->opcodeType);
  3079. if ((op->opcodeType == OPCODETYPE_FUNC1 ||
  3080. op->opcodeType == OPCODETYPE_FUNC2 ||
  3081. op->opcodeType == OPCODETYPE_FUNC3 ||
  3082. op->opcodeType == OPCODETYPE_FUNCX))
  3083. {
  3084. if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
  3085. {
  3086. functionType *fn_ptr = (functionType *)op->fn;
  3087. fname = fn_ptr->name;
  3088. }
  3089. else if (op->fntype == FUNCTYPE_EELFUNC)
  3090. {
  3091. fname = op->relname;
  3092. }
  3093. if (!fname) fname ="";
  3094. }
  3095. switch (op->opcodeType)
  3096. {
  3097. case OPCODETYPE_DIRECTVALUE:
  3098. fprintf(fp," DV=%f\r\n",op->parms.dv.directValue);
  3099. break;
  3100. case OPCODETYPE_VALUE_FROM_NAMESPACENAME: // this.* or namespace.* are encoded this way
  3101. fprintf(fp," NSN=%s(%d)\r\n",op->relname?op->relname : "(null)",op->namespaceidx);
  3102. break;
  3103. case OPCODETYPE_VARPTR:
  3104. {
  3105. const char *nm = op->relname;
  3106. if (!nm || !*nm)
  3107. {
  3108. int wb;
  3109. for (wb = 0; wb < ctx->varTable_numBlocks; wb ++)
  3110. {
  3111. char **plist=ctx->varTable_Names[wb];
  3112. if (!plist) break;
  3113. if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK)
  3114. {
  3115. nm = plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]];
  3116. break;
  3117. }
  3118. }
  3119. }
  3120. fprintf(fp," VP=%s\r\n", nm?nm : "(null)");
  3121. }
  3122. break;
  3123. case OPCODETYPE_VARPTRPTR:
  3124. fprintf(fp, " VPP?\r\n");
  3125. break;
  3126. case OPCODETYPE_FUNC1:
  3127. if (op->fntype == FN_NOT)
  3128. fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_not");
  3129. else if (op->fntype == FN_NOTNOT)
  3130. fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_notnot");
  3131. else if (op->fntype == FN_MEMORY)
  3132. fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mem");
  3133. else if (op->fntype == FN_GMEMORY)
  3134. fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_gmem");
  3135. else if (op->fntype == FN_WHILE)
  3136. fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "while");
  3137. else
  3138. fprintf(fp," FUNC1 %d %s {\r\n",op->fntype, fname);
  3139. if (op->parms.parms[0])
  3140. dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
  3141. else
  3142. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3143. fprintf(fp,"%*s}\r\n", indent_amt, "");
  3144. break;
  3145. case OPCODETYPE_MOREPARAMS:
  3146. case OPCODETYPE_FUNC2:
  3147. if (op->opcodeType == OPCODETYPE_MOREPARAMS)
  3148. fprintf(fp," MOREPARAMS {\r\n");
  3149. else
  3150. {
  3151. if (op->fntype == FN_POW)
  3152. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "pow");
  3153. else if (op->fntype == FN_MOD)
  3154. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mod");
  3155. else if (op->fntype == FN_XOR)
  3156. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xor");
  3157. else if (op->fntype == FN_SHL)
  3158. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shl");
  3159. else if (op->fntype == FN_SHR)
  3160. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shr");
  3161. else if (op->fntype == FN_LT)
  3162. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_below");
  3163. else if (op->fntype == FN_GT)
  3164. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_above");
  3165. else if (op->fntype == FN_LTE)
  3166. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_beleq");
  3167. else if (op->fntype == FN_GTE)
  3168. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_aboeq");
  3169. else if (op->fntype == FN_EQ)
  3170. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal");
  3171. else if (op->fntype == FN_NE)
  3172. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq");
  3173. else if (op->fntype == FN_EQ_EXACT)
  3174. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal_exact");
  3175. else if (op->fntype == FN_NE_EXACT)
  3176. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq_exact");
  3177. else if (op->fntype == FN_LOGICAL_AND)
  3178. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_and");
  3179. else if (op->fntype == FN_LOGICAL_OR)
  3180. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_or");
  3181. else if (op->fntype == FN_ASSIGN)
  3182. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_set");
  3183. else if (op->fntype == FN_ADD_OP)
  3184. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_addop");
  3185. else if (op->fntype == FN_SUB_OP)
  3186. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_subop");
  3187. else if (op->fntype == FN_MUL_OP)
  3188. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mulop");
  3189. else if (op->fntype == FN_DIV_OP)
  3190. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_divop");
  3191. else if (op->fntype == FN_OR_OP)
  3192. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_orop");
  3193. else if (op->fntype == FN_AND_OP)
  3194. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_andop");
  3195. else if (op->fntype == FN_XOR_OP)
  3196. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xorop");
  3197. else if (op->fntype == FN_MOD_OP)
  3198. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_modop");
  3199. else if (op->fntype == FN_POW_OP)
  3200. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_powop");
  3201. else if (op->fntype == FN_LOOP)
  3202. fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "loop");
  3203. else
  3204. fprintf(fp," FUNC2 %d %s {\r\n",op->fntype, fname);
  3205. }
  3206. if (op->parms.parms[0])
  3207. dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
  3208. else
  3209. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3210. if (op->parms.parms[1])
  3211. dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2);
  3212. else
  3213. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3214. fprintf(fp,"%*s}\r\n", indent_amt, "");
  3215. break;
  3216. case OPCODETYPE_FUNCX:
  3217. case OPCODETYPE_FUNC3:
  3218. if (op->opcodeType == OPCODETYPE_FUNCX)
  3219. fprintf(fp," FUNCX %d %s {\r\n",op->fntype, fname);
  3220. else if (op->fntype == FN_IF_ELSE)
  3221. fprintf(fp," FUNC3 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_if");
  3222. else
  3223. fprintf(fp," FUNC3 %d %s {\r\n",op->fntype, fname);
  3224. if (op->parms.parms[0])
  3225. dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
  3226. else
  3227. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3228. if (op->parms.parms[1])
  3229. dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2);
  3230. else
  3231. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3232. if (op->parms.parms[2])
  3233. dumpOpcodeTree(ctx,fp,op->parms.parms[2],indent_amt+2);
  3234. else
  3235. fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
  3236. fprintf(fp,"%*s}\r\n", indent_amt, "");
  3237. break;
  3238. }
  3239. }
  3240. #endif
  3241. #ifdef GLUE_MAX_JMPSIZE
  3242. #define CHECK_SIZE_FORJMP(x,y) if ((x)<0 || (x)>=GLUE_MAX_JMPSIZE) goto y;
  3243. #define RET_MINUS1_FAIL_FALLBACK(err,j) goto j;
  3244. #else
  3245. #define CHECK_SIZE_FORJMP(x,y)
  3246. #define RET_MINUS1_FAIL_FALLBACK(err,j) RET_MINUS1_FAIL(err)
  3247. #endif
  3248. 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)
  3249. {
  3250. int rv_offset=0, denormal_force=-1;
  3251. if (!op) RET_MINUS1_FAIL("coi !op")
  3252. *fpStackUse=0;
  3253. for (;;)
  3254. {
  3255. // special case: statement delimiting means we can process the left side into place, and iteratively do the second parameter without recursing
  3256. // also we don't need to save/restore anything to the stack (which the normal 2 parameter function processing does)
  3257. if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS)
  3258. {
  3259. int fUse1;
  3260. int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL,&fUse1,NULL);
  3261. if (parm_size < 0) RET_MINUS1_FAIL("coc join fail")
  3262. op = op->parms.parms[1];
  3263. if (!op) RET_MINUS1_FAIL("join got to null")
  3264. if (fUse1>*fpStackUse) *fpStackUse=fUse1;
  3265. if (bufOut) bufOut += parm_size;
  3266. bufOut_len -= parm_size;
  3267. rv_offset += parm_size;
  3268. #ifdef DUMP_OPS_DURING_COMPILE
  3269. if (op->opcodeType != OPCODETYPE_FUNC2 || op->fntype != FN_JOIN_STATEMENTS) dumpOp(ctx,op,0);
  3270. #endif
  3271. denormal_force=-1;
  3272. }
  3273. // special case: __denormal_likely(), __denormal_unlikely()
  3274. else if (op->opcodeType == OPCODETYPE_FUNC1 && (op->fntype == FN_DENORMAL_LIKELY || op->fntype == FN_DENORMAL_UNLIKELY))
  3275. {
  3276. denormal_force = op->fntype == FN_DENORMAL_LIKELY;
  3277. op = op->parms.parms[0];
  3278. }
  3279. else
  3280. {
  3281. break;
  3282. }
  3283. }
  3284. if (denormal_force >= 0 && canHaveDenormalOutput)
  3285. {
  3286. *canHaveDenormalOutput = denormal_force;
  3287. canHaveDenormalOutput = &denormal_force; // prevent it from being changed by functions below
  3288. }
  3289. // special case: BAND/BOR
  3290. if (op->opcodeType == OPCODETYPE_FUNC2 && (op->fntype == FN_LOGICAL_AND || op->fntype == FN_LOGICAL_OR))
  3291. {
  3292. int fUse1=0;
  3293. int parm_size;
  3294. #ifdef GLUE_MAX_JMPSIZE
  3295. int parm_size_pre;
  3296. #endif
  3297. int retType=RETURNVALUE_IGNORE;
  3298. if (preferredReturnValues != RETURNVALUE_IGNORE) retType = RETURNVALUE_BOOL;
  3299. *calledRvType = retType;
  3300. parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL, &fUse1, NULL);
  3301. if (parm_size < 0) RET_MINUS1_FAIL("loop band/bor coc fail")
  3302. if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
  3303. #ifdef GLUE_MAX_JMPSIZE
  3304. parm_size_pre=parm_size;
  3305. #endif
  3306. {
  3307. int sz2, fUse2=0;
  3308. unsigned char *destbuf;
  3309. const int testsz=op->fntype == FN_LOGICAL_OR ? sizeof(GLUE_JMP_IF_P1_NZ) : sizeof(GLUE_JMP_IF_P1_Z);
  3310. if (bufOut_len < parm_size+testsz) RET_MINUS1_FAIL_FALLBACK("band/bor size fail",doNonInlinedAndOr_)
  3311. if (bufOut) memcpy(bufOut+parm_size,op->fntype == FN_LOGICAL_OR ? GLUE_JMP_IF_P1_NZ : GLUE_JMP_IF_P1_Z,testsz);
  3312. parm_size += testsz;
  3313. destbuf = bufOut + parm_size;
  3314. sz2= compileOpcodes(ctx,op->parms.parms[1],bufOut?bufOut+parm_size:NULL,bufOut_len-parm_size, computTableSize, namespacePathToThis, retType, NULL,&fUse2, NULL);
  3315. CHECK_SIZE_FORJMP(sz2,doNonInlinedAndOr_)
  3316. if (sz2<0) RET_MINUS1_FAIL("band/bor coc fail")
  3317. parm_size+=sz2;
  3318. if (bufOut) GLUE_JMP_SET_OFFSET(destbuf, (bufOut + parm_size) - destbuf);
  3319. if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
  3320. return rv_offset + parm_size;
  3321. }
  3322. #ifdef GLUE_MAX_JMPSIZE
  3323. if (0)
  3324. {
  3325. void *stub;
  3326. int stubsize;
  3327. unsigned char *newblock2, *p;
  3328. // encode as function call
  3329. doNonInlinedAndOr_:
  3330. parm_size = parm_size_pre;
  3331. if (op->fntype == FN_LOGICAL_AND)
  3332. {
  3333. stub = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&stubsize);
  3334. }
  3335. else
  3336. {
  3337. stub = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&stubsize);
  3338. }
  3339. if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("band/bor len fail")
  3340. if (bufOut)
  3341. {
  3342. int fUse2=0;
  3343. newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, retType, NULL, &fUse2, NULL);
  3344. if (!newblock2) RET_MINUS1_FAIL("band/bor ccbwr fail")
  3345. if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
  3346. p = bufOut + parm_size;
  3347. memcpy(p, stub, stubsize);
  3348. p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2);
  3349. }
  3350. return rv_offset + parm_size + stubsize;
  3351. }
  3352. #endif
  3353. }
  3354. if (op->opcodeType == OPCODETYPE_FUNC3 && op->fntype == FN_IF_ELSE) // special case: IF
  3355. {
  3356. int fUse1=0;
  3357. #ifdef GLUE_MAX_JMPSIZE
  3358. int parm_size_pre;
  3359. #endif
  3360. int use_rv = RETURNVALUE_IGNORE;
  3361. int rvMode=0;
  3362. int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED, &rvMode,&fUse1, NULL);
  3363. if (parm_size < 0) RET_MINUS1_FAIL("if coc fail")
  3364. if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
  3365. if (preferredReturnValues & RETURNVALUE_NORMAL) use_rv=RETURNVALUE_NORMAL;
  3366. else if (preferredReturnValues & RETURNVALUE_FPSTACK) use_rv=RETURNVALUE_FPSTACK;
  3367. else if (preferredReturnValues & RETURNVALUE_BOOL) use_rv=RETURNVALUE_BOOL;
  3368. *calledRvType = use_rv;
  3369. #ifdef GLUE_MAX_JMPSIZE
  3370. parm_size_pre = parm_size;
  3371. #endif
  3372. {
  3373. int csz,hasSecondHalf;
  3374. if (rvMode & RETURNVALUE_BOOL_REVERSED)
  3375. {
  3376. if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_NZ)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_)
  3377. if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_NZ,sizeof(GLUE_JMP_IF_P1_NZ));
  3378. parm_size += sizeof(GLUE_JMP_IF_P1_NZ);
  3379. }
  3380. else
  3381. {
  3382. if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_Z)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_)
  3383. if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_Z,sizeof(GLUE_JMP_IF_P1_Z));
  3384. parm_size += sizeof(GLUE_JMP_IF_P1_Z);
  3385. }
  3386. csz=compileOpcodes(ctx,op->parms.parms[1],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL,&fUse1, canHaveDenormalOutput);
  3387. if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
  3388. hasSecondHalf = preferredReturnValues || !OPCODE_IS_TRIVIAL(op->parms.parms[2]);
  3389. CHECK_SIZE_FORJMP(csz,doNonInlineIf_)
  3390. if (csz<0) RET_MINUS1_FAIL("if coc fial")
  3391. if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size, csz + (hasSecondHalf?sizeof(GLUE_JMP_NC):0));
  3392. parm_size+=csz;
  3393. if (hasSecondHalf)
  3394. {
  3395. if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_NC)) RET_MINUS1_FAIL_FALLBACK("if len fail",doNonInlineIf_)
  3396. if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_NC,sizeof(GLUE_JMP_NC));
  3397. parm_size+=sizeof(GLUE_JMP_NC);
  3398. csz=compileOpcodes(ctx,op->parms.parms[2],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL, &fUse1, canHaveDenormalOutput);
  3399. CHECK_SIZE_FORJMP(csz,doNonInlineIf_)
  3400. if (csz<0) RET_MINUS1_FAIL("if coc 2 fail")
  3401. // update jump address
  3402. if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size,csz);
  3403. parm_size+=csz;
  3404. if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
  3405. }
  3406. return rv_offset + parm_size;
  3407. }
  3408. #ifdef GLUE_MAX_JMPSIZE
  3409. if (0)
  3410. {
  3411. unsigned char *newblock2,*newblock3,*ptr;
  3412. void *stub;
  3413. int stubsize;
  3414. doNonInlineIf_:
  3415. parm_size = parm_size_pre;
  3416. stub = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&stubsize);
  3417. if (!stub || bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL(stub ? "if sz fail" : "if addr fail")
  3418. if (bufOut)
  3419. {
  3420. int fUse2=0;
  3421. newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput);
  3422. if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
  3423. newblock3 = compileCodeBlockWithRet(ctx,op->parms.parms[2],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput);
  3424. if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
  3425. if (!newblock2 || !newblock3) RET_MINUS1_FAIL("if subblock gen fail")
  3426. ptr = bufOut + parm_size;
  3427. memcpy(ptr, stub, stubsize);
  3428. ptr=EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock2);
  3429. EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock3);
  3430. }
  3431. return rv_offset + parm_size + stubsize;
  3432. }
  3433. #endif
  3434. }
  3435. {
  3436. // special case: while
  3437. if (op->opcodeType == OPCODETYPE_FUNC1 && op->fntype == FN_WHILE)
  3438. {
  3439. *calledRvType = RETURNVALUE_BOOL;
  3440. #ifndef GLUE_INLINE_LOOPS
  3441. // todo: PPC looping support when loop length is small enough
  3442. {
  3443. unsigned char *pwr=bufOut;
  3444. unsigned char *newblock2;
  3445. int stubsz;
  3446. void *stubfunc = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&stubsz);
  3447. if (!stubfunc || bufOut_len < stubsz) RET_MINUS1_FAIL(stubfunc ? "repeatwhile size fail" :"repeatwhile addr fail")
  3448. if (bufOut)
  3449. {
  3450. newblock2=compileCodeBlockWithRet(ctx,op->parms.parms[0],computTableSize,namespacePathToThis, RETURNVALUE_BOOL, NULL, fpStackUse, NULL);
  3451. if (!newblock2) RET_MINUS1_FAIL("repeatwhile ccbwr fail")
  3452. memcpy(pwr,stubfunc,stubsz);
  3453. pwr=EEL_GLUE_set_immediate(pwr,(INT_PTR)newblock2);
  3454. }
  3455. return rv_offset+stubsz;
  3456. }
  3457. #else
  3458. {
  3459. #ifndef GLUE_WHILE_END_NOJUMP
  3460. unsigned char *jzoutpt;
  3461. #endif
  3462. unsigned char *looppt;
  3463. int parm_size=0,subsz;
  3464. if (bufOut_len < parm_size + (int)(GLUE_WHILE_SETUP_SIZE + sizeof(GLUE_WHILE_BEGIN))) RET_MINUS1_FAIL("while size fail 1")
  3465. if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_SETUP,GLUE_WHILE_SETUP_SIZE);
  3466. parm_size+=GLUE_WHILE_SETUP_SIZE;
  3467. looppt = bufOut + parm_size;
  3468. if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_BEGIN,sizeof(GLUE_WHILE_BEGIN));
  3469. parm_size+=sizeof(GLUE_WHILE_BEGIN);
  3470. subsz = compileOpcodes(ctx,op->parms.parms[0],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL,fpStackUse, NULL);
  3471. if (subsz<0) RET_MINUS1_FAIL("while coc fail")
  3472. if (bufOut_len < parm_size + (int)(sizeof(GLUE_WHILE_END) + sizeof(GLUE_WHILE_CHECK_RV))) RET_MINUS1_FAIL("which size fial 2")
  3473. parm_size+=subsz;
  3474. if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_END, sizeof(GLUE_WHILE_END));
  3475. parm_size+=sizeof(GLUE_WHILE_END);
  3476. #ifndef GLUE_WHILE_END_NOJUMP
  3477. jzoutpt = bufOut + parm_size;
  3478. #endif
  3479. if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_CHECK_RV, sizeof(GLUE_WHILE_CHECK_RV));
  3480. parm_size+=sizeof(GLUE_WHILE_CHECK_RV);
  3481. if (bufOut)
  3482. {
  3483. GLUE_JMP_SET_OFFSET(bufOut + parm_size,(looppt - (bufOut+parm_size)) );
  3484. #ifndef GLUE_WHILE_END_NOJUMP
  3485. GLUE_JMP_SET_OFFSET(jzoutpt, (bufOut + parm_size) - jzoutpt);
  3486. #endif
  3487. }
  3488. return rv_offset+parm_size;
  3489. }
  3490. #endif
  3491. }
  3492. // special case: loop
  3493. if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_LOOP)
  3494. {
  3495. int fUse1;
  3496. int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_FPSTACK, NULL,&fUse1, NULL);
  3497. if (parm_size < 0) RET_MINUS1_FAIL("loop coc fail")
  3498. *calledRvType = RETURNVALUE_BOOL;
  3499. if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
  3500. #ifndef GLUE_INLINE_LOOPS
  3501. // todo: PPC looping support when loop length is small enough
  3502. {
  3503. void *stub;
  3504. int stubsize;
  3505. unsigned char *newblock2, *p;
  3506. stub = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&stubsize);
  3507. if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("loop size fail")
  3508. if (bufOut)
  3509. {
  3510. newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, RETURNVALUE_IGNORE, NULL,fpStackUse, NULL);
  3511. p = bufOut + parm_size;
  3512. memcpy(p, stub, stubsize);
  3513. p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2);
  3514. }
  3515. return rv_offset + parm_size + stubsize;
  3516. }
  3517. #else
  3518. {
  3519. int subsz;
  3520. int fUse2=0;
  3521. unsigned char *skipptr1,*loopdest;
  3522. if (bufOut_len < parm_size + (int)(sizeof(GLUE_LOOP_LOADCNT) + GLUE_LOOP_CLAMPCNT_SIZE + GLUE_LOOP_BEGIN_SIZE)) RET_MINUS1_FAIL("loop size fail")
  3523. // store, convert to int, compare against 1, if less than, skip to end
  3524. if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_LOADCNT,sizeof(GLUE_LOOP_LOADCNT));
  3525. parm_size += sizeof(GLUE_LOOP_LOADCNT);
  3526. skipptr1 = bufOut+parm_size;
  3527. // compare aginst max loop length, jump to loop start if not above it
  3528. if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_CLAMPCNT,GLUE_LOOP_CLAMPCNT_SIZE);
  3529. parm_size += GLUE_LOOP_CLAMPCNT_SIZE;
  3530. // loop code:
  3531. loopdest = bufOut + parm_size;
  3532. if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_BEGIN,GLUE_LOOP_BEGIN_SIZE);
  3533. parm_size += GLUE_LOOP_BEGIN_SIZE;
  3534. subsz = compileOpcodes(ctx,op->parms.parms[1],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL, &fUse2, NULL);
  3535. if (subsz<0) RET_MINUS1_FAIL("loop coc fail")
  3536. if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
  3537. parm_size += subsz;
  3538. if (bufOut_len < parm_size + (int)sizeof(GLUE_LOOP_END)) RET_MINUS1_FAIL("loop size fail 2")
  3539. if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_END,sizeof(GLUE_LOOP_END));
  3540. parm_size += sizeof(GLUE_LOOP_END);
  3541. if (bufOut)
  3542. {
  3543. GLUE_JMP_SET_OFFSET(bufOut + parm_size,loopdest - (bufOut+parm_size));
  3544. GLUE_JMP_SET_OFFSET(skipptr1, (bufOut+parm_size) - skipptr1);
  3545. }
  3546. return rv_offset + parm_size;
  3547. }
  3548. #endif
  3549. }
  3550. }
  3551. switch (op->opcodeType)
  3552. {
  3553. case OPCODETYPE_DIRECTVALUE:
  3554. if (preferredReturnValues == RETURNVALUE_BOOL)
  3555. {
  3556. int w = fabs(op->parms.dv.directValue) >= NSEEL_CLOSEFACTOR;
  3557. int wsz=(w?sizeof(GLUE_SET_P1_NZ):sizeof(GLUE_SET_P1_Z));
  3558. *calledRvType = RETURNVALUE_BOOL;
  3559. if (bufOut_len < wsz) RET_MINUS1_FAIL("direct bool size fail3")
  3560. if (bufOut) memcpy(bufOut,w?GLUE_SET_P1_NZ:GLUE_SET_P1_Z,wsz);
  3561. return rv_offset+wsz;
  3562. }
  3563. else if (preferredReturnValues & RETURNVALUE_FPSTACK)
  3564. {
  3565. #ifdef GLUE_HAS_FLDZ
  3566. if (op->parms.dv.directValue == 0.0)
  3567. {
  3568. *fpStackUse = 1;
  3569. *calledRvType = RETURNVALUE_FPSTACK;
  3570. if (bufOut_len < sizeof(GLUE_FLDZ)) RET_MINUS1_FAIL("direct fp fail 1")
  3571. if (bufOut) memcpy(bufOut,GLUE_FLDZ,sizeof(GLUE_FLDZ));
  3572. return rv_offset+sizeof(GLUE_FLDZ);
  3573. }
  3574. #endif
  3575. #ifdef GLUE_HAS_FLD1
  3576. if (op->parms.dv.directValue == 1.0)
  3577. {
  3578. *fpStackUse = 1;
  3579. *calledRvType = RETURNVALUE_FPSTACK;
  3580. if (bufOut_len < sizeof(GLUE_FLD1)) RET_MINUS1_FAIL("direct fp fail 1")
  3581. if (bufOut) memcpy(bufOut,GLUE_FLD1,sizeof(GLUE_FLD1));
  3582. return rv_offset+sizeof(GLUE_FLD1);
  3583. }
  3584. #endif
  3585. }
  3586. // fall through
  3587. case OPCODETYPE_DIRECTVALUE_TEMPSTRING:
  3588. case OPCODETYPE_VALUE_FROM_NAMESPACENAME:
  3589. case OPCODETYPE_VARPTR:
  3590. case OPCODETYPE_VARPTRPTR:
  3591. #ifdef GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE
  3592. if (OPCODE_IS_TRIVIAL(op))
  3593. {
  3594. if (preferredReturnValues & RETURNVALUE_FPSTACK)
  3595. {
  3596. *fpStackUse = 1;
  3597. if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE) RET_MINUS1_FAIL("direct fp fail 2")
  3598. if (bufOut)
  3599. {
  3600. if (generateValueToReg(ctx,op,bufOut,-1,namespacePathToThis, 1 /*allow caching*/)<0) RET_MINUS1_FAIL("direct fp fail gvr")
  3601. }
  3602. *calledRvType = RETURNVALUE_FPSTACK;
  3603. return rv_offset+GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE;
  3604. }
  3605. }
  3606. #endif
  3607. if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_SIZE)
  3608. {
  3609. RET_MINUS1_FAIL("direct value fail 1")
  3610. }
  3611. if (bufOut)
  3612. {
  3613. if (generateValueToReg(ctx,op,bufOut,0,namespacePathToThis,
  3614. (preferredReturnValues&(RETURNVALUE_FPSTACK|RETURNVALUE_CACHEABLE))!=0)<0)
  3615. {
  3616. RET_MINUS1_FAIL("direct value gvr fail3")
  3617. }
  3618. }
  3619. return rv_offset + GLUE_MOV_PX_DIRECTVALUE_SIZE;
  3620. case OPCODETYPE_FUNCX:
  3621. case OPCODETYPE_FUNC1:
  3622. case OPCODETYPE_FUNC2:
  3623. case OPCODETYPE_FUNC3:
  3624. if (op->fntype == FUNCTYPE_EELFUNC)
  3625. {
  3626. int a;
  3627. a = compileEelFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,canHaveDenormalOutput);
  3628. if (a<0) return a;
  3629. rv_offset += a;
  3630. }
  3631. else
  3632. {
  3633. int a;
  3634. a = compileNativeFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,preferredReturnValues,canHaveDenormalOutput);
  3635. if (a<0)return a;
  3636. rv_offset += a;
  3637. }
  3638. return rv_offset;
  3639. }
  3640. RET_MINUS1_FAIL("default opcode fail")
  3641. }
  3642. #ifdef DUMP_OPS_DURING_COMPILE
  3643. FILE *g_debugfp;
  3644. int g_debugfp_indent;
  3645. int g_debugfp_histsz=0;
  3646. void dumpOp(compileContext *ctx, opcodeRec *op, int start)
  3647. {
  3648. if (start>=0)
  3649. {
  3650. if (g_debugfp)
  3651. {
  3652. static opcodeRec **hist;
  3653. int x;
  3654. int hit=0;
  3655. if (!hist) hist = (opcodeRec**) calloc(1024,1024*sizeof(opcodeRec*));
  3656. for(x=0;x<g_debugfp_histsz;x++)
  3657. {
  3658. if (hist[x] == op) { hit=1; break; }
  3659. }
  3660. if (x ==g_debugfp_histsz && g_debugfp_histsz<1024*1024) hist[g_debugfp_histsz++] = op;
  3661. if (!start)
  3662. {
  3663. g_debugfp_indent-=2;
  3664. fprintf(g_debugfp,"%*s}(join)\n",g_debugfp_indent," ");
  3665. }
  3666. if (g_debugfp_indent>=100) *(char *)1=0;
  3667. fprintf(g_debugfp,"%*s{ %p : %d%s: ",g_debugfp_indent," ",op,op->opcodeType, hit ? " -- DUPLICATE" : "");
  3668. switch (op->opcodeType)
  3669. {
  3670. case OPCODETYPE_DIRECTVALUE:
  3671. fprintf(g_debugfp,"dv %f",op->parms.dv.directValue);
  3672. break;
  3673. case OPCODETYPE_VARPTR:
  3674. if (op->relname && op->relname[0])
  3675. {
  3676. fprintf(g_debugfp,"var %s",op->relname);
  3677. }
  3678. else
  3679. {
  3680. int wb;
  3681. for (wb = 0; wb < ctx->varTable_numBlocks; wb ++)
  3682. {
  3683. char **plist=ctx->varTable_Names[wb];
  3684. if (!plist) break;
  3685. if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK)
  3686. {
  3687. fprintf(g_debugfp,"var %s",plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]]);
  3688. break;
  3689. }
  3690. }
  3691. }
  3692. break;
  3693. case OPCODETYPE_FUNC1:
  3694. case OPCODETYPE_FUNC2:
  3695. case OPCODETYPE_FUNC3:
  3696. case OPCODETYPE_FUNCX:
  3697. if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
  3698. {
  3699. functionType *p=(functionType*)op->fn;
  3700. fprintf(g_debugfp,"func %d: %s",p->nParams&0xff,p->name);
  3701. }
  3702. else
  3703. fprintf(g_debugfp,"sf %d",op->fntype);
  3704. break;
  3705. }
  3706. fprintf(g_debugfp,"\n");
  3707. g_debugfp_indent+=2;
  3708. }
  3709. }
  3710. else
  3711. {
  3712. if (g_debugfp)
  3713. {
  3714. g_debugfp_indent-=2;
  3715. fprintf(g_debugfp,"%*s}%p\n",g_debugfp_indent," ",op);
  3716. }
  3717. }
  3718. }
  3719. #endif
  3720. int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
  3721. int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput)
  3722. {
  3723. int code_returns=RETURNVALUE_NORMAL;
  3724. int fpsu=0;
  3725. int codesz;
  3726. int denorm=0;
  3727. #ifdef DUMP_OPS_DURING_COMPILE
  3728. dumpOp(ctx,op,1);
  3729. #endif
  3730. codesz = compileOpcodesInternal(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis,&code_returns, supportedReturnValues,&fpsu,&denorm);
  3731. if (denorm && canHaveDenormalOutput) *canHaveDenormalOutput=1;
  3732. #ifdef DUMP_OPS_DURING_COMPILE
  3733. dumpOp(ctx,op,-1);
  3734. #endif
  3735. #ifdef EEL_DUMP_OPS
  3736. // dump opcode trees for verification, after optimizing
  3737. if (g_eel_dump_fp2)
  3738. {
  3739. fprintf(g_eel_dump_fp2,"-- compileOpcodes generated %d bytes of code!\r\n",codesz);
  3740. }
  3741. #endif
  3742. if (codesz < 0) return codesz;
  3743. /*
  3744. {
  3745. char buf[512];
  3746. sprintf(buf,"opcode %d %d (%s): fpu use: %d\n",op->opcodeType,op->fntype,
  3747. op->opcodeType >= OPCODETYPE_FUNC1 && op->fntype == FUNCTYPE_FUNCTIONTYPEREC ? (
  3748. ((functionType *)op->fn)->name
  3749. ) : "",
  3750. fpsu);
  3751. OutputDebugString(buf);
  3752. }
  3753. */
  3754. if (fpStackUse) *fpStackUse=fpsu;
  3755. if (bufOut) bufOut += codesz;
  3756. bufOut_len -= codesz;
  3757. if (code_returns == RETURNVALUE_BOOL && !(supportedReturnValues & RETURNVALUE_BOOL) && supportedReturnValues)
  3758. {
  3759. int stubsize;
  3760. void *stub = GLUE_realAddress(nseel_asm_booltofp,nseel_asm_booltofp_end,&stubsize);
  3761. if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"booltofp size":"booltfp addr")
  3762. if (bufOut)
  3763. {
  3764. memcpy(bufOut,stub,stubsize);
  3765. bufOut += stubsize;
  3766. }
  3767. codesz+=stubsize;
  3768. bufOut_len -= stubsize;
  3769. code_returns = RETURNVALUE_FPSTACK;
  3770. }
  3771. // default processing of code_returns to meet return value requirements
  3772. if (supportedReturnValues & code_returns)
  3773. {
  3774. if (rvType) *rvType = code_returns;
  3775. return codesz;
  3776. }
  3777. if (rvType) *rvType = RETURNVALUE_IGNORE;
  3778. if (code_returns == RETURNVALUE_NORMAL)
  3779. {
  3780. if (supportedReturnValues & (RETURNVALUE_FPSTACK|RETURNVALUE_BOOL))
  3781. {
  3782. if (bufOut_len < GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE) RET_MINUS1_FAIL("pushvalatpxtofpstack,size")
  3783. if (bufOut)
  3784. {
  3785. GLUE_PUSH_VAL_AT_PX_TO_FPSTACK(bufOut,0); // always fld qword [eax] but we might change that later
  3786. bufOut += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
  3787. }
  3788. codesz += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
  3789. bufOut_len -= GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
  3790. if (supportedReturnValues & RETURNVALUE_BOOL)
  3791. {
  3792. code_returns = RETURNVALUE_FPSTACK;
  3793. }
  3794. else
  3795. {
  3796. if (rvType) *rvType = RETURNVALUE_FPSTACK;
  3797. }
  3798. }
  3799. }
  3800. if (code_returns == RETURNVALUE_FPSTACK)
  3801. {
  3802. if (supportedReturnValues & (RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED))
  3803. {
  3804. int stubsize;
  3805. void *stub;
  3806. if (supportedReturnValues & RETURNVALUE_BOOL_REVERSED)
  3807. {
  3808. if (rvType) *rvType = RETURNVALUE_BOOL_REVERSED;
  3809. stub = GLUE_realAddress(nseel_asm_fptobool_rev,nseel_asm_fptobool_rev_end,&stubsize);
  3810. }
  3811. else
  3812. {
  3813. if (rvType) *rvType = RETURNVALUE_BOOL;
  3814. stub = GLUE_realAddress(nseel_asm_fptobool,nseel_asm_fptobool_end,&stubsize);
  3815. }
  3816. if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"fptobool size":"fptobool addr")
  3817. if (bufOut)
  3818. {
  3819. memcpy(bufOut,stub,stubsize);
  3820. bufOut += stubsize;
  3821. }
  3822. codesz+=stubsize;
  3823. bufOut_len -= stubsize;
  3824. }
  3825. else if (supportedReturnValues & RETURNVALUE_NORMAL)
  3826. {
  3827. if (computTableSize) (*computTableSize) ++;
  3828. if (bufOut_len < GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE) RET_MINUS1_FAIL("popfpstacktowtptopxsize")
  3829. // generate fp-pop to temp space
  3830. if (bufOut) GLUE_POP_FPSTACK_TO_WTP_TO_PX(bufOut,0);
  3831. codesz+=GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE;
  3832. if (rvType) *rvType = RETURNVALUE_NORMAL;
  3833. }
  3834. else
  3835. {
  3836. // toss return value that will be ignored
  3837. if (bufOut_len < GLUE_POP_FPSTACK_SIZE) RET_MINUS1_FAIL("popfpstack size")
  3838. if (bufOut) memcpy(bufOut,GLUE_POP_FPSTACK,GLUE_POP_FPSTACK_SIZE);
  3839. codesz+=GLUE_POP_FPSTACK_SIZE;
  3840. }
  3841. }
  3842. return codesz;
  3843. }
  3844. #if 0
  3845. static void movestringover(char *str, int amount)
  3846. {
  3847. char tmp[1024+8];
  3848. int l=(int)strlen(str);
  3849. l=wdl_min(1024-amount-1,l);
  3850. memcpy(tmp,str,l+1);
  3851. while (l >= 0 && tmp[l]!='\n') l--;
  3852. l++;
  3853. tmp[l]=0;//ensure we null terminate
  3854. memcpy(str+amount,tmp,l+1);
  3855. }
  3856. #endif
  3857. //------------------------------------------------------------------------------
  3858. NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs)
  3859. {
  3860. return NSEEL_code_compile_ex(_ctx,_expression,lineoffs,0);
  3861. }
  3862. typedef struct topLevelCodeSegmentRec {
  3863. struct topLevelCodeSegmentRec *_next;
  3864. void *code;
  3865. int codesz;
  3866. int tmptable_use;
  3867. } topLevelCodeSegmentRec;
  3868. NSEEL_CODEHANDLE NSEEL_code_compile_ex(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs, int compile_flags)
  3869. {
  3870. compileContext *ctx = (compileContext *)_ctx;
  3871. const char *endptr;
  3872. const char *_expression_end;
  3873. codeHandleType *handle;
  3874. topLevelCodeSegmentRec *startpts_tail=NULL;
  3875. topLevelCodeSegmentRec *startpts=NULL;
  3876. _codeHandleFunctionRec *oldCommonFunctionList;
  3877. int curtabptr_sz=0;
  3878. void *curtabptr=NULL;
  3879. int had_err=0;
  3880. if (!ctx) return 0;
  3881. ctx->directValueCache=0;
  3882. ctx->optimizeDisableFlags=0;
  3883. ctx->gotEndOfInput=0;
  3884. ctx->current_compile_flags = compile_flags;
  3885. if (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS_RESET)
  3886. {
  3887. ctx->functions_common=NULL; // reset common function list
  3888. }
  3889. else
  3890. {
  3891. // reset common compiled function code, forcing a recompile if shared
  3892. _codeHandleFunctionRec *a = ctx->functions_common;
  3893. while (a)
  3894. {
  3895. _codeHandleFunctionRec *b = a->derivedCopies;
  3896. if (a->localstorage)
  3897. {
  3898. // force local storage actual values to be reallocated if used again
  3899. memset(a->localstorage,0,sizeof(EEL_F *) * a->localstorage_size);
  3900. }
  3901. a->startptr = NULL; // force this copy to be recompiled
  3902. a->startptr_size = -1;
  3903. while (b)
  3904. {
  3905. b->startptr = NULL; // force derived copies to get recompiled
  3906. b->startptr_size = -1;
  3907. // no need to reset b->localstorage, since it points to a->localstorage
  3908. b=b->derivedCopies;
  3909. }
  3910. a=a->next;
  3911. }
  3912. }
  3913. ctx->last_error_string[0]=0;
  3914. if (!_expression || !*_expression) return 0;
  3915. _expression_end = _expression + strlen(_expression);
  3916. oldCommonFunctionList = ctx->functions_common;
  3917. ctx->isGeneratingCommonFunction=0;
  3918. ctx->isSharedFunctions = !!(compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS);
  3919. ctx->functions_local = NULL;
  3920. freeBlocks(&ctx->tmpblocks_head); // free blocks
  3921. freeBlocks(&ctx->blocks_head); // free blocks
  3922. freeBlocks(&ctx->blocks_head_data); // free blocks
  3923. memset(ctx->l_stats,0,sizeof(ctx->l_stats));
  3924. handle = (codeHandleType*)newDataBlock(sizeof(codeHandleType),8);
  3925. if (!handle)
  3926. {
  3927. return 0;
  3928. }
  3929. memset(handle,0,sizeof(codeHandleType));
  3930. ctx->l_stats[0] += (int)(_expression_end - _expression);
  3931. ctx->tmpCodeHandle = handle;
  3932. endptr=_expression;
  3933. while (*endptr)
  3934. {
  3935. int computTableTop = 0;
  3936. int startptr_size=0;
  3937. void *startptr=NULL;
  3938. opcodeRec *start_opcode=NULL;
  3939. const char *expr=endptr;
  3940. int function_numparms=0;
  3941. char is_fname[NSEEL_MAX_VARIABLE_NAMELEN+1];
  3942. is_fname[0]=0;
  3943. memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size));
  3944. memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names));
  3945. ctx->function_localTable_ValuePtrs=0;
  3946. ctx->function_usesNamespaces=0;
  3947. ctx->function_curName=NULL;
  3948. ctx->function_globalFlag=0;
  3949. ctx->errVar=0;
  3950. // single out top level segment
  3951. {
  3952. int had_something = 0, pcnt=0, pcnt2=0;
  3953. int state=0;
  3954. for (;;)
  3955. {
  3956. int l;
  3957. const char *p=nseel_simple_tokenizer(&endptr,_expression_end,&l,&state);
  3958. if (!p)
  3959. {
  3960. if (pcnt || pcnt2) ctx->gotEndOfInput|=4;
  3961. break;
  3962. }
  3963. if (*p == ';')
  3964. {
  3965. if (had_something && !pcnt && !pcnt2) break;
  3966. }
  3967. else if (*p == '/' && l > 1 && (p[1] == '/' || p[1] == '*'))
  3968. {
  3969. if (l > 19 && !strnicmp(p,"//#eel-no-optimize:",19))
  3970. ctx->optimizeDisableFlags = atoi(p+19);
  3971. }
  3972. else
  3973. {
  3974. if (!had_something)
  3975. {
  3976. expr = p;
  3977. had_something = 1;
  3978. }
  3979. if (*p == '(') pcnt++;
  3980. else if (*p == ')') { if (--pcnt<0) pcnt=0; }
  3981. else if (*p == '[') pcnt2++;
  3982. else if (*p == ']') { if (--pcnt2<0) pcnt2=0; }
  3983. }
  3984. }
  3985. if (!*expr || !had_something) break;
  3986. }
  3987. // parse
  3988. {
  3989. int tmplen,funcname_len;
  3990. const char *p = expr;
  3991. const char *tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL);
  3992. const char *funcname = nseel_simple_tokenizer(&p,endptr,&funcname_len,NULL);
  3993. if (tok1 && funcname && tmplen == 8 && !strnicmp(tok1,"function",8) && (isalpha(funcname[0]) || funcname[0] == '_'))
  3994. {
  3995. int had_parms_locals=0;
  3996. if (funcname_len > sizeof(is_fname)-1) funcname_len=sizeof(is_fname)-1;
  3997. memcpy(is_fname, funcname, funcname_len);
  3998. is_fname[funcname_len]=0;
  3999. ctx->function_curName = is_fname; // only assigned for the duration of the loop, cleared later //-V507
  4000. while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
  4001. {
  4002. int is_parms = 0, localTableContext = 0;
  4003. int maxcnt=0;
  4004. const char *sp_save;
  4005. if (tok1[0] == '(')
  4006. {
  4007. if (had_parms_locals)
  4008. {
  4009. expr = p-1; // begin compilation at this code!
  4010. break;
  4011. }
  4012. is_parms = 1;
  4013. }
  4014. else
  4015. {
  4016. if (tmplen == 5 && !strnicmp(tok1,"local",tmplen)) localTableContext=0;
  4017. else if (tmplen == 6 && !strnicmp(tok1,"static",tmplen)) localTableContext=0;
  4018. else if (tmplen == 8 && !strnicmp(tok1,"instance",tmplen)) localTableContext=1;
  4019. else if ((tmplen == 7 && !strnicmp(tok1,"globals",tmplen)) ||
  4020. (tmplen == 6 && !strnicmp(tok1,"global",tmplen)))
  4021. {
  4022. ctx->function_globalFlag = 1;
  4023. localTableContext=2;
  4024. }
  4025. else break; // unknown token!
  4026. tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL);
  4027. if (!tok1 || tok1[0] != '(') break;
  4028. }
  4029. had_parms_locals = 1;
  4030. sp_save=p;
  4031. while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
  4032. {
  4033. if (tok1[0] == ')') break;
  4034. if (*tok1 == '#' && localTableContext!=1 && localTableContext!=2)
  4035. {
  4036. ctx->errVar = (int) (tok1 - _expression);
  4037. lstrcpyn_safe(ctx->last_error_string,"#string can only be in instance() or globals()",sizeof(ctx->last_error_string));
  4038. goto had_error;
  4039. }
  4040. if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#')
  4041. {
  4042. maxcnt++;
  4043. if (p < endptr && *p == '*')
  4044. {
  4045. if (!is_parms && localTableContext!=2)
  4046. {
  4047. ctx->errVar = (int) (p - _expression);
  4048. lstrcpyn_safe(ctx->last_error_string,"namespace* can only be used in parameters or globals()",sizeof(ctx->last_error_string));
  4049. goto had_error;
  4050. }
  4051. p++;
  4052. }
  4053. }
  4054. else if (*tok1 != ',')
  4055. {
  4056. ctx->errVar = (int)(tok1 - _expression);
  4057. lstrcpyn_safe(ctx->last_error_string,"unknown character in function parameters",sizeof(ctx->last_error_string));
  4058. goto had_error;
  4059. }
  4060. }
  4061. if (tok1 && maxcnt > 0)
  4062. {
  4063. char **ot = ctx->function_localTable_Names[localTableContext];
  4064. const int osz = ctx->function_localTable_Size[localTableContext];
  4065. maxcnt += osz;
  4066. ctx->function_localTable_Names[localTableContext] = (char **)newTmpBlock(ctx,sizeof(char *) * maxcnt);
  4067. if (ctx->function_localTable_Names[localTableContext])
  4068. {
  4069. int i=osz;
  4070. if (osz && ot) memcpy(ctx->function_localTable_Names[localTableContext],ot,sizeof(char *) * osz);
  4071. p=sp_save;
  4072. while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
  4073. {
  4074. if (tok1[0] == ')') break;
  4075. if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#')
  4076. {
  4077. char *newstr;
  4078. int l = tmplen;
  4079. if (*p == '*') // xyz* for namespace
  4080. {
  4081. p++;
  4082. l++;
  4083. }
  4084. if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN;
  4085. newstr = newTmpBlock(ctx,l+1);
  4086. if (newstr)
  4087. {
  4088. memcpy(newstr,tok1,l);
  4089. newstr[l]=0;
  4090. ctx->function_localTable_Names[localTableContext][i++] = newstr;
  4091. }
  4092. }
  4093. }
  4094. ctx->function_localTable_Size[localTableContext]=i;
  4095. if (is_parms) function_numparms = i;
  4096. }
  4097. }
  4098. }
  4099. }
  4100. }
  4101. if (ctx->function_localTable_Size[0]>0)
  4102. {
  4103. ctx->function_localTable_ValuePtrs =
  4104. ctx->isSharedFunctions ? newDataBlock(ctx->function_localTable_Size[0] * sizeof(EEL_F *),8) :
  4105. newTmpBlock(ctx,ctx->function_localTable_Size[0] * sizeof(EEL_F *));
  4106. if (!ctx->function_localTable_ValuePtrs)
  4107. {
  4108. ctx->function_localTable_Size[0]=0;
  4109. function_numparms=0;
  4110. }
  4111. else
  4112. {
  4113. memset(ctx->function_localTable_ValuePtrs,0,sizeof(EEL_F *) * ctx->function_localTable_Size[0]); // force values to be allocated
  4114. }
  4115. }
  4116. {
  4117. int nseelparse(compileContext* context);
  4118. void nseelrestart (void *input_file ,void *yyscanner );
  4119. ctx->rdbuf_start = _expression;
  4120. #ifdef NSEEL_SUPER_MINIMAL_LEXER
  4121. ctx->rdbuf = expr;
  4122. ctx->rdbuf_end = endptr;
  4123. if (!nseelparse(ctx) && !ctx->errVar)
  4124. {
  4125. start_opcode = ctx->result;
  4126. }
  4127. #else
  4128. nseelrestart(NULL,ctx->scanner);
  4129. ctx->rdbuf = expr;
  4130. ctx->rdbuf_end = endptr;
  4131. if (!nseelparse(ctx) && !ctx->errVar)
  4132. {
  4133. start_opcode = ctx->result;
  4134. }
  4135. if (ctx->errVar)
  4136. {
  4137. const char *p=expr;
  4138. ctx->errVar += expr-_expression;
  4139. }
  4140. #endif
  4141. ctx->rdbuf = NULL;
  4142. }
  4143. if (start_opcode)
  4144. {
  4145. int rvMode=0, fUse=0;
  4146. #ifdef LOG_OPT
  4147. char buf[512];
  4148. int sd=0;
  4149. 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);
  4150. #ifdef _WIN32
  4151. OutputDebugString(buf);
  4152. #else
  4153. printf("%s\n",buf);
  4154. #endif
  4155. #endif
  4156. #ifdef EEL_DUMP_OPS
  4157. // dump opcode trees for verification, before optimizing
  4158. if (g_eel_dump_fp)
  4159. {
  4160. fprintf(g_eel_dump_fp,"-- opcode chunk --\r\n");
  4161. dumpOpcodeTree(ctx,g_eel_dump_fp,start_opcode,2);
  4162. }
  4163. #endif
  4164. if (!(ctx->optimizeDisableFlags&OPTFLAG_NO_OPTIMIZE)) optimizeOpcodes(ctx,start_opcode,is_fname[0] ? 1 : 0);
  4165. #ifdef LOG_OPT
  4166. 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);
  4167. #ifdef _WIN32
  4168. OutputDebugString(buf);
  4169. #else
  4170. printf("%s\n",buf);
  4171. #endif
  4172. #endif
  4173. #ifdef EEL_DUMP_OPS
  4174. // dump opcode trees for verification, after optimizing
  4175. if (g_eel_dump_fp2)
  4176. {
  4177. fprintf(g_eel_dump_fp2,"-- POST-OPTIMIZED opcode chunk --\r\n");
  4178. dumpOpcodeTree(ctx,g_eel_dump_fp2,start_opcode,2);
  4179. }
  4180. #endif
  4181. if (is_fname[0])
  4182. {
  4183. _codeHandleFunctionRec *fr = ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) :
  4184. newTmpBlock(ctx,sizeof(_codeHandleFunctionRec));
  4185. if (fr)
  4186. {
  4187. memset(fr,0,sizeof(_codeHandleFunctionRec));
  4188. fr->startptr_size = -1;
  4189. fr->opcodes = start_opcode;
  4190. if (ctx->function_localTable_Size[0] > 0 && ctx->function_localTable_ValuePtrs)
  4191. {
  4192. if (ctx->function_localTable_Names[0])
  4193. {
  4194. int i;
  4195. for(i=0;i<function_numparms;i++)
  4196. {
  4197. const char *nptr = ctx->function_localTable_Names[0][i];
  4198. if (nptr && *nptr && nptr[strlen(nptr)-1] == '*')
  4199. {
  4200. fr->parameterAsNamespaceMask |= ((unsigned int)1)<<i;
  4201. }
  4202. }
  4203. }
  4204. fr->num_params=function_numparms;
  4205. fr->localstorage = ctx->function_localTable_ValuePtrs;
  4206. fr->localstorage_size = ctx->function_localTable_Size[0];
  4207. }
  4208. fr->usesNamespaces = ctx->function_usesNamespaces;
  4209. fr->isCommonFunction = ctx->isSharedFunctions;
  4210. lstrcpyn_safe(fr->fname,is_fname,sizeof(fr->fname));
  4211. if (ctx->isSharedFunctions)
  4212. {
  4213. fr->next = ctx->functions_common;
  4214. ctx->functions_common = fr;
  4215. }
  4216. else
  4217. {
  4218. fr->next = ctx->functions_local;
  4219. ctx->functions_local = fr;
  4220. }
  4221. }
  4222. continue;
  4223. }
  4224. #ifdef DUMP_OPS_DURING_COMPILE
  4225. g_debugfp_indent=0;
  4226. g_debugfp_histsz=0;
  4227. g_debugfp = fopen("C:/temp/foo.txt","w");
  4228. #endif
  4229. startptr_size = compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL, NULL,
  4230. 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
  4231. // if a function, allow the code to decide how return values are generated
  4232. #ifdef DUMP_OPS_DURING_COMPILE
  4233. if (g_debugfp) fclose(g_debugfp);
  4234. g_debugfp=0;
  4235. #endif
  4236. if (!startptr_size) continue; // optimized away
  4237. if (startptr_size>0)
  4238. {
  4239. startptr = newTmpBlock(ctx,startptr_size);
  4240. if (startptr)
  4241. {
  4242. startptr_size=compileOpcodes(ctx,start_opcode,(unsigned char*)startptr,startptr_size,&computTableTop, NULL, RETURNVALUE_IGNORE, NULL,NULL, NULL);
  4243. if (startptr_size<=0) startptr = NULL;
  4244. }
  4245. }
  4246. }
  4247. if (!startptr)
  4248. {
  4249. had_error:
  4250. #ifdef NSEEL_EEL1_COMPAT_MODE
  4251. continue;
  4252. #else
  4253. //if (!ctx->last_error_string[0])
  4254. {
  4255. int byteoffs = ctx->errVar;
  4256. int linenumber;
  4257. char cur_err[sizeof(ctx->last_error_string)];
  4258. lstrcpyn_safe(cur_err,ctx->last_error_string,sizeof(cur_err));
  4259. if (cur_err[0]) lstrcatn(cur_err,": ",sizeof(cur_err));
  4260. else lstrcpyn_safe(cur_err,"syntax error: ",sizeof(cur_err));
  4261. if (_expression + byteoffs >= _expression_end)
  4262. {
  4263. if (ctx->gotEndOfInput&4) byteoffs = (int)(expr-_expression);
  4264. else byteoffs=(int)(_expression_end-_expression);
  4265. }
  4266. if (byteoffs < 0) byteoffs=0;
  4267. linenumber=findLineNumber(_expression,byteoffs)+1;
  4268. if (ctx->gotEndOfInput&4)
  4269. {
  4270. snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %smissing ) or ]",linenumber+lineoffs,cur_err);
  4271. }
  4272. else
  4273. {
  4274. const char *p = _expression + byteoffs;
  4275. int x=0, right_amt_nospace=0, left_amt_nospace=0;
  4276. while (x < 32 && p-x > _expression && p[-x] != '\r' && p[-x] != '\n')
  4277. {
  4278. if (!isspace(p[-x])) left_amt_nospace=x;
  4279. x++;
  4280. }
  4281. x=0;
  4282. while (x < 60 && p[x] && p[x] != '\r' && p[x] != '\n')
  4283. {
  4284. if (!isspace(p[x])) right_amt_nospace=x;
  4285. x++;
  4286. }
  4287. if (right_amt_nospace<1) right_amt_nospace=1;
  4288. // display left_amt >>>> right_amt_nospace
  4289. if (left_amt_nospace > 0)
  4290. snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s <!> %.*s'",linenumber+lineoffs,cur_err,
  4291. left_amt_nospace,p-left_amt_nospace,
  4292. right_amt_nospace,p);
  4293. else
  4294. snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s'",linenumber+lineoffs,cur_err,right_amt_nospace,p);
  4295. }
  4296. }
  4297. startpts=NULL;
  4298. startpts_tail=NULL;
  4299. had_err=1;
  4300. break;
  4301. #endif
  4302. }
  4303. if (!is_fname[0]) // redundant check (if is_fname[0] is set and we succeeded, it should continue)
  4304. // but we'll be on the safe side
  4305. {
  4306. topLevelCodeSegmentRec *p = newTmpBlock(ctx,sizeof(topLevelCodeSegmentRec));
  4307. p->_next=0;
  4308. p->code = startptr;
  4309. p->codesz = startptr_size;
  4310. p->tmptable_use = computTableTop;
  4311. if (!startpts_tail) startpts_tail=startpts=p;
  4312. else
  4313. {
  4314. startpts_tail->_next=p;
  4315. startpts_tail=p;
  4316. }
  4317. if (curtabptr_sz < computTableTop)
  4318. {
  4319. curtabptr_sz=computTableTop;
  4320. }
  4321. }
  4322. }
  4323. memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size));
  4324. memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names));
  4325. ctx->function_localTable_ValuePtrs=0;
  4326. ctx->function_usesNamespaces=0;
  4327. ctx->function_curName=NULL;
  4328. ctx->function_globalFlag=0;
  4329. ctx->tmpCodeHandle = NULL;
  4330. if (handle->want_stack)
  4331. {
  4332. if (!handle->stack) startpts=NULL;
  4333. }
  4334. if (startpts)
  4335. {
  4336. curtabptr_sz += 2; // many functions use the worktable for temporary storage of up to 2 EEL_F's
  4337. handle->workTable_size = curtabptr_sz;
  4338. handle->workTable = curtabptr = newDataBlock((curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F),32);
  4339. #ifdef EEL_VALIDATE_WORKTABLE_USE
  4340. if (curtabptr) memset(curtabptr,0x3a,(curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F));
  4341. #endif
  4342. if (!curtabptr) startpts=NULL;
  4343. }
  4344. if (startpts || (!had_err && (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS)))
  4345. {
  4346. unsigned char *writeptr;
  4347. topLevelCodeSegmentRec *p=startpts;
  4348. int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :)
  4349. int wtpos=0;
  4350. // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item as necessary
  4351. while (p)
  4352. {
  4353. if (wtpos <= 0)
  4354. {
  4355. wtpos=MIN_COMPUTABLE_SIZE;
  4356. size += GLUE_RESET_WTP(NULL,0);
  4357. }
  4358. size+=p->codesz;
  4359. wtpos -= p->tmptable_use;
  4360. p=p->_next;
  4361. }
  4362. handle->code = newCodeBlock(size,32);
  4363. if (handle->code)
  4364. {
  4365. writeptr=(unsigned char *)handle->code;
  4366. #if GLUE_FUNC_ENTER_SIZE > 0
  4367. memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE);
  4368. writeptr += GLUE_FUNC_ENTER_SIZE;
  4369. #endif
  4370. p=startpts;
  4371. wtpos=0;
  4372. while (p)
  4373. {
  4374. if (wtpos <= 0)
  4375. {
  4376. wtpos=MIN_COMPUTABLE_SIZE;
  4377. writeptr+=GLUE_RESET_WTP(writeptr,curtabptr);
  4378. }
  4379. memcpy(writeptr,(char*)p->code,p->codesz);
  4380. writeptr += p->codesz;
  4381. wtpos -= p->tmptable_use;
  4382. p=p->_next;
  4383. }
  4384. #if GLUE_FUNC_LEAVE_SIZE > 0
  4385. memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE);
  4386. writeptr += GLUE_FUNC_LEAVE_SIZE;
  4387. #endif
  4388. memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET);
  4389. ctx->l_stats[1]=size;
  4390. handle->code_size = (int) (writeptr - (unsigned char *)handle->code);
  4391. #if defined(__arm__) || defined(__aarch64__)
  4392. __clear_cache(handle->code,writeptr);
  4393. #endif
  4394. }
  4395. handle->blocks = ctx->blocks_head;
  4396. handle->blocks_data = ctx->blocks_head_data;
  4397. ctx->blocks_head=0;
  4398. ctx->blocks_head_data=0;
  4399. }
  4400. else
  4401. {
  4402. // failed compiling, or failed calloc()
  4403. handle=NULL; // return NULL (after resetting blocks_head)
  4404. }
  4405. ctx->directValueCache=0;
  4406. ctx->functions_local = NULL;
  4407. ctx->isGeneratingCommonFunction=0;
  4408. ctx->isSharedFunctions=0;
  4409. freeBlocks(&ctx->tmpblocks_head); // free blocks
  4410. freeBlocks(&ctx->blocks_head); // free blocks of code (will be nonzero only on error)
  4411. freeBlocks(&ctx->blocks_head_data); // free blocks of data (will be nonzero only on error)
  4412. if (handle)
  4413. {
  4414. handle->compile_flags = compile_flags;
  4415. handle->ramPtr = ctx->ram_state.blocks;
  4416. memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
  4417. nseel_evallib_stats[0]+=ctx->l_stats[0];
  4418. nseel_evallib_stats[1]+=ctx->l_stats[1];
  4419. nseel_evallib_stats[2]+=ctx->l_stats[2];
  4420. nseel_evallib_stats[3]+=ctx->l_stats[3];
  4421. nseel_evallib_stats[4]++;
  4422. }
  4423. else
  4424. {
  4425. ctx->functions_common = oldCommonFunctionList; // failed compiling, remove any added common functions from the list
  4426. // remove any derived copies of functions due to error, since we may have added some that have been freed
  4427. while (oldCommonFunctionList)
  4428. {
  4429. oldCommonFunctionList->derivedCopies=NULL;
  4430. oldCommonFunctionList=oldCommonFunctionList->next;
  4431. }
  4432. }
  4433. memset(ctx->l_stats,0,sizeof(ctx->l_stats));
  4434. return (NSEEL_CODEHANDLE)handle;
  4435. }
  4436. //------------------------------------------------------------------------------
  4437. void NSEEL_code_execute(NSEEL_CODEHANDLE code)
  4438. {
  4439. #ifndef GLUE_TABPTR_IGNORED
  4440. INT_PTR tabptr;
  4441. #endif
  4442. INT_PTR codeptr;
  4443. codeHandleType *h = (codeHandleType *)code;
  4444. if (!h || !h->code) return;
  4445. codeptr = (INT_PTR) h->code;
  4446. #if 0
  4447. {
  4448. unsigned int *p=(unsigned int *)codeptr;
  4449. while (*p != GLUE_RET[0])
  4450. {
  4451. printf("instr:%04X:%04X\n",*p>>16,*p&0xffff);
  4452. p++;
  4453. }
  4454. }
  4455. #endif
  4456. #ifndef GLUE_TABPTR_IGNORED
  4457. tabptr=(INT_PTR)h->workTable;
  4458. #endif
  4459. //printf("calling code!\n");
  4460. GLUE_CALL_CODE(tabptr,codeptr,(INT_PTR)h->ramPtr);
  4461. }
  4462. int NSEEL_code_geterror_flag(NSEEL_VMCTX ctx)
  4463. {
  4464. compileContext *c=(compileContext *)ctx;
  4465. if (c) return (c->gotEndOfInput ? 1 : 0);
  4466. return 0;
  4467. }
  4468. char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
  4469. {
  4470. compileContext *c=(compileContext *)ctx;
  4471. if (ctx && c->last_error_string[0]) return c->last_error_string;
  4472. return 0;
  4473. }
  4474. //------------------------------------------------------------------------------
  4475. void NSEEL_code_free(NSEEL_CODEHANDLE code)
  4476. {
  4477. codeHandleType *h = (codeHandleType *)code;
  4478. if (h != NULL)
  4479. {
  4480. #ifdef EEL_VALIDATE_WORKTABLE_USE
  4481. if (h->workTable)
  4482. {
  4483. char *p = ((char*)h->workTable) + h->workTable_size*sizeof(EEL_F);
  4484. int x;
  4485. for(x=COMPUTABLE_EXTRA_SPACE*sizeof(EEL_F) - 1;x >= 0; x --)
  4486. if (p[x] != 0x3a)
  4487. {
  4488. char buf[512];
  4489. 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))));
  4490. #ifdef _WIN32
  4491. OutputDebugString(buf);
  4492. #else
  4493. printf("%s",buf);
  4494. #endif
  4495. break;
  4496. }
  4497. }
  4498. #endif
  4499. nseel_evallib_stats[0]-=h->code_stats[0];
  4500. nseel_evallib_stats[1]-=h->code_stats[1];
  4501. nseel_evallib_stats[2]-=h->code_stats[2];
  4502. nseel_evallib_stats[3]-=h->code_stats[3];
  4503. nseel_evallib_stats[4]--;
  4504. #if defined(__ppc__) && defined(__APPLE__)
  4505. {
  4506. FILE *fp = fopen("/var/db/receipts/com.apple.pkg.Rosetta.plist","r");
  4507. if (fp)
  4508. {
  4509. fclose(fp);
  4510. // on PPC, but rosetta installed, do not free h->blocks, as rosetta won't detect changes to these pages
  4511. }
  4512. else
  4513. {
  4514. freeBlocks(&h->blocks);
  4515. }
  4516. }
  4517. #else
  4518. freeBlocks(&h->blocks);
  4519. #endif
  4520. freeBlocks(&h->blocks_data);
  4521. }
  4522. }
  4523. //------------------------------------------------------------------------------
  4524. NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
  4525. {
  4526. compileContext *ctx=calloc(1,sizeof(compileContext));
  4527. #ifdef NSEEL_SUPER_MINIMAL_LEXER
  4528. if (ctx) ctx->scanner = ctx;
  4529. #else
  4530. if (ctx)
  4531. {
  4532. int nseellex_init(void ** ptr_yy_globals);
  4533. void nseelset_extra(void *user_defined , void *yyscanner);
  4534. if (nseellex_init(&ctx->scanner))
  4535. {
  4536. free(ctx);
  4537. return NULL;
  4538. }
  4539. nseelset_extra(ctx,ctx->scanner);
  4540. }
  4541. #endif
  4542. if (ctx)
  4543. {
  4544. ctx->ram_state.maxblocks = NSEEL_RAM_BLOCKS_DEFAULTMAX;
  4545. ctx->ram_state.closefact = NSEEL_CLOSEFACTOR;
  4546. }
  4547. return ctx;
  4548. }
  4549. int NSEEL_VM_setramsize(NSEEL_VMCTX _ctx, int maxent)
  4550. {
  4551. compileContext *ctx = (compileContext *)_ctx;
  4552. if (!ctx) return 0;
  4553. if (maxent > 0)
  4554. {
  4555. maxent = (maxent + NSEEL_RAM_ITEMSPERBLOCK - 1)/NSEEL_RAM_ITEMSPERBLOCK;
  4556. if (maxent > NSEEL_RAM_BLOCKS) maxent = NSEEL_RAM_BLOCKS;
  4557. ctx->ram_state.maxblocks = maxent;
  4558. }
  4559. return ctx->ram_state.maxblocks * NSEEL_RAM_ITEMSPERBLOCK;
  4560. }
  4561. void NSEEL_VM_SetFunctionValidator(NSEEL_VMCTX _ctx, const char * (*validateFunc)(const char *fn_name, void *user), void *user)
  4562. {
  4563. if (_ctx)
  4564. {
  4565. compileContext *ctx = (compileContext *)_ctx;
  4566. ctx->func_check = validateFunc;
  4567. ctx->func_check_user = user;
  4568. }
  4569. }
  4570. void NSEEL_VM_SetFunctionTable(NSEEL_VMCTX _ctx, eel_function_table *tab)
  4571. {
  4572. if (_ctx)
  4573. {
  4574. compileContext *ctx = (compileContext *)_ctx;
  4575. ctx->registered_func_tab = tab;
  4576. }
  4577. }
  4578. void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well
  4579. {
  4580. if (_ctx)
  4581. {
  4582. compileContext *ctx=(compileContext *)_ctx;
  4583. EEL_GROWBUF_RESIZE(&ctx->varNameList,-1);
  4584. NSEEL_VM_freeRAM(_ctx);
  4585. freeBlocks(&ctx->pblocks);
  4586. // these should be 0 normally but just in case
  4587. freeBlocks(&ctx->tmpblocks_head); // free blocks
  4588. freeBlocks(&ctx->blocks_head); // free blocks
  4589. freeBlocks(&ctx->blocks_head_data); // free blocks
  4590. #ifndef NSEEL_SUPER_MINIMAL_LEXER
  4591. if (ctx->scanner)
  4592. {
  4593. int nseellex_destroy(void *yyscanner);
  4594. nseellex_destroy(ctx->scanner);
  4595. }
  4596. #endif
  4597. ctx->scanner=0;
  4598. if (ctx->has_used_global_vars)
  4599. {
  4600. nseel_globalVarItem *p = NULL;
  4601. NSEEL_HOSTSTUB_EnterMutex();
  4602. if (--nseel_vms_referencing_globallist_cnt == 0)
  4603. {
  4604. // clear and free globals
  4605. p = nseel_globalreg_list;
  4606. nseel_globalreg_list=0;
  4607. }
  4608. NSEEL_HOSTSTUB_LeaveMutex();
  4609. while (p)
  4610. {
  4611. nseel_globalVarItem *op = p;
  4612. p=p->_next;
  4613. free(op);
  4614. }
  4615. }
  4616. free(ctx);
  4617. }
  4618. }
  4619. int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
  4620. {
  4621. codeHandleType *h = (codeHandleType *)code;
  4622. if (h)
  4623. {
  4624. return h->code_stats;
  4625. }
  4626. return 0;
  4627. }
  4628. void NSEEL_VM_SetStringFunc(NSEEL_VMCTX ctx,
  4629. EEL_F (*onString)(void *caller_this, struct eelStringSegmentRec *list),
  4630. EEL_F (*onNamedString)(void *caller_this, const char *name))
  4631. {
  4632. if (ctx)
  4633. {
  4634. compileContext *c=(compileContext*)ctx;
  4635. c->onString = onString;
  4636. c->onNamedString = onNamedString;
  4637. }
  4638. }
  4639. void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr)
  4640. {
  4641. if (ctx)
  4642. {
  4643. compileContext *c=(compileContext*)ctx;
  4644. c->caller_this=thisptr;
  4645. }
  4646. }
  4647. void *NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx)
  4648. {
  4649. if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->ram_state.blocks);
  4650. return data;
  4651. }
  4652. void *NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx)
  4653. {
  4654. if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->caller_this);
  4655. return data;
  4656. }
  4657. static int vartable_lowerbound(compileContext *ctx, const char *name, int *ismatch)
  4658. {
  4659. int a = 0, c = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
  4660. varNameRec **list = EEL_GROWBUF_GET(&ctx->varNameList);
  4661. while (a != c)
  4662. {
  4663. const int b = (a+c)/2;
  4664. const int cmp = strnicmp(name,list[b]->str,NSEEL_MAX_VARIABLE_NAMELEN);
  4665. if (cmp > 0) a = b+1;
  4666. else if (cmp < 0) c = b;
  4667. else
  4668. {
  4669. *ismatch = 1;
  4670. return b;
  4671. }
  4672. }
  4673. *ismatch = 0;
  4674. return a;
  4675. }
  4676. static void vartable_cull_list(compileContext *ctx, int refcnt_chk)
  4677. {
  4678. const int ni = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
  4679. int i = ni, ndel = 0;
  4680. varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList), **wr=rd;
  4681. while (i--)
  4682. {
  4683. varNameRec *v = rd[0];
  4684. if ((!refcnt_chk || !v->refcnt) && !v->isreg)
  4685. {
  4686. ndel++;
  4687. }
  4688. else
  4689. {
  4690. if (wr != rd) *wr = *rd;
  4691. wr++;
  4692. }
  4693. rd++;
  4694. }
  4695. if (ndel) EEL_GROWBUF_RESIZE(&ctx->varNameList,ni - ndel);
  4696. }
  4697. void NSEEL_VM_remove_unused_vars(NSEEL_VMCTX _ctx)
  4698. {
  4699. compileContext *ctx = (compileContext *)_ctx;
  4700. if (ctx) vartable_cull_list(ctx,1);
  4701. }
  4702. void NSEEL_VM_remove_all_nonreg_vars(NSEEL_VMCTX _ctx)
  4703. {
  4704. compileContext *ctx = (compileContext *)_ctx;
  4705. if (ctx) vartable_cull_list(ctx,0);
  4706. }
  4707. void NSEEL_VM_clear_var_refcnts(NSEEL_VMCTX _ctx)
  4708. {
  4709. compileContext *ctx = (compileContext *)_ctx;
  4710. if (ctx)
  4711. {
  4712. int i = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
  4713. varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList);
  4714. while (i--)
  4715. {
  4716. rd[0]->refcnt=0;
  4717. rd++;
  4718. }
  4719. }
  4720. }
  4721. #ifdef NSEEL_EEL1_COMPAT_MODE
  4722. static EEL_F __nseel_global_regs[100];
  4723. double *NSEEL_getglobalregs() { return __nseel_global_regs; }
  4724. #endif
  4725. EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent)
  4726. {
  4727. nseel_globalVarItem *p;
  4728. #ifdef NSEEL_EEL1_COMPAT_MODE
  4729. if (!strnicmp(gv,"reg",3) && gv[3]>='0' && gv[3] <= '9' && gv[4] >= '0' && gv[4] <= '9' && !gv[5])
  4730. {
  4731. return __nseel_global_regs + atoi(gv+3);
  4732. }
  4733. #endif
  4734. NSEEL_HOSTSTUB_EnterMutex();
  4735. if (!ctx->has_used_global_vars)
  4736. {
  4737. ctx->has_used_global_vars++;
  4738. nseel_vms_referencing_globallist_cnt++;
  4739. }
  4740. p = nseel_globalreg_list;
  4741. while (p)
  4742. {
  4743. if (!stricmp(p->name,gv)) break;
  4744. p=p->_next;
  4745. }
  4746. if (!p && addIfNotPresent)
  4747. {
  4748. size_t gvl = strlen(gv);
  4749. p = (nseel_globalVarItem*)malloc(sizeof(nseel_globalVarItem) + gvl);
  4750. if (p)
  4751. {
  4752. p->data=0.0;
  4753. strcpy(p->name,gv);
  4754. p->_next = nseel_globalreg_list;
  4755. nseel_globalreg_list=p;
  4756. }
  4757. }
  4758. NSEEL_HOSTSTUB_LeaveMutex();
  4759. return p ? &p->data : NULL;
  4760. }
  4761. EEL_F *nseel_int_register_var(compileContext *ctx, const char *name, int isReg, const char **namePtrOut)
  4762. {
  4763. int slot, match;
  4764. if (isReg == 0 && ctx->getVariable)
  4765. {
  4766. EEL_F *ret = ctx->getVariable(ctx->getVariable_userctx, name);
  4767. if (ret) return ret;
  4768. }
  4769. if (!strnicmp(name,"_global.",8) && name[8])
  4770. {
  4771. EEL_F *a=get_global_var(ctx,name+8,isReg >= 0);
  4772. if (a) return a;
  4773. }
  4774. slot = vartable_lowerbound(ctx,name, &match);
  4775. if (match)
  4776. {
  4777. varNameRec *v = EEL_GROWBUF_GET(&ctx->varNameList)[slot];
  4778. if (isReg >= 0)
  4779. {
  4780. v->refcnt++;
  4781. if (isReg) v->isreg=isReg;
  4782. if (namePtrOut) *namePtrOut = v->str;
  4783. }
  4784. return v->value;
  4785. }
  4786. if (isReg < 0) return NULL;
  4787. if (ctx->varValueStore_left<1)
  4788. {
  4789. const int sz=500;
  4790. ctx->varValueStore_left = sz;
  4791. ctx->varValueStore = (EEL_F *)newCtxDataBlock((int)sizeof(EEL_F)*sz,8);
  4792. }
  4793. if (ctx->varValueStore)
  4794. {
  4795. int listsz = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
  4796. size_t l = strlen(name);
  4797. varNameRec *vh;
  4798. if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN;
  4799. vh = (varNameRec*) newCtxDataBlock( (int) (sizeof(varNameRec) + l),8);
  4800. if (!vh || EEL_GROWBUF_RESIZE(&ctx->varNameList, (listsz+1))) return NULL; // alloc fail
  4801. (vh->value = ctx->varValueStore++)[0]=0.0;
  4802. ctx->varValueStore_left--;
  4803. vh->refcnt=1;
  4804. vh->isreg=isReg;
  4805. memcpy(vh->str,name,l);
  4806. vh->str[l] = 0;
  4807. if (namePtrOut) *namePtrOut = vh->str;
  4808. if (slot < listsz)
  4809. {
  4810. memmove(EEL_GROWBUF_GET(&ctx->varNameList) + slot+1,
  4811. EEL_GROWBUF_GET(&ctx->varNameList) + slot, (listsz - slot) * sizeof(EEL_GROWBUF_GET(&ctx->varNameList)[0]));
  4812. }
  4813. EEL_GROWBUF_GET(&ctx->varNameList)[slot] = vh;
  4814. return vh->value;
  4815. }
  4816. return NULL;
  4817. }
  4818. //------------------------------------------------------------------------------
  4819. void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx)
  4820. {
  4821. compileContext *tctx = (compileContext *) ctx;
  4822. int ni;
  4823. varNameRec **rd;
  4824. if (!tctx) return;
  4825. ni = EEL_GROWBUF_GET_SIZE(&tctx->varNameList);
  4826. rd = EEL_GROWBUF_GET(&tctx->varNameList);
  4827. while (ni--)
  4828. {
  4829. if (!func(rd[0]->str,rd[0]->value,userctx)) break;
  4830. rd++;
  4831. }
  4832. }
  4833. //------------------------------------------------------------------------------
  4834. EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX _ctx, const char *var)
  4835. {
  4836. compileContext *ctx = (compileContext *)_ctx;
  4837. if (!ctx) return 0;
  4838. if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4]))
  4839. {
  4840. EEL_F *a=get_global_var(ctx,var,1);
  4841. if (a) return a;
  4842. }
  4843. return nseel_int_register_var(ctx,var,1,NULL);
  4844. }
  4845. EEL_F *NSEEL_VM_getvar(NSEEL_VMCTX _ctx, const char *var)
  4846. {
  4847. compileContext *ctx = (compileContext *)_ctx;
  4848. if (!ctx) return 0;
  4849. if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4]))
  4850. {
  4851. EEL_F *a=get_global_var(ctx,var,0);
  4852. if (a) return a;
  4853. }
  4854. return nseel_int_register_var(ctx,var,-1,NULL);
  4855. }
  4856. int NSEEL_VM_get_var_refcnt(NSEEL_VMCTX _ctx, const char *name)
  4857. {
  4858. compileContext *ctx = (compileContext *)_ctx;
  4859. int slot,match;
  4860. if (!ctx) return -1;
  4861. slot = vartable_lowerbound(ctx,name, &match);
  4862. return match ? EEL_GROWBUF_GET(&ctx->varNameList)[slot]->refcnt : -1;
  4863. }
  4864. opcodeRec *nseel_createFunctionByName(compileContext *ctx, const char *name, int np, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3)
  4865. {
  4866. int chkamt=0;
  4867. functionType *f=nseel_getFunctionByName(ctx,name,&chkamt);
  4868. if (f) while (chkamt-->=0)
  4869. {
  4870. if ((f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK) == np)
  4871. {
  4872. opcodeRec *o=newOpCode(ctx,NULL, np==3?OPCODETYPE_FUNC3:np==2?OPCODETYPE_FUNC2:OPCODETYPE_FUNC1);
  4873. if (o)
  4874. {
  4875. o->fntype = FUNCTYPE_FUNCTIONTYPEREC;
  4876. o->fn = f;
  4877. o->parms.parms[0]=code1;
  4878. o->parms.parms[1]=code2;
  4879. o->parms.parms[2]=code3;
  4880. }
  4881. return o;
  4882. }
  4883. f++;
  4884. if (stricmp(f->name,name)) break;
  4885. }
  4886. return NULL;
  4887. }
  4888. //------------------------------------------------------------------------------
  4889. opcodeRec *nseel_translate(compileContext *ctx, const char *tmp, size_t tmplen) // tmplen 0 = null term
  4890. {
  4891. // this depends on the string being nul terminated eventually, tmplen is used more as a hint than anything else
  4892. if ((tmp[0] == '0' || tmp[0] == '$') && toupper(tmp[1])=='X')
  4893. {
  4894. char *p;
  4895. return nseel_createCompiledValue(ctx,(EEL_F)strtoul(tmp+2,&p,16));
  4896. }
  4897. else if (tmp[0] == '$')
  4898. {
  4899. if (tmp[1] == '~')
  4900. {
  4901. char *p=(char*)tmp+2;
  4902. unsigned int v=strtoul(tmp+2,&p,10);
  4903. if (v>53) v=53;
  4904. return nseel_createCompiledValue(ctx,(EEL_F)((((WDL_INT64)1) << v) - 1));
  4905. }
  4906. else if (!tmplen ? !stricmp(tmp,"$E") : (tmplen == 2 && !strnicmp(tmp,"$E",2)))
  4907. return nseel_createCompiledValue(ctx,(EEL_F)2.71828183);
  4908. else if (!tmplen ? !stricmp(tmp, "$PI") : (tmplen == 3 && !strnicmp(tmp, "$PI", 3)))
  4909. return nseel_createCompiledValue(ctx,(EEL_F)3.141592653589793);
  4910. else if (!tmplen ? !stricmp(tmp, "$PHI") : (tmplen == 4 && !strnicmp(tmp, "$PHI", 4)))
  4911. return nseel_createCompiledValue(ctx,(EEL_F)1.61803399);
  4912. else if ((!tmplen || tmplen == 4) && tmp[1] == '\'' && tmp[2] && tmp[3] == '\'')
  4913. return nseel_createCompiledValue(ctx,(EEL_F)tmp[2]);
  4914. else return NULL;
  4915. }
  4916. else if (tmp[0] == '\'')
  4917. {
  4918. char b[64];
  4919. int x,sz;
  4920. unsigned int rv=0;
  4921. if (!tmplen) // nul terminated tmplen, calculate a workable length
  4922. {
  4923. // faster than strlen(tmp) if tmp is large, we'll never need more than ~18 chars anyway
  4924. while (tmplen < 32 && tmp[tmplen]) tmplen++;
  4925. }
  4926. sz = tmplen > 0 ? nseel_filter_escaped_string(b,sizeof(b),tmp+1, tmplen - 1, '\'') : 0;
  4927. if (sz > 4)
  4928. {
  4929. if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
  4930. snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"multi-byte character '%.5s...' too long",b);
  4931. return NULL; // do not allow 'xyzxy', limit to 4 bytes
  4932. }
  4933. for (x=0;x<sz;x++) rv = (rv<<8) + ((unsigned char*)b)[x];
  4934. return nseel_createCompiledValue(ctx,(EEL_F)rv);
  4935. }
  4936. else if (tmp[0] == '#')
  4937. {
  4938. char buf[2048];
  4939. if (!tmplen) while (tmplen < sizeof(buf)-1 && tmp[tmplen]) tmplen++;
  4940. else if (tmplen > sizeof(buf)-1) tmplen = sizeof(buf)-1;
  4941. memcpy(buf,tmp,tmplen);
  4942. buf[tmplen]=0;
  4943. if (ctx->onNamedString)
  4944. {
  4945. if (tmplen>0 && buf[1]&&ctx->function_curName)
  4946. {
  4947. int err=0;
  4948. opcodeRec *r = nseel_resolve_named_symbol(ctx,nseel_createCompiledValuePtr(ctx,NULL,buf),-1, &err);
  4949. if (r)
  4950. {
  4951. if (r->opcodeType!=OPCODETYPE_VALUE_FROM_NAMESPACENAME)
  4952. {
  4953. r->opcodeType = OPCODETYPE_DIRECTVALUE;
  4954. r->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,buf+1);
  4955. r->parms.dv.valuePtr=NULL;
  4956. }
  4957. return r;
  4958. }
  4959. if (err) return NULL;
  4960. }
  4961. // if not namespaced symbol, return directly
  4962. if (!buf[1])
  4963. {
  4964. opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE_TEMPSTRING);
  4965. if (r) r->parms.dv.directValue = -10000.0;
  4966. return r;
  4967. }
  4968. return nseel_createCompiledValue(ctx,ctx->onNamedString(ctx->caller_this,buf+1));
  4969. }
  4970. }
  4971. return nseel_createCompiledValue(ctx,(EEL_F)atof(tmp));
  4972. }
  4973. void NSEEL_VM_set_var_resolver(NSEEL_VMCTX _ctx, EEL_F *(*res)(void *userctx, const char *name), void *userctx)
  4974. {
  4975. compileContext *ctx = (compileContext *)_ctx;
  4976. if (ctx)
  4977. {
  4978. ctx->getVariable = res;
  4979. ctx->getVariable_userctx = userctx;
  4980. }
  4981. }
  4982. #if defined(__ppc__) || defined(EEL_TARGET_PORTABLE)
  4983. // blank stubs
  4984. void eel_setfp_round() { }
  4985. void eel_setfp_trunc() { }
  4986. void eel_enterfp(int s[2]) {}
  4987. void eel_leavefp(int s[2]) {}
  4988. #endif