123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2021 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- The original version of this library can be located at:
- http://www.angelcode.com/angelscript/
- Andreas Jonsson
- andreas@angelcode.com
- */
- //
- // as_restore.cpp
- //
- // Functions for saving and restoring module bytecode
- // asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be
- #include "as_config.h"
- #include "as_restore.h"
- #include "as_bytecode.h"
- #include "as_scriptobject.h"
- #include "as_texts.h"
- #include "as_debug.h"
- BEGIN_AS_NAMESPACE
- // Macros for doing endianess agnostic bitmask serialization
- #define SAVE_TO_BIT(dst, val, bit) ((dst) |= ((val) << (bit)))
- #define LOAD_FROM_BIT(dst, val, bit) ((dst) = ((val) >> (bit)) & 1)
- asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine)
- : module(_module), stream(_stream), engine(_engine)
- {
- error = false;
- bytesRead = 0;
- }
- int asCReader::ReadData(void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- int ret = 0;
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; ret >= 0 && n < size; n++ )
- ret = stream->Read(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; ret >= 0 && n >= 0; n-- )
- ret = stream->Read(((asBYTE*)data)+n, 1);
- #endif
- if (ret < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- bytesRead += size;
- return ret;
- }
- int asCReader::Read(bool *wasDebugInfoStripped)
- {
- TimeIt("asCReader::Read");
- // Before starting the load, make sure that
- // any existing resources have been freed
- module->InternalReset();
- // Call the inner method to do the actual loading
- int r = ReadInner();
- if( r < 0 )
- {
- // Something went wrong while loading the bytecode, so we need
- // to clean-up whatever has been created during the process.
- // Make sure none of the loaded functions attempt to release
- // references that have not yet been increased
- asUINT i;
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) )
- if( module->m_scriptFunctions[i]->scriptData )
- module->m_scriptFunctions[i]->scriptData->byteCode.SetLength(0);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->m_scriptGlobals.List();
- for( ; it; it++ )
- if( (*it)->GetInitFunc() )
- if( (*it)->GetInitFunc()->scriptData )
- (*it)->GetInitFunc()->scriptData->byteCode.SetLength(0);
- module->InternalReset();
- }
- else
- {
- // Init system functions properly
- engine->PrepareEngine();
- // Initialize the global variables (unless requested not to)
- if( engine->ep.initGlobalVarsAfterBuild )
- r = module->ResetGlobalVars(0);
- if( wasDebugInfoStripped )
- *wasDebugInfoStripped = noDebugInfo;
- }
- // Clean up the loaded string constants
- for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
- engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
- usedStringConstants.SetLength(0);
- return r;
- }
- int asCReader::Error(const char *msg)
- {
- // Don't write if it has already been reported an error earlier
- if( !error )
- {
- asCString str;
- str.Format(msg, bytesRead);
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- error = true;
- }
- return asERROR;
- }
- int asCReader::ReadInner()
- {
- TimeIt("asCReader::ReadInner");
- // This function will load each entity one by one from the stream.
- // If any error occurs, it will return to the caller who is
- // responsible for cleaning up the partially loaded entities.
- engine->deferValidationOfTemplateTypes = true;
- unsigned long i, count;
- asCScriptFunction* func;
- // Read the flag as 1 byte even on platforms with 4byte booleans
- noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0;
- // Read enums
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_enumTypes.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCEnumType *et = asNEW(asCEnumType)(engine);
- if( et == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(et, 1, &isExternal);
- // If the type is shared then we should use the original if it exists
- bool sharedExists = false;
- if( et->IsShared() )
- {
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
- {
- asCTypeInfo *t = engine->sharedScriptTypes[n];
- if( t &&
- t->IsShared() &&
- t->name == et->name &&
- t->nameSpace == et->nameSpace &&
- (t->flags & asOBJ_ENUM) )
- {
- asDELETE(et, asCEnumType);
- et = CastToEnumType(t);
- sharedExists = true;
- break;
- }
- }
- }
- if (isExternal && !sharedExists)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- asDELETE(et, asCEnumType);
- error = true;
- return asERROR;
- }
- if( sharedExists )
- {
- existingShared.Insert(et, true);
- et->AddRefInternal();
- }
- else
- {
- if( et->IsShared() )
- {
- engine->sharedScriptTypes.PushLast(et);
- et->AddRefInternal();
- }
- // Set this module as the owner
- et->module = module;
- }
- module->AddEnumType(et);
- if (isExternal)
- module->m_externalTypes.PushLast(et);
- ReadTypeDeclaration(et, 2);
- }
- if( error ) return asERROR;
- // classTypes[]
- // First restore the structure names, then the properties
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_classTypes.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- asCObjectType *ot = asNEW(asCObjectType)(engine);
- if( ot == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(ot, 1, &isExternal);
- // If the type is shared, then we should use the original if it exists
- bool sharedExists = false;
- if( ot->IsShared() )
- {
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
- {
- asCTypeInfo *ti = engine->sharedScriptTypes[n];
- asCObjectType *t = CastToObjectType(ti);
- if( t &&
- t->IsShared() &&
- t->name == ot->name &&
- t->nameSpace == ot->nameSpace &&
- t->IsInterface() == ot->IsInterface() )
- {
- asDELETE(ot, asCObjectType);
- ot = CastToObjectType(t);
- sharedExists = true;
- break;
- }
- }
- }
- if (isExternal && !sharedExists)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- asDELETE(ot, asCObjectType);
- error = true;
- return asERROR;
- }
- if( sharedExists )
- {
- existingShared.Insert(ot, true);
- ot->AddRefInternal();
- }
- else
- {
- if( ot->IsShared() )
- {
- engine->sharedScriptTypes.PushLast(ot);
- ot->AddRefInternal();
- }
- // Set this module as the owner
- ot->module = module;
- }
- module->AddClassType(ot);
- if (isExternal)
- module->m_externalTypes.PushLast(ot);
- }
- if( error ) return asERROR;
- // Read func defs
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_funcDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- bool isNew, isExternal;
- asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal);
- if(funcDef)
- {
- funcDef->module = module;
- asCFuncdefType *fdt = funcDef->funcdefType;
- fdt->module = module;
- module->AddFuncDef(fdt);
- engine->funcDefs.PushLast(fdt);
- // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module
- // Check if there is another identical funcdef from another module and if so reuse that instead
- if(funcDef->IsShared())
- {
- for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
- {
- asCFuncdefType *f2 = engine->funcDefs[n];
- if( f2 == 0 || fdt == f2 )
- continue;
- if( !f2->funcdef->IsShared() )
- continue;
- if( f2->name == fdt->name &&
- f2->nameSpace == fdt->nameSpace &&
- f2->parentClass == fdt->parentClass &&
- f2->funcdef->IsSignatureExceptNameEqual(funcDef) )
- {
- // Replace our funcdef for the existing one
- module->ReplaceFuncDef(fdt, f2);
- f2->AddRefInternal();
- if (isExternal)
- module->m_externalTypes.PushLast(f2);
- engine->funcDefs.RemoveValue(fdt);
- savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef;
- if (fdt->parentClass)
- {
- // The real funcdef should already be in the object
- asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0);
- fdt->parentClass = 0;
- }
- fdt->ReleaseInternal();
- funcDef = 0;
- break;
- }
- }
- }
- // Add the funcdef to the parentClass if this is a child funcdef
- if (funcDef && fdt->parentClass)
- fdt->parentClass->childFuncDefs.PushLast(fdt);
- // Check if an external shared funcdef was really found
- if (isExternal && funcDef)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- error = true;
- return asERROR;
- }
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- // Read interface methods
- for( i = 0; i < module->m_classTypes.GetLength() && !error; i++ )
- {
- if( module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 2);
- }
- // Read class methods and behaviours
- for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 2);
- }
- // Read class properties
- for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 3);
- }
- if( error ) return asERROR;
- // Read typedefs
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_typeDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCTypedefType *td = asNEW(asCTypedefType)(engine);
- if( td == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(td, 1, &isExternal);
- td->module = module;
- module->AddTypeDef(td);
- ReadTypeDeclaration(td, 2);
- }
- if( error ) return asERROR;
- // scriptGlobals[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- if( count && engine->ep.disallowGlobalVars )
- {
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED);
- Error(TXT_INVALID_BYTECODE_d);
- }
- module->m_scriptGlobals.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- ReadGlobalProperty();
- }
- // scriptFunctions[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- for( i = 0; i < count && !error; ++i )
- {
- size_t len = module->m_scriptFunctions.GetLength();
- bool isNew, isExternal;
- func = ReadFunction(isNew, true, true, true, &isExternal);
- if( func == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- // Is the function shared and was it created now?
- if( func->IsShared() && len != module->m_scriptFunctions.GetLength() )
- {
- // If the function already existed in another module, then
- // we need to replace it with previously existing one
- for( asUINT n = 0; n < engine->scriptFunctions.GetLength() && !error; n++ )
- {
- asCScriptFunction *realFunc = engine->scriptFunctions[n];
- if( realFunc &&
- realFunc != func &&
- realFunc->IsShared() &&
- realFunc->nameSpace == func->nameSpace &&
- realFunc->IsSignatureEqual(func) )
- {
- // Replace the recently created function with the pre-existing function
- module->m_scriptFunctions[module->m_scriptFunctions.GetLength()-1] = realFunc;
- realFunc->AddRefInternal();
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- engine->RemoveScriptFunction(func);
- // Insert the function in the dontTranslate array
- dontTranslate.Insert(realFunc, true);
- if (isExternal)
- module->m_externalFunctions.PushLast(realFunc);
- // Release the function, but make sure nothing else is released
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- func = 0;
- break;
- }
- }
- }
- // Check if an external shared func was really found
- if (isExternal && func)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- error = true;
- return asERROR;
- }
- }
- // globalFunctions[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- for( i = 0; i < count && !error; ++i )
- {
- bool isNew;
- func = ReadFunction(isNew, false, false);
- if( func )
- {
- // All the global functions were already loaded while loading the scriptFunctions, here
- // we're just re-reading the references to know which goes into the globalFunctions array
- asASSERT( !isNew );
- module->m_globalFunctions.Put(func);
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( error ) return asERROR;
- // bindInformations[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_bindInformations.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- sBindInfo *info = asNEW(sBindInfo);
- if( info == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isNew;
- info->importedFunctionSignature = ReadFunction(isNew, false, false);
- if( info->importedFunctionSignature == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- if( engine->freeImportedFunctionIdxs.GetLength() )
- {
- int id = engine->freeImportedFunctionIdxs.PopLast();
- info->importedFunctionSignature->id = int(FUNC_IMPORTED + id);
- engine->importedFunctions[id] = info;
- }
- else
- {
- info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength());
- engine->importedFunctions.PushLast(info);
- }
- ReadString(&info->importFromModule);
- info->boundFunctionId = -1;
- module->m_bindInformations.PushLast(info);
- }
- if( error ) return asERROR;
- // usedTypes[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedTypes.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- asCTypeInfo *ti = ReadTypeInfo();
- usedTypes.PushLast(ti);
- }
- // usedTypeIds[]
- if( !error )
- ReadUsedTypeIds();
- // usedFunctions[]
- if( !error )
- ReadUsedFunctions();
- // usedGlobalProperties[]
- if( !error )
- ReadUsedGlobalProps();
- // usedStringConstants[]
- if( !error )
- ReadUsedStringConstants();
- // usedObjectProperties
- if( !error )
- ReadUsedObjectProps();
- // Validate the template types
- if( !error )
- {
- for( i = 0; i < usedTypes.GetLength() && !error; i++ )
- {
- asCObjectType *ot = CastToObjectType(usedTypes[i]);
- if( !ot ||
- !(ot->flags & asOBJ_TEMPLATE) ||
- !ot->beh.templateCallback )
- continue;
- bool dontGarbageCollect = false;
- asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback];
- if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) )
- {
- asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace);
- for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += ot->templateSubTypes[n].Format(ot->nameSpace);
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- else
- {
- // If the callback said this template instance won't be garbage collected then remove the flag
- if( dontGarbageCollect )
- ot->flags &= ~asOBJ_GC;
- }
- }
- }
- engine->deferValidationOfTemplateTypes = false;
- if( error ) return asERROR;
- // Update the loaded bytecode to point to the correct types, property offsets,
- // function ids, etc. This is basically a linking stage.
- for( i = 0; i < module->m_scriptFunctions.GetLength() && !error; i++ )
- if( module->m_scriptFunctions[i]->funcType == asFUNC_SCRIPT )
- TranslateFunction(module->m_scriptFunctions[i]);
- asCSymbolTable<asCGlobalProperty>::iterator globIt = module->m_scriptGlobals.List();
- while( globIt && !error )
- {
- asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
- if( initFunc )
- TranslateFunction(initFunc);
- globIt++;
- }
- if( error ) return asERROR;
- // Add references for all functions (except for the pre-existing shared code)
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) )
- module->m_scriptFunctions[i]->AddReferences();
- globIt = module->m_scriptGlobals.List();
- while( globIt )
- {
- asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
- if( initFunc )
- initFunc->AddReferences();
- globIt++;
- }
- return error ? asERROR : asSUCCESS;
- }
- void asCReader::ReadUsedStringConstants()
- {
- TimeIt("asCReader::ReadUsedStringConstants");
- asCString str;
- asUINT count;
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- if (count > 0 && engine->stringFactory == 0)
- {
- Error(TXT_STRINGS_NOT_RECOGNIZED);
- return;
- }
- usedStringConstants.Allocate(count, false);
- for( asUINT i = 0; i < count; ++i )
- {
- ReadString(&str);
- usedStringConstants.PushLast(const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())));
- }
- }
- void asCReader::ReadUsedFunctions()
- {
- TimeIt("asCReader::ReadUsedFunctions");
- asUINT count;
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedFunctions.SetLength(count);
- if( usedFunctions.GetLength() != count )
- {
- // Out of memory
- error = true;
- return;
- }
- memset(usedFunctions.AddressOf(), 0, sizeof(asCScriptFunction *)*count);
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- char c;
- // Read the data to be able to uniquely identify the function
- // Is the function from the module or the application?
- ReadData(&c, 1);
- if( c == 'n' )
- {
- // Null function pointer
- usedFunctions[n] = 0;
- }
- else
- {
- asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY);
- asCObjectType *parentClass = 0;
- ReadFunctionSignature(&func, &parentClass);
- if( error )
- {
- func.funcType = asFUNC_DUMMY;
- return;
- }
- // Find the correct function
- if( c == 'm' )
- {
- if( func.funcType == asFUNC_IMPORTED )
- {
- for( asUINT i = 0; i < module->m_bindInformations.GetLength(); i++ )
- {
- asCScriptFunction *f = module->m_bindInformations[i]->importedFunctionSignature;
- if( func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.funcType == asFUNC_FUNCDEF )
- {
- const asCArray<asCFuncdefType *> &funcs = module->m_funcDefs;
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if( f == 0 ||
- func.name != f->name ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
- funcs[i]->parentClass != parentClass )
- continue;
- asASSERT( f->objectType == 0 );
- usedFunctions[n] = f;
- break;
- }
- }
- else
- {
- // TODO: optimize: Global functions should be searched for in module->globalFunctions
- // TODO: optimize: funcdefs should be searched for in module->funcDefs
- // TODO: optimize: object methods should be searched for directly in the object type
- for( asUINT i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = module->m_scriptFunctions[i];
- if( func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if (c == 's')
- {
- // Look for shared entities in the engine, as they may not necessarily be part
- // of the scope of the module if they have been inhereted from other modules.
- if (func.funcType == asFUNC_FUNCDEF)
- {
- const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
- for (asUINT i = 0; i < funcs.GetLength(); i++)
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if (f == 0 ||
- func.name != f->name ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
- funcs[i]->parentClass != parentClass)
- continue;
- asASSERT(f->objectType == 0);
- usedFunctions[n] = f;
- break;
- }
- }
- else
- {
- for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[i];
- if (f == 0 || !f->IsShared() ||
- func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else
- {
- asASSERT(c == 'a');
- if( func.funcType == asFUNC_FUNCDEF )
- {
- // This is a funcdef (registered or shared)
- const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass )
- continue;
- asASSERT( f->objectType == 0 );
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.name[0] == '$' )
- {
- // This is a special function
- if( func.name == "$beh0" && func.objectType )
- {
- if (func.objectType->flags & asOBJ_TEMPLATE)
- {
- // Look for the matching constructor inside the factory stubs generated for the template instance
- // See asCCompiler::PerformFunctionCall
- for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
-
- // Find the id of the real constructor and not the generated stub
- asUINT id = 0;
- asDWORD *bc = f->scriptData->byteCode.AddressOf();
- while (bc)
- {
- if ((*(asBYTE*)bc) == asBC_CALLSYS)
- {
- id = asBC_INTARG(bc);
- break;
- }
- bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
- }
- f = engine->scriptFunctions[id];
- if (f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- if( usedFunctions[n] == 0 )
- {
- // This is a class constructor, so we can search directly in the object type's constructors
- for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
- if (f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if( func.name == "$fact" || func.name == "$beh3" )
- {
- // This is a factory (or stub), so look for the function in the return type's factories
- asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo());
- if( objType )
- {
- for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]];
- if( f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if( func.name == "$list" )
- {
- // listFactory is used for both factory is global and returns a handle and constructor that is a method
- asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo());
- if( objType )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
- if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- usedFunctions[n] = f;
- }
- }
- else if( func.name == "$beh2" )
- {
- // This is a destructor, so check the object type's destructor
- asCObjectType *objType = func.objectType;
- if( objType )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct];
- if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- usedFunctions[n] = f;
- }
- }
- else if( func.name == "$dlgte" )
- {
- // This is the delegate factory
- asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
- asASSERT( f && func.IsSignatureEqual(f) );
- usedFunctions[n] = f;
- }
- else
- {
- // Must match one of the above cases
- asASSERT(false);
- }
- }
- else if( func.objectType == 0 )
- {
- // This is a global function
- const asCArray<asUINT> &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name);
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]);
- if( f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.objectType )
- {
- // It is a class member, so we can search directly in the object type's members
- // TODO: virtual function is different that implemented method
- for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]];
- if( f == 0 ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- if( usedFunctions[n] == 0 )
- {
- // TODO: clean up: This part of the code should never happen. All functions should
- // be found in the above logic. The only valid reason to come here
- // is if the bytecode is wrong and the function doesn't exist anyway.
- // This loop is kept temporarily until we can be certain all scenarios
- // are covered.
- for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[i];
- if( f == 0 ||
- func.objectType != f->objectType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- // No function is expected to be found
- asASSERT(usedFunctions[n] == 0);
- }
- }
- // Set the type to dummy so it won't try to release the id
- func.funcType = asFUNC_DUMMY;
- if( usedFunctions[n] == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- }
- void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass)
- {
- asUINT i, count;
- asCDataType dt;
- int num;
- ReadString(&func->name);
- if( func->name == DELEGATE_FACTORY )
- {
- // It's not necessary to read anymore, everything is known
- asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
- asASSERT( f );
- func->returnType = f->returnType;
- func->parameterTypes = f->parameterTypes;
- func->inOutFlags = f->inOutFlags;
- func->funcType = f->funcType;
- func->defaultArgs = f->defaultArgs;
- func->nameSpace = f->nameSpace;
- return;
- }
- ReadDataType(&func->returnType);
- count = SanityCheck(ReadEncodedUInt(), 256);
- func->parameterTypes.Allocate(count, false);
- for( i = 0; i < count; ++i )
- {
- ReadDataType(&dt);
- func->parameterTypes.PushLast(dt);
- }
- func->inOutFlags.SetLength(func->parameterTypes.GetLength());
- if( func->inOutFlags.GetLength() != func->parameterTypes.GetLength() )
- {
- // Out of memory
- error = true;
- return;
- }
- memset(func->inOutFlags.AddressOf(), 0, sizeof(asETypeModifiers)*func->inOutFlags.GetLength());
- if (func->parameterTypes.GetLength() > 0)
- {
- count = ReadEncodedUInt();
- if (count > func->parameterTypes.GetLength())
- {
- // Cannot be more than the number of arguments
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- for (i = 0; i < count; ++i)
- {
- num = ReadEncodedUInt();
- func->inOutFlags[i] = static_cast<asETypeModifiers>(num);
- }
- }
- func->funcType = (asEFuncType)ReadEncodedUInt();
- // Read the default args, from last to first
- if (func->parameterTypes.GetLength() > 0)
- {
- count = ReadEncodedUInt();
- if (count > func->parameterTypes.GetLength())
- {
- // Cannot be more than the number of arguments
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- if (count)
- {
- func->defaultArgs.SetLength(func->parameterTypes.GetLength());
- if (func->defaultArgs.GetLength() != func->parameterTypes.GetLength())
- {
- // Out of memory
- error = true;
- return;
- }
- memset(func->defaultArgs.AddressOf(), 0, sizeof(asCString*)*func->defaultArgs.GetLength());
- for (i = 0; i < count; i++)
- {
- asCString *str = asNEW(asCString);
- if (str == 0)
- {
- // Out of memory
- error = true;
- return;
- }
- func->defaultArgs[func->defaultArgs.GetLength() - 1 - i] = str;
- ReadString(str);
- }
- }
- }
- func->objectType = CastToObjectType(ReadTypeInfo());
- if( func->objectType )
- {
- func->objectType->AddRefInternal();
- asBYTE b;
- ReadData(&b, 1);
- func->SetReadOnly((b & 1) ? true : false);
- func->SetPrivate((b & 2) ? true : false);
- func->SetProtected((b & 4) ? true : false);
- func->nameSpace = func->objectType->nameSpace;
- }
- else
- {
- if (func->funcType == asFUNC_FUNCDEF)
- {
- asBYTE b;
- ReadData(&b, 1);
- if (b == 'n')
- {
- asCString ns;
- ReadString(&ns);
- func->nameSpace = engine->AddNameSpace(ns.AddressOf());
- }
- else if (b == 'o')
- {
- func->nameSpace = 0;
- if (parentClass)
- *parentClass = CastToObjectType(ReadTypeInfo());
- else
- error = true;
- }
- else
- error = true;
- }
- else
- {
- asCString ns;
- ReadString(&ns);
- func->nameSpace = engine->AddNameSpace(ns.AddressOf());
- }
- }
- }
- asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal)
- {
- isNew = false;
- if (isExternal) *isExternal = false;
- if( error ) return 0;
- char c;
- ReadData(&c, 1);
- if( c == '\0' )
- {
- // There is no function, so return a null pointer
- return 0;
- }
- if( c == 'r' )
- {
- // This is a reference to a previously saved function
- asUINT index = ReadEncodedUInt();
- if( index < savedFunctions.GetLength() )
- return savedFunctions[index];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- // Load the new function
- isNew = true;
- asCScriptFunction *func = asNEW(asCScriptFunction)(engine,0,asFUNC_DUMMY);
- if( func == 0 )
- {
- // Out of memory
- error = true;
- return 0;
- }
- savedFunctions.PushLast(func);
- int i, count;
- asCDataType dt;
- int num;
- asCObjectType *parentClass = 0;
- ReadFunctionSignature(func, &parentClass);
- if( error )
- {
- func->DestroyHalfCreated();
- return 0;
- }
- if( func->funcType == asFUNC_SCRIPT )
- {
- // Skip this for external shared entities
- if (module->m_externalTypes.IndexOf(func->objectType) >= 0)
- {
- // Replace with the real function from the existing entity
- isNew = false;
- asCObjectType *ot = func->objectType;
- for (asUINT n = 0; n < ot->methods.GetLength(); n++)
- {
- asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]];
- if (func2->funcType == asFUNC_VIRTUAL)
- func2 = ot->virtualFunctionTable[func2->vfTableIdx];
- if (func->IsSignatureEqual(func2))
- {
- func->DestroyHalfCreated();
- // as this is an existing function it shouldn't be translated as if just loaded
- dontTranslate.Insert(func2, true);
- // update the saved functions for future references
- savedFunctions[savedFunctions.GetLength() - 1] = func2;
- // As it is an existing function it shouldn't be added to the module or the engine
- return func2;
- }
- }
- }
- else
- {
- char bits;
- ReadData(&bits, 1);
- func->SetShared((bits & 1) ? true : false);
- func->SetExplicit((bits & 32) ? true : false);
- func->dontCleanUpOnException = (bits & 2) ? true : false;
- if ((bits & 4) && isExternal)
- *isExternal = true;
- // for external shared functions the rest is not needed
- if (!(bits & 4))
- {
- func->AllocateScriptFunctionData();
- if (func->scriptData == 0)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- if (addToGC && !addToModule)
- engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours);
- ReadByteCode(func);
- func->scriptData->variableSpace = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariablesOnHeap = 0;
- if (bits & 8)
- {
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariablePos.Allocate(count, false);
- func->scriptData->objVariableTypes.Allocate(count, false);
- for (i = 0; i < count; ++i)
- {
- func->scriptData->objVariableTypes.PushLast(ReadTypeInfo());
- num = ReadEncodedUInt();
- func->scriptData->objVariablePos.PushLast(num);
- if (error)
- {
- // No need to continue (the error has already been reported before)
- func->DestroyHalfCreated();
- return 0;
- }
- }
- if (count > 0)
- func->scriptData->objVariablesOnHeap = SanityCheck(ReadEncodedUInt(), 10000);
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariableInfo.SetLength(length);
- for (i = 0; i < length; ++i)
- {
- func->scriptData->objVariableInfo[i].programPos = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariableInfo[i].variableOffset = SanityCheck(ReadEncodedInt(), 10000);
- asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt();
- func->scriptData->objVariableInfo[i].option = option;
- if (option != asOBJ_INIT &&
- option != asOBJ_UNINIT &&
- option != asBLOCK_BEGIN &&
- option != asBLOCK_END &&
- option != asOBJ_VARDECL)
- {
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- }
- }
- if (bits & 16)
- {
- // Read info on try/catch blocks
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->tryCatchInfo.SetLength(length);
- for (i = 0; i < length; ++i)
- {
- // The program position must be adjusted to be in number of instructions
- func->scriptData->tryCatchInfo[i].tryPos = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->tryCatchInfo[i].catchPos = SanityCheck(ReadEncodedUInt(), 1000000);
- }
- }
- if (!noDebugInfo)
- {
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->lineNumbers.SetLength(length);
- if (int(func->scriptData->lineNumbers.GetLength()) != length)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- for (i = 0; i < length; ++i)
- func->scriptData->lineNumbers[i] = ReadEncodedUInt();
- // Read the array of script sections
- length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->sectionIdxs.SetLength(length);
- if (int(func->scriptData->sectionIdxs.GetLength()) != length)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- for (i = 0; i < length; ++i)
- {
- if ((i & 1) == 0)
- func->scriptData->sectionIdxs[i] = ReadEncodedUInt();
- else
- {
- asCString str;
- ReadString(&str);
- func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf());
- }
- }
- }
- // Read the variable information
- if (!noDebugInfo)
- {
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->variables.Allocate(length, false);
- for (i = 0; i < length; i++)
- {
- asSScriptVariable *var = asNEW(asSScriptVariable);
- if (var == 0)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- func->scriptData->variables.PushLast(var);
- var->declaredAtProgramPos = ReadEncodedUInt();
- var->stackOffset = SanityCheck(ReadEncodedInt(),10000);
- ReadString(&var->name);
- ReadDataType(&var->type);
- if (error)
- {
- // No need to continue (the error has already been reported before)
- func->DestroyHalfCreated();
- return 0;
- }
- }
- }
- // Read script section name
- if (!noDebugInfo)
- {
- asCString name;
- ReadString(&name);
- func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf());
- func->scriptData->declaredAt = ReadEncodedUInt();
- }
- // Read parameter names
- if (!noDebugInfo)
- {
- asUINT countParam = asUINT(ReadEncodedUInt64());
- if (countParam > func->parameterTypes.GetLength())
- {
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- func->parameterNames.SetLength(countParam);
- for (asUINT n = 0; n < countParam; n++)
- ReadString(&func->parameterNames[n]);
- }
- }
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- func->vfTableIdx = ReadEncodedUInt();
- }
- else if( func->funcType == asFUNC_FUNCDEF )
- {
- asBYTE bits;
- ReadData(&bits, 1);
- if( bits & 1 )
- func->SetShared(true);
- if ((bits & 2) && isExternal)
- *isExternal = true;
- // The asCFuncdefType constructor adds itself to the func->funcdefType member
- asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func);
- fdt->parentClass = parentClass;
- }
- // Methods loaded for shared objects, owned by other modules should not be created as new functions
- if( func->objectType && func->objectType->module != module )
- {
- // Return the real function from the object
- asCScriptFunction *realFunc = 0;
- bool found = false;
- if( func->funcType == asFUNC_SCRIPT )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.destruct];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- }
- for( asUINT n = 0; !found && n < func->objectType->beh.constructors.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.constructors[n]];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->beh.factories.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.factories[n]];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->methods.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->methods[n]];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->virtualFunctionTable.GetLength(); n++ )
- {
- realFunc = func->objectType->virtualFunctionTable[n];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- // If the loaded function is a virtual function, then look for the identical virtual function in the methods array
- for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->methods[n]];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- asASSERT( func->vfTableIdx == realFunc->vfTableIdx );
- found = true;
- break;
- }
- }
- }
- if( found )
- {
- // as this is an existing function it shouldn't be translated as if just loaded
- dontTranslate.Insert(realFunc, true);
- // update the saved functions for future references
- savedFunctions[savedFunctions.GetLength() - 1] = realFunc;
- if( realFunc->funcType == asFUNC_VIRTUAL && addToModule )
- {
- // Virtual methods must be added to the module's script functions array,
- // even if they are not owned by the module
- module->m_scriptFunctions.PushLast(realFunc);
- realFunc->AddRefInternal();
- }
- }
- else
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, func->objectType->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
-
- Error(TXT_INVALID_BYTECODE_d);
- savedFunctions.PopLast();
- realFunc = 0;
- }
- // Destroy the newly created function instance since it has been replaced by an existing function
- isNew = false;
- func->DestroyHalfCreated();
-
- // As it is an existing function it shouldn't be added to the module or the engine
- return realFunc;
- }
- if( addToModule )
- {
- // The refCount is already 1
- module->m_scriptFunctions.PushLast(func);
- func->module = module;
- }
- if( addToEngine )
- {
- func->id = engine->GetNextScriptFunctionId();
- engine->AddScriptFunction(func);
- }
- if( func->objectType )
- func->ComputeSignatureId();
- return func;
- }
- void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal)
- {
- if( phase == 1 )
- {
- asASSERT(isExternal);
- if (isExternal)
- *isExternal = false;
- // Read the initial attributes
- ReadString(&type->name);
- ReadData(&type->flags, 4);
- type->size = SanityCheck(ReadEncodedUInt(), 1000000);
- asCString ns;
- ReadString(&ns);
- type->nameSpace = engine->AddNameSpace(ns.AddressOf());
- // Verify that the flags match the asCTypeInfo
- if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) ||
- (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) ||
- (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE))))
- {
- error = true;
- return;
- }
- // Reset the size of script classes, since it will be recalculated as properties are added
- if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 )
- type->size = sizeof(asCScriptObject);
- asCObjectType *ot = CastToObjectType(type);
- if (ot)
- {
- // Use the default script class behaviours
- ot->beh = engine->scriptTypeBehaviours.beh;
- ot->beh.construct = 0;
- ot->beh.factory = 0;
- ot->beh.constructors.PopLast(); // These will be read from the file
- ot->beh.factories.PopLast(); // These will be read from the file
- engine->scriptFunctions[ot->beh.addref]->AddRefInternal();
- engine->scriptFunctions[ot->beh.release]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal();
- engine->scriptFunctions[ot->beh.copy]->AddRefInternal();
- // TODO: weak: Should not do this if the class has been declared with 'noweak'
- engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal();
- }
- // external shared flag
- if (type->flags & asOBJ_SHARED)
- {
- char c;
- ReadData(&c, 1);
- if (c == 'e')
- *isExternal = true;
- else if (c != ' ')
- {
- error = true;
- return;
- }
- }
- }
- else if( phase == 2 )
- {
- // external shared types doesn't store this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- if( type->flags & asOBJ_ENUM )
- {
- asCEnumType *t = CastToEnumType(type);
- int count = SanityCheck(ReadEncodedUInt(), 1000000);
- bool sharedExists = existingShared.MoveTo(0, type);
- if( !sharedExists )
- {
- t->enumValues.Allocate(count, false);
- for( int n = 0; n < count; n++ )
- {
- asSEnumValue *e = asNEW(asSEnumValue);
- if( e == 0 )
- {
- // Out of memory
- error = true;
- return;
- }
- ReadString(&e->name);
- ReadData(&e->value, 4); // TODO: Should be encoded
- t->enumValues.PushLast(e);
- }
- }
- else
- {
- // Verify that the enum values exists in the original
- asCString name;
- int value;
- for( int n = 0; n < count; n++ )
- {
- ReadString(&name);
- ReadData(&value, 4); // TODO: Should be encoded
- bool found = false;
- for( asUINT e = 0; e < t->enumValues.GetLength(); e++ )
- {
- if( t->enumValues[e]->name == name &&
- t->enumValues[e]->value == value )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( type->flags & asOBJ_TYPEDEF )
- {
- asCTypedefType *td = CastToTypedefType(type);
- asASSERT(td);
- eTokenType t = (eTokenType)ReadEncodedUInt();
- td->aliasForType = asCDataType::CreatePrimitive(t, false);
- }
- else
- {
- asCObjectType *ot = CastToObjectType(type);
- asASSERT(ot);
- // If the type is shared and pre-existing, we should just
- // validate that the loaded methods match the original
- bool sharedExists = existingShared.MoveTo(0, type);
- if( sharedExists )
- {
- asCObjectType *dt = CastToObjectType(ReadTypeInfo());
- if( ot->derivedFrom != dt )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- else
- {
- ot->derivedFrom = CastToObjectType(ReadTypeInfo());
- if( ot->derivedFrom )
- ot->derivedFrom->AddRefInternal();
- }
- // interfaces[] / interfaceVFTOffsets[]
- int size = SanityCheck(ReadEncodedUInt(), 1000000);
- if( sharedExists )
- {
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = CastToObjectType(ReadTypeInfo());
- if (!ot->IsInterface())
- ReadEncodedUInt();
- if( !type->Implements(intf) )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- else
- {
- ot->interfaces.Allocate(size, false);
- if( !ot->IsInterface() )
- ot->interfaceVFTOffsets.Allocate(size, false);
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = CastToObjectType(ReadTypeInfo());
- ot->interfaces.PushLast(intf);
- if (!ot->IsInterface())
- {
- asUINT offset = SanityCheck(ReadEncodedUInt(), 1000000);
- ot->interfaceVFTOffsets.PushLast(offset);
- }
- }
- }
- // behaviours
- if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.destruct);
- if( (realFunc == 0 && func == 0) || realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( func && savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- }
- else
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( func )
- {
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- dontTranslate.Insert(realFunc, true);
- }
- }
- else
- {
- if( func )
- {
- ot->beh.destruct = func->id;
- func->AddRefInternal();
- }
- else
- ot->beh.destruct = 0;
- }
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( int n = 0; n < size; n++ )
- {
- func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->beh.constructors.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->beh.constructors.PushLast(func->id);
- func->AddRefInternal();
- if( func->parameterTypes.GetLength() == 0 )
- ot->beh.construct = func->id;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->beh.factories.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->beh.factories.PushLast(func->id);
- func->AddRefInternal();
- if( func->parameterTypes.GetLength() == 0 )
- ot->beh.factory = func->id;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- // methods[]
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- int n;
- for( n = 0; n < size; n++ )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->methods.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- if( func->id == func->signatureId )
- engine->signatureIds.RemoveValue(func);
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- // If the method is the assignment operator we need to replace the default implementation
- if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 &&
- func->parameterTypes[0].GetTypeInfo() == func->objectType &&
- (func->inOutFlags[0] & asTM_INREF) )
- {
- engine->scriptFunctions[ot->beh.copy]->ReleaseInternal();
- ot->beh.copy = func->id;
- func->AddRefInternal();
- }
- ot->methods.PushLast(func->id);
- func->AddRefInternal();
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- // virtualFunctionTable[]
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( n = 0; n < size; n++ )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->virtualFunctionTable.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = ot->virtualFunctionTable[f];
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->virtualFunctionTable.PushLast(func);
- func->AddRefInternal();
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( phase == 3 )
- {
- // external shared types doesn't store this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- asCObjectType *ot = CastToObjectType(type);
- // This is only done for object types
- asASSERT(ot);
- // properties[]
- asUINT size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( asUINT n = 0; n < size; n++ )
- ReadObjectProperty(ot);
- }
- }
- asWORD asCReader::ReadEncodedUInt16()
- {
- asDWORD dw = ReadEncodedUInt();
- if( (dw>>16) != 0 && (dw>>16) != 0xFFFF )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- return asWORD(dw & 0xFFFF);
- }
- asUINT asCReader::ReadEncodedUInt()
- {
- asQWORD qw = ReadEncodedUInt64();
- if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- return asUINT(qw & 0xFFFFFFFFu);
- }
- int asCReader::ReadEncodedInt()
- {
- return int(ReadEncodedUInt());
- }
- asQWORD asCReader::ReadEncodedUInt64()
- {
- asQWORD i = 0;
- asBYTE b = 0xFF; // set to 0xFF to better catch if the stream doesn't update the value
- ReadData(&b, 1);
- bool isNegative = ( b & 0x80 ) ? true : false;
- b &= 0x7F;
- if( (b & 0x7F) == 0x7F )
- {
- ReadData(&b, 1); i = asQWORD(b) << 56;
- ReadData(&b, 1); i += asQWORD(b) << 48;
- ReadData(&b, 1); i += asQWORD(b) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x7E) == 0x7E )
- {
- i = asQWORD(b & 0x01) << 48;
- ReadData(&b, 1); i += asQWORD(b) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x7C) == 0x7C )
- {
- i = asQWORD(b & 0x03) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x78) == 0x78 )
- {
- i = asQWORD(b & 0x07) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x70) == 0x70 )
- {
- i = asUINT(b & 0x0F) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x60) == 0x60 )
- {
- i = asUINT(b & 0x1F) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x40) == 0x40 )
- {
- i = asUINT(b & 0x3F) << 8;
- ReadData(&b, 1); i += b;
- }
- else
- {
- i = b;
- }
- if( isNegative )
- i = (asQWORD)(-asINT64(i));
- return i;
- }
- asUINT asCReader::SanityCheck(asUINT val, asUINT max)
- {
- if (val > max)
- {
- Error(TXT_INVALID_BYTECODE_d);
- // Return 0 as default value
- return 0;
- }
- return val;
- }
- int asCReader::SanityCheck(int val, asUINT max)
- {
- if (val > int(max) || val < -int(max))
- {
- Error(TXT_INVALID_BYTECODE_d);
- // Return 0 as default value
- return 0;
- }
- return val;
- }
- void asCReader::ReadString(asCString* str)
- {
- asUINT len = SanityCheck(ReadEncodedUInt(), 1000000);
- if( len & 1 )
- {
- asUINT idx = len/2;
- if( idx < savedStrings.GetLength() )
- *str = savedStrings[idx];
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- else if( len > 0 )
- {
- len /= 2;
- str->SetLength(len);
- int r = stream->Read(str->AddressOf(), len);
- if (r < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- savedStrings.PushLast(*str);
- }
- else
- str->SetLength(0);
- }
- void asCReader::ReadGlobalProperty()
- {
- asCString name;
- asCDataType type;
- ReadString(&name);
- asCString ns;
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- ReadDataType(&type);
- asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace);
- // Read the initialization function
- bool isNew;
- // Do not add the function to the GC at this time. It will
- // only be added to the GC when the module releases the property
- asCScriptFunction *func = ReadFunction(isNew, false, true, false);
- if( func )
- {
- // Make sure the function knows it is owned by the module
- func->module = module;
- prop->SetInitFunc(func);
- func->ReleaseInternal();
- }
- }
- void asCReader::ReadObjectProperty(asCObjectType *ot)
- {
- asCString name;
- ReadString(&name);
- asCDataType dt;
- ReadDataType(&dt);
- int flags = ReadEncodedUInt();
- bool isPrivate = (flags & 1) ? true : false;
- bool isProtected = (flags & 2) ? true : false;
- bool isInherited = (flags & 4) ? true : false;
- // TODO: shared: If the type is shared and pre-existing, we should just
- // validate that the loaded methods match the original
- if( !existingShared.MoveTo(0, ot) )
- ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited);
- }
- void asCReader::ReadDataType(asCDataType *dt)
- {
- // Check if this is a previously used type
- asUINT idx = ReadEncodedUInt();
- if( idx != 0 )
- {
- // Get the datatype from the cache
- *dt = savedDataTypes[idx-1];
- return;
- }
- // Read the type definition
- eTokenType tokenType = (eTokenType)ReadEncodedUInt();
- // Reserve a spot in the savedDataTypes
- asUINT saveSlot = savedDataTypes.GetLength();
- savedDataTypes.PushLast(asCDataType());
- // Read the datatype for the first time
- asCTypeInfo *ti = 0;
- if( tokenType == ttIdentifier )
- ti = ReadTypeInfo();
- // Read type flags as a bitmask
- // Endian-safe code
- bool isObjectHandle, isHandleToConst, isReference, isReadOnly;
- char b = 0;
- ReadData(&b, 1);
- LOAD_FROM_BIT(isObjectHandle, b, 0);
- LOAD_FROM_BIT(isHandleToConst, b, 1);
- LOAD_FROM_BIT(isReference, b, 2);
- LOAD_FROM_BIT(isReadOnly, b, 3);
- if( tokenType == ttIdentifier )
- *dt = asCDataType::CreateType(ti, false);
- else
- *dt = asCDataType::CreatePrimitive(tokenType, false);
- if( isObjectHandle )
- {
- dt->MakeReadOnly(isHandleToConst ? true : false);
- // Here we must allow a scoped type to be a handle
- // e.g. if the datatype is for a system function
- dt->MakeHandle(true, true);
- }
- dt->MakeReadOnly(isReadOnly ? true : false);
- dt->MakeReference(isReference ? true : false);
- // Update the previously saved slot
- savedDataTypes[saveSlot] = *dt;
- }
- asCTypeInfo* asCReader::ReadTypeInfo()
- {
- asCTypeInfo *ot = 0;
- char ch;
- ReadData(&ch, 1);
- if( ch == 'a' )
- {
- // Read the name of the template type
- asCString typeName, ns;
- ReadString(&typeName);
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
- asCObjectType *tmpl = CastToObjectType(tmp);
- if( tmpl == 0 )
- {
- asCString str;
- str.Format(TXT_TEMPLATE_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- asUINT numSubTypes = SanityCheck(ReadEncodedUInt(), 100);
- asCArray<asCDataType> subTypes;
- for( asUINT n = 0; n < numSubTypes; n++ )
- {
- ReadData(&ch, 1);
- if( ch == 's' )
- {
- asCDataType dt;
- ReadDataType(&dt);
- subTypes.PushLast(dt);
- }
- else
- {
- eTokenType tokenType = (eTokenType)ReadEncodedUInt();
- asCDataType dt = asCDataType::CreatePrimitive(tokenType, false);
- subTypes.PushLast(dt);
- }
- }
- // Return the actual template if the subtypes are the template's dummy types
- if( tmpl->templateSubTypes == subTypes )
- ot = tmpl;
- else
- {
- // Get the template instance type based on the loaded subtypes
- ot = engine->GetTemplateInstanceType(tmpl, subTypes, module);
- }
- if( ot == 0 )
- {
- // Show all subtypes in error message
- asCString sub = subTypes[0].Format(nameSpace);
- for( asUINT n = 1; n < subTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += subTypes[n].Format(nameSpace);
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, typeName.AddressOf(), sub.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( ch == 'l' )
- {
- asCObjectType *st = CastToObjectType(ReadTypeInfo());
- if( st == 0 || st->beh.listFactory == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- ot = engine->GetListPatternType(st->beh.listFactory);
- }
- else if( ch == 's' )
- {
- // Read the name of the template subtype
- asCString typeName;
- ReadString(&typeName);
- // Find the template subtype
- ot = 0;
- for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ )
- {
- if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName )
- {
- ot = engine->templateSubTypes[n];
- break;
- }
- }
- if( ot == 0 )
- {
- asCString str;
- str.Format(TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( ch == 'o' )
- {
- // Read the object type name
- asCString typeName, ns;
- ReadString(&typeName);
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" )
- {
- // Find the object type
- ot = module->GetType(typeName.AddressOf(), nameSpace);
- if (!ot)
- ot = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
- if( ot == 0 )
- {
- asCString str;
- str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( typeName == "$obj" )
- {
- ot = &engine->scriptTypeBehaviours;
- }
- else if( typeName == "$func" )
- {
- ot = &engine->functionBehaviours;
- }
- else
- asASSERT( false );
- }
- else if (ch == 'c')
- {
- // Read the object type name
- asCString typeName, ns;
- ReadString(&typeName);
- // Read the parent class
- asCObjectType *parentClass = CastToObjectType(ReadTypeInfo());
- if (parentClass == 0)
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- // Find the child type in the parentClass
- for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++)
- {
- if (parentClass->childFuncDefs[n]->name == typeName)
- ot = parentClass->childFuncDefs[n];
- }
- if (ot == 0)
- {
- asCString str;
- str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else
- {
- // No object type
- asASSERT( ch == '\0' || error );
- ot = 0;
- }
- return ot;
- }
- void asCReader::ReadByteCode(asCScriptFunction *func)
- {
- asASSERT( func->scriptData );
- // Read number of instructions
- asUINT total, numInstructions;
- total = numInstructions = SanityCheck(ReadEncodedUInt(), 1000000);
- // Reserve some space for the instructions
- func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false);
- asUINT pos = 0;
- while( numInstructions )
- {
- asBYTE b;
- ReadData(&b, 1);
- // Allocate the space for the instruction
- asUINT len = asBCTypeSize[asBCInfo[b].type];
- asUINT newSize = asUINT(func->scriptData->byteCode.GetLength()) + len;
- if( func->scriptData->byteCode.GetCapacity() < newSize )
- {
- // Determine the average size of the loaded instructions and re-estimate the final size
- asUINT size = asUINT(float(newSize) / (total - numInstructions) * total) + 1;
- func->scriptData->byteCode.AllocateNoConstruct(size, true);
- }
- if( !func->scriptData->byteCode.SetLengthNoConstruct(newSize) )
- {
- // Out of memory
- error = true;
- return;
- }
- asDWORD *bc = func->scriptData->byteCode.AddressOf() + pos;
- pos += len;
- switch( asBCInfo[b].type )
- {
- case asBCTYPE_NO_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- }
- break;
- case asBCTYPE_W_ARG:
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- }
- break;
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the word argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the dword argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the first argument
- *bc++ = ReadEncodedUInt();
- // Read the second argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- // Read the third argument
- w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- case asBCTYPE_wW_W_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- bc++;
- }
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- bc++;
- // Read the third argument
- asDWORD dw = ReadEncodedUInt();
- *bc++ = dw;
- }
- break;
- case asBCTYPE_QW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- }
- break;
- case asBCTYPE_QW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the first argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- // Read the second argument
- asDWORD dw = ReadEncodedUInt();
- *bc++ = dw;
- }
- break;
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_wW_QW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- }
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the 1st argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the 2nd argument
- *bc++ = ReadEncodedUInt();
- // Read the 3rd argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- default:
- {
- // This should never happen
- asASSERT(false);
- // Read the next 3 bytes
- asDWORD c; asBYTE t;
- #if defined(AS_BIG_ENDIAN)
- c = b << 24;
- ReadData(&t, 1); c += t << 16;
- ReadData(&t, 1); c += t << 8;
- ReadData(&t, 1); c += t;
- #else
- c = b;
- ReadData(&t, 1); c += t << 8;
- ReadData(&t, 1); c += t << 16;
- ReadData(&t, 1); c += t << 24;
- #endif
- *bc++ = c;
- c = *(asBYTE*)&c;
- // Read the bc as is
- for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ )
- ReadData(&*bc++, 4);
- }
- }
- numInstructions--;
- }
- // Correct the final size in case we over-estimated it
- func->scriptData->byteCode.SetLengthNoConstruct(pos);
- }
- void asCReader::ReadUsedTypeIds()
- {
- TimeIt("asCReader::ReadUsedTypeIds");
- asUINT count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedTypeIds.Allocate(count, false);
- for( asUINT n = 0; n < count; n++ )
- {
- asCDataType dt;
- ReadDataType(&dt);
- usedTypeIds.PushLast(engine->GetTypeIdFromDataType(dt));
- }
- }
- void asCReader::ReadUsedGlobalProps()
- {
- TimeIt("asCReader::ReadUsedGlobalProps");
- int c = SanityCheck(ReadEncodedUInt(), 1000000);
- usedGlobalProperties.Allocate(c, false);
- for( int n = 0; n < c; n++ )
- {
- asCString name, ns;
- asCDataType type;
- char moduleProp;
- ReadString(&name);
- ReadString(&ns);
- ReadDataType(&type);
- ReadData(&moduleProp, 1);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- // Find the real property
- asCGlobalProperty *globProp = 0;
- if( moduleProp )
- globProp = module->m_scriptGlobals.GetFirst(nameSpace, name);
- else
- globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name);
- void *prop = 0;
- if( globProp && globProp->type == type )
- prop = globProp->GetAddressOfValue();
- usedGlobalProperties.PushLast(prop);
- if( prop == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- void asCReader::ReadUsedObjectProps()
- {
- TimeIt("asCReader::ReadUsedObjectProps");
- asUINT c = SanityCheck(ReadEncodedUInt(), 1000000);
- usedObjectProperties.SetLength(c);
- for( asUINT n = 0; n < c; n++ )
- {
- asCObjectType *objType = CastToObjectType(ReadTypeInfo());
- if( objType == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- asCString name;
- ReadString(&name);
- // Find the property
- bool found = false;
- for( asUINT p = 0; p < objType->properties.GetLength(); p++ )
- {
- if( objType->properties[p]->name == name )
- {
- usedObjectProperties[n].objType = objType;
- usedObjectProperties[n].prop = objType->properties[p];
- found = true;
- break;
- }
- }
- if( !found )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- short asCReader::FindObjectPropOffset(asWORD index)
- {
- static asCObjectProperty *lastCompositeProp = 0;
- if (lastCompositeProp)
- {
- if (index != 0)
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- short offset = (short)lastCompositeProp->byteOffset;
- lastCompositeProp = 0;
- return offset;
- }
- if( index >= usedObjectProperties.GetLength() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect)
- {
- lastCompositeProp = usedObjectProperties[index].prop;
- return (short)lastCompositeProp->compositeOffset;
- }
- return (short)usedObjectProperties[index].prop->byteOffset;
- }
- asCScriptFunction *asCReader::FindFunction(int idx)
- {
- if( idx >= 0 && idx < (int)usedFunctions.GetLength() )
- return usedFunctions[idx];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- void asCReader::TranslateFunction(asCScriptFunction *func)
- {
- // Skip this if the function is part of an pre-existing shared object
- if( dontTranslate.MoveTo(0, func) ) return;
- asASSERT( func->scriptData );
- // Pre-compute the size of each instruction in order to translate jump offsets
- asUINT n;
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
- asCArray<asUINT> bcSizes(bcLength);
- asCArray<asUINT> instructionNbrToPos(bcLength);
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- asUINT size = asBCTypeSize[asBCInfo[c].type];
- if( size == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- bcSizes.PushLast(size);
- instructionNbrToPos.PushLast(n);
- n += size;
- }
- asUINT bcNum = 0;
- for( n = 0; n < bcLength; bcNum++ )
- {
- int c = *(asBYTE*)&bc[n];
- if( c == asBC_REFCPY ||
- c == asBC_RefCpyV ||
- c == asBC_OBJTYPE )
- {
- // Translate the index to the true object type
- asPWORD *ot = (asPWORD*)&bc[n+1];
- *(asCObjectType**)ot = CastToObjectType(FindType(int(*ot)));
- }
- else if( c == asBC_TYPEID ||
- c == asBC_Cast )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- }
- else if( c == asBC_ADDSi ||
- c == asBC_LoadThisR )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- // Translate the prop index into the property offset
- *(((short*)&bc[n])+1) = FindObjectPropOffset(*(((short*)&bc[n])+1));
- }
- else if( c == asBC_LoadRObjR ||
- c == asBC_LoadVObjR )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+2];
- *tid = FindTypeId(*tid);
- asCObjectType *ot = engine->GetObjectTypeFromTypeId(*tid);
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- // List patterns have a different way of adjusting the offsets
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- *(((short*)&bc[n])+2) = (short)listAdj->AdjustOffset(*(((short*)&bc[n])+2));
- }
- else
- {
- // Translate the prop index into the property offset
- *(((short*)&bc[n])+2) = FindObjectPropOffset(*(((short*)&bc[n])+2));
- }
- }
- else if( c == asBC_COPY )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- // COPY is used to copy POD types that don't have the opAssign method. It is
- // also used to copy references to scoped types during variable initializations.
- // Update the number of dwords to copy as it may be different on the target platform
- if( (*tid) & asTYPEID_OBJHANDLE )
- {
- // It is the actual reference that is being copied, not the object itself
- asBC_SWORDARG0(&bc[n]) = AS_PTR_SIZE;
- }
- else
- {
- asCDataType dt = engine->GetDataTypeFromTypeId(*tid);
- if( !dt.IsValid() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- else
- asBC_SWORDARG0(&bc[n]) = (short)dt.GetSizeInMemoryDWords();
- }
- }
- else if( c == asBC_RET )
- {
- // Determine the correct amount of DWORDs to pop
- asWORD dw = (asWORD)func->GetSpaceNeededForArguments();
- if( func->DoesReturnOnStack() ) dw += AS_PTR_SIZE;
- if( func->objectType ) dw += AS_PTR_SIZE;
- asBC_WORDARG0(&bc[n]) = dw;
- }
- else if( c == asBC_CALL ||
- c == asBC_CALLINTF ||
- c == asBC_CALLSYS ||
- c == asBC_Thiscall1 )
- {
- // Translate the index to the func id
- int *fid = (int*)&bc[n+1];
- asCScriptFunction *f = FindFunction(*fid);
- if( f )
- *fid = f->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else if( c == asBC_FuncPtr )
- {
- // Translate the index to the func pointer
- asPWORD *fid = (asPWORD*)&bc[n+1];
- *fid = (asPWORD)FindFunction(int(*fid));
- }
- else if( c == asBC_ALLOC )
- {
- // Translate the index to the true object type
- asPWORD *arg = (asPWORD*)&bc[n+1];
- *(asCObjectType**)arg = CastToObjectType(FindType(int(*arg)));
- // The constructor function id must be translated, unless it is zero
- int *fid = (int*)&bc[n+1+AS_PTR_SIZE];
- if( *fid != 0 )
- {
- // Subtract 1 from the id, as it was incremented during the writing
- asCScriptFunction *f = FindFunction(*fid-1);
- if( f )
- *fid = f->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- else if( c == asBC_STR )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- else if( c == asBC_CALLBND )
- {
- // Translate the function id
- asUINT *fid = (asUINT*)&bc[n+1];
- if( *fid < module->m_bindInformations.GetLength() )
- {
- sBindInfo *bi = module->m_bindInformations[*fid];
- if( bi )
- *fid = bi->importedFunctionSignature->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else if( c == asBC_PGA ||
- c == asBC_PshGPtr ||
- c == asBC_LDG ||
- c == asBC_PshG4 ||
- c == asBC_LdGRdR4 ||
- c == asBC_CpyGtoV4 ||
- c == asBC_CpyVtoG4 ||
- c == asBC_SetG4 )
- {
- // Translate the index to pointer
- asPWORD *index = (asPWORD*)&bc[n + 1];
- if ((*index & 1))
- {
- if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength())
- *(void**)index = usedGlobalProperties[asUINT(*index)>>1];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else
- {
- // Only PGA and PshGPtr can hold string constants
- asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
- if ((asUINT(*index)>>1) < usedStringConstants.GetLength())
- *(void**)index = usedStringConstants[asUINT(*index)>>1];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- else if( c == asBC_JMP ||
- c == asBC_JZ ||
- c == asBC_JNZ ||
- c == asBC_JLowZ ||
- c == asBC_JLowNZ ||
- c == asBC_JS ||
- c == asBC_JNS ||
- c == asBC_JP ||
- c == asBC_JNP ) // The JMPP instruction doesn't need modification
- {
- // Get the offset
- int offset = int(bc[n+1]);
- // Count the instruction sizes to the destination instruction
- int size = 0;
- if( offset >= 0 )
- // If moving ahead, then start from next instruction
- for( asUINT num = bcNum+1; offset-- > 0; num++ )
- size += bcSizes[num];
- else
- // If moving backwards, then start at current instruction
- for( asUINT num = bcNum; offset++ < 0; num-- )
- size -= bcSizes[num];
- // The size is dword offset
- bc[n+1] = size;
- }
- else if( c == asBC_AllocMem )
- {
- // The size of the allocated memory is only known after all the elements has been seen.
- // This helper class will collect this information and adjust the size when the
- // corresponding asBC_FREE is encountered
- // The adjuster also needs to know the list type so it can know the type of the elements
- asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n])));
- listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot));
- }
- else if( c == asBC_FREE )
- {
- // Translate the index to the true object type
- asPWORD *pot = (asPWORD*)&bc[n+1];
- *(asCObjectType**)pot = CastToObjectType(FindType(int(*pot)));
- asCObjectType *ot = *(asCObjectType**)pot;
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- if( listAdjusters.GetLength() == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- // Finalize the adjustment of the list buffer that was initiated with asBC_AllocMem
- SListAdjuster *list = listAdjusters.PopLast();
- list->AdjustAllocMem();
- asDELETE(list, SListAdjuster);
- }
- }
- else if( c == asBC_SetListSize )
- {
- // Adjust the offset in the list where the size is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- // Inform the list adjuster how many values will be repeated
- listAdj->SetRepeatCount(bc[n+2]);
- }
- else if( c == asBC_PshListElmnt )
- {
- // Adjust the offset in the list where the size is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- }
- else if( c == asBC_SetListType )
- {
- // Adjust the offset in the list where the typeid is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- // Translate the type id
- bc[n+2] = FindTypeId(bc[n+2]);
- // Inform the list adjuster the type id of the next element
- listAdj->SetNextType(bc[n+2]);
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- // Calculate the stack adjustments
- CalculateAdjustmentByPos(func);
- // Adjust all variable positions in the bytecode
- bc = func->scriptData->byteCode.AddressOf();
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_wW_W_ARG:
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- case asBCTYPE_rW_DW_DW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_rW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
- asBC_SWORDARG2(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG2(&bc[n]));
- }
- break;
- default:
- // The other types don't treat variables so won't be modified
- break;
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- // Adjust the space needed for local variables
- func->scriptData->variableSpace = AdjustStackPosition(func->scriptData->variableSpace);
- // Adjust the variable information. This will be used during the adjustment below
- for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
- {
- func->scriptData->variables[n]->declaredAtProgramPos = instructionNbrToPos[func->scriptData->variables[n]->declaredAtProgramPos];
- func->scriptData->variables[n]->stackOffset = AdjustStackPosition(func->scriptData->variables[n]->stackOffset);
- }
- // objVariablePos
- for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
- func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]);
- // Adjust the get offsets. This must be done in the second iteration because
- // it relies on the function ids and variable position already being correct in the
- // bytecodes that come after the GET instructions.
- // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions
- // on a stack, and then when a call instruction is found update all of them.
- // This will also make the AdjustGetOffset() function quicker as it can
- // receive the called function directly instead of having to search for it.
- bc = func->scriptData->byteCode.AddressOf();
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- if( c == asBC_GETREF ||
- c == asBC_GETOBJ ||
- c == asBC_GETOBJREF ||
- c == asBC_ChkNullS )
- {
- asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n);
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- for( n = 0; n < func->scriptData->objVariableInfo.GetLength(); n++ )
- {
- // The program position must be adjusted as it is stored in number of instructions
- func->scriptData->objVariableInfo[n].programPos = instructionNbrToPos[func->scriptData->objVariableInfo[n].programPos];
- func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset);
- }
- for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
- {
- func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos];
- func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos];
- }
- // The program position (every even number) needs to be adjusted
- // for the line numbers to be in number of dwords instead of number of instructions
- for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 )
- func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]];
- for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 )
- func->scriptData->sectionIdxs[n] = instructionNbrToPos[func->scriptData->sectionIdxs[n]];
- CalculateStackNeeded(func);
- }
- asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) :
- reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
- {
- asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) );
- // Find the first expected value in the list
- asSListPatternNode *node = patternType->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
- asASSERT( node && node->type == asLPT_START );
- patternNode = node->next;
- }
- int asCReader::SListAdjuster::AdjustOffset(int offset)
- {
- if( offset < lastOffset )
- {
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- // If it is the same offset being accessed again, just return the same adjusted value
- if( lastOffset == offset )
- return lastAdjustedOffset;
- lastOffset = offset;
- lastAdjustedOffset = maxOffset;
- // What is being expected at this position?
- if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
- {
- // Align the offset to 4 bytes boundary
- if( maxOffset & 0x3 )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
- maxOffset += 4;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- else if( patternNode->type == asLPT_TYPE )
- {
- const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
- if( dt.GetTokenType() == ttQuestion )
- {
- if( nextTypeId != -1 )
- {
- if( repeatCount > 0 )
- repeatCount--;
- asCDataType nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId);
- asUINT size;
- if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = nextdt.GetSizeInMemoryBytes();
- // Align the offset to 4 bytes boundary
- if( size >= 4 && (maxOffset & 0x3) )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextTypeId = -1;
- maxOffset += size;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- else
- {
- // Align the offset to 4 bytes boundary
- if( maxOffset & 0x3 )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // The first adjustment is for the typeId
- maxOffset += 4;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- }
- else
- {
- // Determine the size of the element
- asUINT size;
- if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = dt.GetSizeInMemoryBytes();
- // If values are skipped, the offset needs to be incremented
- while( nextOffset <= offset )
- {
- if( repeatCount > 0 )
- repeatCount--;
- // Align the offset to 4 bytes boundary
- if( size >= 4 && (maxOffset & 0x3) )
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- nextOffset += 1;
- maxOffset += size;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- }
- else if( patternNode->type == asLPT_START )
- {
- if( repeatCount > 0 )
- repeatCount--;
- SInfo info = {repeatCount, patternNode};
- stack.PushLast(info);
- repeatCount = 0;
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset);
- }
- else if( patternNode->type == asLPT_END )
- {
- if( stack.GetLength() == 0 )
- {
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- SInfo info = stack.PopLast();
- repeatCount = info.repeatCount;
- if( repeatCount )
- patternNode = info.startNode;
- else
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset);
- }
- else
- {
- // Something is wrong with the pattern list declaration
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- UNREACHABLE_RETURN;
- }
- void asCReader::SListAdjuster::SetRepeatCount(asUINT rc)
- {
- // Make sure the list is expecting a repeat at this location
- asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
- // Now move to the next patternNode
- patternNode = patternNode->next;
- repeatCount = rc;
- }
- void asCReader::SListAdjuster::AdjustAllocMem()
- {
- allocMemBC[1] = maxOffset;
- }
- void asCReader::SListAdjuster::SetNextType(int typeId)
- {
- asASSERT( nextTypeId == -1 );
- nextTypeId = typeId;
- }
- void asCReader::CalculateStackNeeded(asCScriptFunction *func)
- {
- asASSERT( func->scriptData );
- int largestStackUsed = 0;
- // Clear the known stack size for each bytecode
- asCArray<int> stackSize;
- stackSize.SetLength(func->scriptData->byteCode.GetLength());
- memset(&stackSize[0], -1, stackSize.GetLength()*4);
- // Add the first instruction to the list of unchecked code
- // paths and set the stack size at that instruction to variableSpace
- asCArray<asUINT> paths;
- paths.PushLast(0);
- stackSize[0] = func->scriptData->variableSpace;
- // Go through each of the code paths
- for( asUINT p = 0; p < paths.GetLength(); ++p )
- {
- asUINT pos = paths[p];
- int currStackSize = stackSize[pos];
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos];
- if( bc == asBC_RET )
- continue;
- // Determine the change in stack size for this instruction
- int stackInc = asBCInfo[bc].stackInc;
- if( stackInc == 0xFFFF )
- {
- // Determine the true delta from the instruction arguments
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLBND ||
- bc == asBC_ALLOC ||
- bc == asBC_CALLINTF ||
- bc == asBC_CallPtr )
- {
- asCScriptFunction *called = GetCalledFunction(func, pos);
- if( called )
- {
- stackInc = -called->GetSpaceNeededForArguments();
- if( called->objectType )
- stackInc -= AS_PTR_SIZE;
- if( called->DoesReturnOnStack() )
- stackInc -= AS_PTR_SIZE;
- }
- else
- {
- // It is an allocation for an object without a constructor
- asASSERT( bc == asBC_ALLOC );
- stackInc = -AS_PTR_SIZE;
- }
- }
- }
- currStackSize += stackInc;
- asASSERT( currStackSize >= 0 );
- if( currStackSize > largestStackUsed )
- largestStackUsed = currStackSize;
- if( bc == asBC_JMP )
- {
- // Find the label that we should jump to
- int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
- pos += 2 + offset;
- // Add the destination as a new path
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- else if( bc == asBC_JZ || bc == asBC_JNZ ||
- bc == asBC_JLowZ || bc == asBC_JLowNZ ||
- bc == asBC_JS || bc == asBC_JNS ||
- bc == asBC_JP || bc == asBC_JNP )
- {
- // Find the label that is being jumped to
- int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
- // Add both paths to the code paths
- pos += 2;
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- pos += offset;
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- else if( bc == asBC_JMPP )
- {
- pos++;
- // Add all subsequent JMP instructions to the path
- while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP )
- {
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- pos += 2;
- }
- continue;
- }
- else
- {
- // Add next instruction to the paths
- pos += asBCTypeSize[asBCInfo[bc].type];
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- }
- func->scriptData->stackNeeded = largestStackUsed;
- }
- void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func)
- {
- // Adjust the offset of all negative variables (parameters) as
- // all pointers have been stored as having a size of 1 dword
- asUINT n;
- asCArray<int> adjustments;
- asUINT offset = 0;
- if( func->objectType )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- if( func->DoesReturnOnStack() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- for( n = 0; n < func->parameterTypes.GetLength(); n++ )
- {
- if( !func->parameterTypes[n].IsPrimitive() ||
- func->parameterTypes[n].IsReference() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- else
- {
- asASSERT( func->parameterTypes[n].IsPrimitive() );
- offset += func->parameterTypes[n].GetSizeOnStackDWords();
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustNegativeStackByPos.SetLength(offset);
- memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
- adjustNegativeStackByPos[i] += adjust;
- }
- // The bytecode has been stored as if all object variables take up only 1 dword.
- // It is necessary to adjust to the size according to the current platform.
- adjustments.SetLength(0);
- int highestPos = 0;
- for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- // objVariableTypes is null if the type is a null pointer
- if( func->scriptData->objVariableTypes[n] &&
- (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
- n >= func->scriptData->objVariablesOnHeap )
- {
- size = func->scriptData->objVariableTypes[n]->GetSize();
- if( size < 4 )
- size = 1;
- else
- size /= 4;
- }
- // Check if type has a different size than stored
- if( size > 1 )
- {
- if( func->scriptData->objVariablePos[n] > highestPos )
- highestPos = func->scriptData->objVariablePos[n];
- adjustments.PushLast(func->scriptData->objVariablePos[n]);
- adjustments.PushLast(size-1);
- }
- }
- // Count position 0 too
- adjustByPos.SetLength(highestPos+1);
- memset(adjustByPos.AddressOf(), 0, adjustByPos.GetLength()*sizeof(int));
- // Build look-up table with the adjustments for each stack position
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos; i < adjustByPos.GetLength(); i++ )
- adjustByPos[i] += adjust;
- }
- }
- int asCReader::AdjustStackPosition(int pos)
- {
- if( pos >= (int)adjustByPos.GetLength() )
- {
- // It can be higher for primitives allocated on top of highest object variable
- if( adjustByPos.GetLength() )
- pos += (short)adjustByPos[adjustByPos.GetLength()-1];
- }
- else if( pos >= 0 )
- pos += (short)adjustByPos[pos];
- else if( -pos >= (int)adjustNegativeStackByPos.GetLength() )
- Error(TXT_INVALID_BYTECODE_d);
- else
- pos += (short)adjustNegativeStackByPos[-pos];
- return pos;
- }
- asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD programPos)
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos];
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLINTF )
- {
- // Find the function from the function id in bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]);
- return engine->scriptFunctions[funcId];
- }
- else if( bc == asBC_ALLOC )
- {
- // Find the function from the function id in the bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos+AS_PTR_SIZE]);
- return engine->scriptFunctions[funcId];
- }
- else if( bc == asBC_CALLBND )
- {
- // Find the function from the engine's bind array
- int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]);
- return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
- }
- else if( bc == asBC_CallPtr )
- {
- asUINT v;
- int var = asBC_SWORDARG0(&func->scriptData->byteCode[programPos]);
- // Find the funcdef from the local variable
- for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
- if( func->scriptData->objVariablePos[v] == var )
- return CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef;
- // Look in parameters
- int paramPos = 0;
- if( func->objectType )
- paramPos -= AS_PTR_SIZE;
- if( func->DoesReturnOnStack() )
- paramPos -= AS_PTR_SIZE;
- for( v = 0; v < func->parameterTypes.GetLength(); v++ )
- {
- if (var == paramPos)
- {
- if (func->parameterTypes[v].IsFuncdef())
- return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
- else
- {
- error = true;
- return 0;
- }
- }
- paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
- }
- }
- return 0;
- }
- int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
- {
- // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
- // the function can remember where it found the function and check if the programPos is still valid
- // Get offset 0 doesn't need adjustment
- if( offset == 0 ) return 0;
- bool bcAlloc = false;
- // Find out which function that will be called
- asCScriptFunction *calledFunc = 0;
- int stackDelta = 0;
- for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); )
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLINTF ||
- bc == asBC_ALLOC ||
- bc == asBC_CALLBND ||
- bc == asBC_CallPtr )
- {
- // The alloc instruction allocates the object memory
- // so it doesn't take the this pointer as input
- if (bc == asBC_ALLOC)
- bcAlloc = true;
- calledFunc = GetCalledFunction(func, n);
- break;
- }
- else if( bc == asBC_REFCPY ||
- bc == asBC_COPY )
- {
- // In this case we know there is only 1 pointer on the stack above
- asASSERT( offset == 1 );
- return offset - (1 - AS_PTR_SIZE);
- }
- // Keep track of the stack size between the
- // instruction that needs to be adjusted and the call
- stackDelta += asBCInfo[bc].stackInc;
- n += asBCTypeSize[asBCInfo[bc].type];
- }
- if( calledFunc == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return offset;
- }
- // Count the number of pointers pushed on the stack above the
- // current offset, and then adjust the offset accordingly
- asUINT numPtrs = 0;
- int currOffset = -stackDelta;
- if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- }
- for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
- {
- if( offset <= currOffset ) break;
- if( !calledFunc->parameterTypes[p].IsPrimitive() ||
- calledFunc->parameterTypes[p].IsReference() )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- // The variable arg ? has an additiona 32bit integer with the typeid
- if( calledFunc->parameterTypes[p].IsAnyType() )
- currOffset += 1;
- }
- else
- {
- // Enums or built-in primitives are passed by value
- asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
- currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
- }
- }
- return offset - numPtrs * (1 - AS_PTR_SIZE);
- }
- int asCReader::FindTypeId(int idx)
- {
- if( idx >= 0 && idx < (int)usedTypeIds.GetLength() )
- return usedTypeIds[idx];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- asCTypeInfo *asCReader::FindType(int idx)
- {
- if( idx < 0 || idx >= (int)usedTypes.GetLength() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- return usedTypes[idx];
- }
- #ifndef AS_NO_COMPILER
- asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug)
- : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0)
- {
- }
- int asCWriter::Error(const char *msg)
- {
- // Don't write if it has already been reported an error earlier
- if (!error)
- {
- asCString str;
- str.Format(msg, bytesWritten);
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- error = true;
- }
- return asERROR;
- }
- int asCWriter::WriteData(const void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- int ret = 0;
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; ret >= 0 && n < size; n++ )
- ret = stream->Write(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; ret >= 0 && n >= 0; n-- )
- ret = stream->Write(((asBYTE*)data)+n, 1);
- #endif
- if (ret < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- bytesWritten += size;
- return ret;
- }
- int asCWriter::Write()
- {
- TimeIt("asCWriter::Write");
- unsigned long i, count;
- // Store everything in the same order that the builder parses scripts
- // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway
- // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway
- // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway
- // Write the flag as 1byte even on platforms with 4byte booleans
- WriteEncodedInt64(stripDebugInfo ? 1 : 0);
- // Store enums
- {
- TimeIt("store enums");
- count = (asUINT)module->m_enumTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteTypeDeclaration(module->m_enumTypes[i], 1);
- WriteTypeDeclaration(module->m_enumTypes[i], 2);
- }
- }
- // Store type declarations first
- {
- TimeIt("type declarations");
- count = (asUINT)module->m_classTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- // Store only the name of the class/interface types
- WriteTypeDeclaration(module->m_classTypes[i], 1);
- }
- }
- // Store func defs
- {
- TimeIt("func defs");
- count = (asUINT)module->m_funcDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- WriteFunction(module->m_funcDefs[i]->funcdef);
- }
- // Now store all interface methods
- {
- TimeIt("interface methods");
- count = (asUINT)module->m_classTypes.GetLength();
- for( i = 0; i < count; i++ )
- {
- if( module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 2);
- }
- }
- // Then store the class methods and behaviours
- {
- TimeIt("class methods and behaviours");
- for( i = 0; i < count; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 2);
- }
- }
- // Then store the class properties
- {
- TimeIt("class properties");
- for( i = 0; i < count; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 3);
- }
- }
- // Store typedefs
- {
- TimeIt("type defs");
- count = (asUINT)module->m_typeDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteTypeDeclaration(module->m_typeDefs[i], 1);
- WriteTypeDeclaration(module->m_typeDefs[i], 2);
- }
- }
- // scriptGlobals[]
- {
- TimeIt("script globals");
- count = (asUINT)module->m_scriptGlobals.GetSize();
- WriteEncodedInt64(count);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->m_scriptGlobals.List();
- for( ; it; it++ )
- WriteGlobalProperty(*it);
- }
- // scriptFunctions[]
- {
- TimeIt("scriptFunctions");
- count = 0;
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( module->m_scriptFunctions[i]->objectType == 0 )
- count++;
- WriteEncodedInt64(count);
- for( i = 0; i < module->m_scriptFunctions.GetLength(); ++i )
- if( module->m_scriptFunctions[i]->objectType == 0 )
- WriteFunction(module->m_scriptFunctions[i]);
- }
- // globalFunctions[]
- {
- TimeIt("globalFunctions");
- count = (int)module->m_globalFunctions.GetSize();
- asCSymbolTable<asCScriptFunction>::iterator funcIt = module->m_globalFunctions.List();
- WriteEncodedInt64(count);
- while( funcIt )
- {
- WriteFunction(*funcIt);
- funcIt++;
- }
- }
- // bindInformations[]
- {
- TimeIt("bindInformations");
- count = (asUINT)module->m_bindInformations.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- {
- WriteFunction(module->m_bindInformations[i]->importedFunctionSignature);
- WriteString(&module->m_bindInformations[i]->importFromModule);
- }
- }
- // usedTypes[]
- {
- TimeIt("usedTypes");
- count = (asUINT)usedTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- WriteTypeInfo(usedTypes[i]);
- }
- // usedTypeIds[]
- WriteUsedTypeIds();
- // usedFunctions[]
- WriteUsedFunctions();
- // usedGlobalProperties[]
- WriteUsedGlobalProps();
- // usedStringConstants[]
- WriteUsedStringConstants();
- // usedObjectProperties[]
- WriteUsedObjectProps();
- return error ? asERROR : asSUCCESS;
- }
- int asCWriter::FindStringConstantIndex(void *str)
- {
- asSMapNode<void*, int> *cursor = 0;
- if (stringToIndexMap.MoveTo(&cursor, str))
- return cursor->value;
- usedStringConstants.PushLast(str);
- int index = int(usedStringConstants.GetLength() - 1);
- stringToIndexMap.Insert(str, index);
- return index;
- }
- void asCWriter::WriteUsedStringConstants()
- {
- TimeIt("asCWriter::WriteUsedStringConstants");
- asUINT count = (asUINT)usedStringConstants.GetLength();
- WriteEncodedInt64(count);
- asCString str;
- for (asUINT i = 0; i < count; ++i)
- {
- asUINT length;
- engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length);
- str.SetLength(length);
- engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length);
- WriteString(&str);
- }
- }
- void asCWriter::WriteUsedFunctions()
- {
- TimeIt("asCWriter::WriteUsedFunctions");
- asUINT count = (asUINT)usedFunctions.GetLength();
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- char c;
- // Write enough data to be able to uniquely identify the function upon load
- asCScriptFunction *func = usedFunctions[n];
- if(func)
- {
- // Is the function from the module or the application?
- c = func->module ? 'm' : 'a';
- // Functions and methods that are shared should be stored as 's' as the bytecode
- // may be imported from other modules (even if the current module have received ownership)
- if (c == 'm' && func->IsShared() )
- c = 's';
- WriteData(&c, 1);
- WriteFunctionSignature(func);
- }
- else
- {
- // null function pointer
- c = 'n';
- WriteData(&c, 1);
- }
- }
- }
- void asCWriter::WriteFunctionSignature(asCScriptFunction *func)
- {
- asUINT i, count;
- WriteString(&func->name);
- if( func->name == DELEGATE_FACTORY )
- {
- // It's not necessary to write anything else
- return;
- }
- WriteDataType(&func->returnType);
- count = (asUINT)func->parameterTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- WriteDataType(&func->parameterTypes[i]);
- // Only write the inout flags if any of them are set
- // If the number of parameters is 0, then no need to save this
- if (func->parameterTypes.GetLength() > 0)
- {
- count = 0;
- for (i = asUINT(func->inOutFlags.GetLength()); i > 0; i--)
- if (func->inOutFlags[i - 1] != asTM_NONE)
- {
- count = i;
- break;
- }
- WriteEncodedInt64(count);
- for (i = 0; i < count; ++i)
- WriteEncodedInt64(func->inOutFlags[i]);
- }
- WriteEncodedInt64(func->funcType);
- // Write the default args, from last to first
- // If the number of parameters is 0, then no need to save this
- if (func->parameterTypes.GetLength() > 0)
- {
- count = 0;
- for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
- if (func->defaultArgs[i])
- count++;
- WriteEncodedInt64(count);
- for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
- if (func->defaultArgs[i])
- WriteString(func->defaultArgs[i]);
- }
- WriteTypeInfo(func->objectType);
- if( func->objectType )
- {
- asBYTE b = 0;
- b += func->IsReadOnly() ? 1 : 0;
- b += func->IsPrivate() ? 2 : 0;
- b += func->IsProtected() ? 4 : 0;
- WriteData(&b, 1);
- }
- else
- {
- if (func->funcType == asFUNC_FUNCDEF)
- {
- if (func->nameSpace)
- {
- // This funcdef was declared as global entity
- asBYTE b = 'n';
- WriteData(&b, 1);
- WriteString(&func->nameSpace->name);
- }
- else
- {
- // This funcdef was declared as class member
- asBYTE b = 'o';
- WriteData(&b, 1);
- WriteTypeInfo(func->funcdefType->parentClass);
- }
- }
- else
- WriteString(&func->nameSpace->name);
- }
- }
- void asCWriter::WriteFunction(asCScriptFunction* func)
- {
- char c;
- // If there is no function, then store a null char
- if( func == 0 )
- {
- c = '\0';
- WriteData(&c, 1);
- return;
- }
- // First check if the function has been saved already
- for( asUINT f = 0; f < savedFunctions.GetLength(); f++ )
- {
- if( savedFunctions[f] == func )
- {
- c = 'r';
- WriteData(&c, 1);
- WriteEncodedInt64(f);
- return;
- }
- }
- // Keep a reference to the function in the list
- savedFunctions.PushLast(func);
- c = 'f';
- WriteData(&c, 1);
- asUINT i, count;
- WriteFunctionSignature(func);
- if( func->funcType == asFUNC_SCRIPT )
- {
- // Skip this for external shared entities
- if (module->m_externalTypes.IndexOf(func->objectType) >= 0)
- return;
- char bits = 0;
- bits += func->IsShared() ? 1 : 0;
- bits += func->dontCleanUpOnException ? 2 : 0;
- if (module->m_externalFunctions.IndexOf(func) >= 0)
- bits += 4;
- if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength())
- bits += 8;
- if (func->scriptData->tryCatchInfo.GetLength())
- bits += 16;
- bits += func->IsExplicit() ? 32 : 0;
- WriteData(&bits, 1);
- // For external shared functions the rest is not needed
- if (bits & 4)
- return;
- // Calculate the adjustment by position lookup table
- CalculateAdjustmentByPos(func);
- WriteByteCode(func);
- asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace);
- WriteEncodedInt64(varSpace);
- if (bits & 8)
- {
- count = (asUINT)func->scriptData->objVariablePos.GetLength();
- WriteEncodedInt64(count);
- for (i = 0; i < count; ++i)
- {
- WriteTypeInfo(func->scriptData->objVariableTypes[i]);
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i]));
- }
- if (count > 0)
- WriteEncodedInt64(func->scriptData->objVariablesOnHeap);
- WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength());
- for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i)
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]);
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset));
- WriteEncodedInt64(func->scriptData->objVariableInfo[i].option);
- }
- }
- if (bits & 16)
- {
- // Write info on try/catch blocks
- WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength());
- for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i)
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]);
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]);
- }
- }
- // The program position (every even number) needs to be adjusted
- // to be in number of instructions instead of DWORD offset
- if( !stripDebugInfo )
- {
- asUINT length = (asUINT)func->scriptData->lineNumbers.GetLength();
- WriteEncodedInt64(length);
- for( i = 0; i < length; ++i )
- {
- if( (i & 1) == 0 )
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->lineNumbers[i]]);
- else
- WriteEncodedInt64(func->scriptData->lineNumbers[i]);
- }
- // Write the array of script sections
- length = (asUINT)func->scriptData->sectionIdxs.GetLength();
- WriteEncodedInt64(length);
- for( i = 0; i < length; ++i )
- {
- if( (i & 1) == 0 )
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->sectionIdxs[i]]);
- else
- {
- if( func->scriptData->sectionIdxs[i] >= 0 )
- WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]);
- else
- {
- c = 0;
- WriteData(&c, 1);
- }
- }
- }
- }
- // Write the variable information
- if( !stripDebugInfo )
- {
- WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength());
- for( i = 0; i < func->scriptData->variables.GetLength(); i++ )
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]);
- // The stack position must be adjusted according to the pointer sizes
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->variables[i]->stackOffset));
- WriteString(&func->scriptData->variables[i]->name);
- WriteDataType(&func->scriptData->variables[i]->type);
- }
- }
- // Store script section name
- if( !stripDebugInfo )
- {
- if( func->scriptData->scriptSectionIdx >= 0 )
- WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]);
- else
- {
- c = 0;
- WriteData(&c, 1);
- }
- WriteEncodedInt64(func->scriptData->declaredAt);
- }
- // Store the parameter names
- if( !stripDebugInfo )
- {
- count = asUINT(func->parameterNames.GetLength());
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < count; n++ )
- WriteString(&func->parameterNames[n]);
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- // TODO: Do we really need to store this? It can probably be reconstructed by the reader
- WriteEncodedInt64(func->vfTableIdx);
- }
- else if( func->funcType == asFUNC_FUNCDEF )
- {
- char bits = 0;
- bits += func->IsShared() ? 1 : 0;
- if (module->m_externalTypes.IndexOf(func->funcdefType) >= 0)
- bits += 2;
- WriteData(&bits,1);
- }
- }
- void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase)
- {
- if( phase == 1 )
- {
- // name
- WriteString(&type->name);
- // flags
- WriteData(&type->flags, 4);
- // size
- // TODO: Do we really need to store this? The reader should be able to
- // determine the correct size from the object type's flags
- if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size > 0 )
- {
- // The size for script objects may vary from platform to platform so
- // only store 1 to diferentiate from interfaces that have size 0.
- WriteEncodedInt64(1);
- }
- else
- {
- // Enums, typedefs, and interfaces have fixed sizes independently
- // of platform so it is safe to serialize the size directly.
- WriteEncodedInt64(type->size);
- }
- // namespace
- WriteString(&type->nameSpace->name);
- // external shared flag
- if ((type->flags & asOBJ_SHARED))
- {
- char c = ' ';
- if (module->m_externalTypes.IndexOf(type) >= 0)
- c = 'e';
- WriteData(&c, 1);
- }
- }
- else if( phase == 2 )
- {
- // external shared types doesn't need to save this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- if(type->flags & asOBJ_ENUM )
- {
- // enumValues[]
- asCEnumType *t = CastToEnumType(type);
- int size = (int)t->enumValues.GetLength();
- WriteEncodedInt64(size);
- for( int n = 0; n < size; n++ )
- {
- WriteString(&t->enumValues[n]->name);
- WriteData(&t->enumValues[n]->value, 4);
- }
- }
- else if(type->flags & asOBJ_TYPEDEF )
- {
- asCTypedefType *td = CastToTypedefType(type);
- eTokenType t = td->aliasForType.GetTokenType();
- WriteEncodedInt64(t);
- }
- else
- {
- asCObjectType *t = CastToObjectType(type);
- WriteTypeInfo(t->derivedFrom);
- // interfaces[] / interfaceVFTOffsets[]
- // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those?
- int size = (asUINT)t->interfaces.GetLength();
- WriteEncodedInt64(size);
- asUINT n;
- asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() );
- for( n = 0; n < t->interfaces.GetLength(); n++ )
- {
- WriteTypeInfo(t->interfaces[n]);
- if( !t->IsInterface() )
- WriteEncodedInt64(t->interfaceVFTOffsets[n]);
- }
- // behaviours
- // TODO: Default behaviours should just be stored as a indicator
- // to avoid storing the actual function object
- if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
- {
- WriteFunction(engine->scriptFunctions[t->beh.destruct]);
- size = (int)t->beh.constructors.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < t->beh.constructors.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]);
- WriteFunction(engine->scriptFunctions[t->beh.factories[n]]);
- }
- }
- // methods[]
- // TODO: Avoid storing inherited methods in interfaces, as the reader
- // can add those directly from the base interface
- size = (int)t->methods.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < t->methods.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[t->methods[n]]);
- }
- // virtualFunctionTable[]
- // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader
- size = (int)t->virtualFunctionTable.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < (asUINT)size; n++ )
- {
- WriteFunction(t->virtualFunctionTable[n]);
- }
- }
- }
- else if( phase == 3 )
- {
- // external shared types doesn't need to save this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- // properties[]
- asCObjectType *t = CastToObjectType(type);
- // This is only done for object types
- asASSERT(t);
- asUINT size = (asUINT)t->properties.GetLength();
- WriteEncodedInt64(size);
- for (asUINT n = 0; n < t->properties.GetLength(); n++)
- {
- WriteObjectProperty(t->properties[n]);
- }
- }
- }
- void asCWriter::WriteEncodedInt64(asINT64 i)
- {
- asBYTE signBit = ( i & asINT64(1)<<63 ) ? 0x80 : 0;
- if( signBit ) i = -i;
- asBYTE b;
- if( i < (1<<6) )
- {
- b = (asBYTE)(signBit + i); WriteData(&b, 1);
- }
- else if( i < (1<<13) )
- {
- b = asBYTE(0x40 + signBit + (i >> 8)); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (1<<20) )
- {
- b = asBYTE(0x60 + signBit + (i >> 16)); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (1<<27) )
- {
- b = asBYTE(0x70 + signBit + (i >> 24)); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<34) )
- {
- b = asBYTE(0x78 + signBit + (i >> 32)); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<41) )
- {
- b = asBYTE(0x7C + signBit + (i >> 40)); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<48) )
- {
- b = asBYTE(0x7E + signBit + (i >> 48)); WriteData(&b, 1);
- b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else
- {
- b = asBYTE(0x7F + signBit); WriteData(&b, 1);
- b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 48) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- }
- void asCWriter::WriteString(asCString* str)
- {
- // First check if the string hasn't been saved already
- asSMapNode<asCString, int> *cursor = 0;
- if (stringToIdMap.MoveTo(&cursor, *str))
- {
- // Save a reference to the existing string
- // The lowest bit is set to 1 to indicate a reference
- WriteEncodedInt64(cursor->value*2+1);
- return;
- }
- // Save a new string
- // The lowest bit is set to 0 to indicate a new string
- asUINT len = (asUINT)str->GetLength();
- WriteEncodedInt64(len*2);
- if( len > 0 )
- {
- stream->Write(str->AddressOf(), (asUINT)len);
- bytesWritten += len;
- savedStrings.PushLast(*str);
- stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1);
- }
- }
- void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop)
- {
- // TODO: We might be able to avoid storing the name and type of the global
- // properties twice if we merge this with the WriteUsedGlobalProperties.
- WriteString(&prop->name);
- WriteString(&prop->nameSpace->name);
- WriteDataType(&prop->type);
- // Store the initialization function
- WriteFunction(prop->GetInitFunc());
- }
- void asCWriter::WriteObjectProperty(asCObjectProperty* prop)
- {
- WriteString(&prop->name);
- WriteDataType(&prop->type);
- int flags = 0;
- if( prop->isPrivate ) flags |= 1;
- if( prop->isProtected ) flags |= 2;
- if( prop->isInherited ) flags |= 4;
- WriteEncodedInt64(flags);
- }
- void asCWriter::WriteDataType(const asCDataType *dt)
- {
- // First check if the datatype has already been saved
- for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ )
- {
- if( *dt == savedDataTypes[n] )
- {
- WriteEncodedInt64(n+1);
- return;
- }
- }
- // Indicate a new type with a null byte
- asUINT c = 0;
- WriteEncodedInt64(c);
- // Save the new datatype
- savedDataTypes.PushLast(*dt);
- int t = dt->GetTokenType();
- WriteEncodedInt64(t);
- if( t == ttIdentifier )
- WriteTypeInfo(dt->GetTypeInfo());
- // Endianess safe bitmask
- char bits = 0;
- SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0);
- SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1);
- SAVE_TO_BIT(bits, dt->IsReference(), 2);
- SAVE_TO_BIT(bits, dt->IsReadOnly(), 3);
- WriteData(&bits, 1);
- }
- void asCWriter::WriteTypeInfo(asCTypeInfo* ti)
- {
- char ch;
- if( ti )
- {
- // Check for template instances/specializations
- asCObjectType *ot = CastToObjectType(ti);
- if( ot && ot->templateSubTypes.GetLength() )
- {
- // Check for list pattern type or template type
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- ch = 'l'; // list
- WriteData(&ch, 1);
- WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo());
- }
- else
- {
- ch = 'a'; // array
- WriteData(&ch, 1);
- WriteString(&ot->name);
- WriteString(&ot->nameSpace->name);
- WriteEncodedInt64(ot->templateSubTypes.GetLength());
- for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
- {
- if( !ot->templateSubTypes[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() )
- {
- ch = 's'; // sub type
- WriteData(&ch, 1);
- WriteDataType(&ot->templateSubTypes[n]);
- }
- else
- {
- ch = 't'; // token
- WriteData(&ch, 1);
- eTokenType t = ot->templateSubTypes[n].GetTokenType();
- WriteEncodedInt64(t);
- }
- }
- }
- }
- else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE )
- {
- ch = 's'; // sub type
- WriteData(&ch, 1);
- WriteString(&ti->name);
- }
- else if( !ti->GetParentType() )
- {
- ch = 'o'; // object
- WriteData(&ch, 1);
- WriteString(&ti->name);
- WriteString(&ti->nameSpace->name);
- }
- else
- {
- asASSERT(ti->flags & asOBJ_FUNCDEF);
- ch = 'c'; // child type
- WriteData(&ch, 1);
- WriteString(&ti->name);
- WriteTypeInfo(CastToFuncdefType(ti)->parentClass);
- }
- }
- else
- {
- ch = '\0';
- WriteData(&ch, 1);
- }
- }
- void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func)
- {
- // Adjust the offset of all negative variables (parameters) so all pointers will have a size of 1 dword
- asUINT n;
- asCArray<int> adjustments;
- asUINT offset = 0;
- if( func->objectType )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- if( func->DoesReturnOnStack() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- for( n = 0; n < func->parameterTypes.GetLength(); n++ )
- {
- if( !func->parameterTypes[n].IsPrimitive() ||
- func->parameterTypes[n].IsReference() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- else
- {
- asASSERT( func->parameterTypes[n].IsPrimitive() );
- offset += func->parameterTypes[n].GetSizeOnStackDWords();
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustNegativeStackByPos.SetLength(offset);
- memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
- adjustNegativeStackByPos[i] += adjust;
- }
- // Adjust the offset of all positive variables so that all object types and handles have a size of 1 dword
- // This is similar to how the adjustment is done in the asCReader::TranslateFunction, only the reverse
- adjustments.SetLength(0);
- for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- // objVariableTypes is null if the variable type is a null pointer
- if( func->scriptData->objVariableTypes[n] &&
- (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
- n >= func->scriptData->objVariablesOnHeap )
- {
- size = func->scriptData->objVariableTypes[n]->GetSize();
- if( size < 4 )
- size = 1;
- else
- size /= 4;
- }
- // If larger than 1 dword, adjust the offsets accordingly
- if (size > 1)
- {
- // How much needs to be adjusted?
- adjustments.PushLast(func->scriptData->objVariablePos[n]);
- adjustments.PushLast(-(size - 1));
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustStackByPos.SetLength(func->scriptData->stackNeeded);
- memset(adjustStackByPos.AddressOf(), 0, adjustStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos; i < adjustStackByPos.GetLength(); i++ )
- adjustStackByPos[i] += adjust;
- }
- // Compute the sequence number of each bytecode instruction in order to update the jump offsets
- asUINT length = func->scriptData->byteCode.GetLength();
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- bytecodeNbrByPos.SetLength(length);
- asUINT num;
- for( offset = 0, num = 0; offset < length; )
- {
- bytecodeNbrByPos[offset] = num;
- offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type];
- num++;
- }
- // Store the number of instructions in the last position of bytecodeNbrByPos,
- // so this can be easily queried in SaveBytecode. Normally this is already done
- // as most functions end with BC_RET, but in some cases the last instruction in
- // the function is not a BC_RET, e.g. when a function has a never ending loop.
- bytecodeNbrByPos[length - 1] = num - 1;
- }
- int asCWriter::AdjustStackPosition(int pos)
- {
- if( pos >= (int)adjustStackByPos.GetLength() )
- {
- // This happens for example if the function only have temporary variables
- // The adjustByPos can also be empty if the function doesn't have any variables at all, but receive a handle by parameter
- if( adjustStackByPos.GetLength() > 0 )
- pos += adjustStackByPos[adjustStackByPos.GetLength()-1];
- }
- else if( pos >= 0 )
- pos += adjustStackByPos[pos];
- else
- {
- asASSERT( -pos < (int)adjustNegativeStackByPos.GetLength() );
- pos -= (short)adjustNegativeStackByPos[-pos];
- }
- return pos;
- }
- int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
- {
- // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
- // the function can remember where it found the function and check if the programPos is still valid
- // Get offset 0 doesn't need adjustment
- if( offset == 0 ) return 0;
- bool bcAlloc = false;
- // Find out which function that will be called
- asCScriptFunction *calledFunc = 0;
- int stackDelta = 0;
- for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); )
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLINTF )
- {
- // Find the function from the function id in bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
- calledFunc = engine->scriptFunctions[funcId];
- break;
- }
- else if( bc == asBC_ALLOC )
- {
- // The alloc instruction doesn't take the object pointer on the stack,
- // as the memory will be allocated by the instruction itself
- bcAlloc = true;
- // Find the function from the function id in the bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]);
- calledFunc = engine->scriptFunctions[funcId];
- break;
- }
- else if( bc == asBC_CALLBND )
- {
- // Find the function from the engine's bind array
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
- calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
- break;
- }
- else if( bc == asBC_CallPtr )
- {
- int var = asBC_SWORDARG0(&func->scriptData->byteCode[n]);
- asUINT v;
- // Find the funcdef from the local variable
- for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
- {
- if( func->scriptData->objVariablePos[v] == var )
- {
- calledFunc = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef;
- break;
- }
- }
- if( !calledFunc )
- {
- // Look in parameters
- int paramPos = 0;
- if( func->objectType )
- paramPos -= AS_PTR_SIZE;
- if( func->DoesReturnOnStack() )
- paramPos -= AS_PTR_SIZE;
- for( v = 0; v < func->parameterTypes.GetLength(); v++ )
- {
- if( var == paramPos )
- {
- calledFunc = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
- break;
- }
- paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
- }
- }
- break;
- }
- else if( bc == asBC_REFCPY ||
- bc == asBC_COPY )
- {
- // In this case we know there is only 1 pointer on the stack above
- asASSERT( offset == AS_PTR_SIZE );
- return offset + (1 - AS_PTR_SIZE);
- }
- // Keep track of the stack size between the
- // instruction that needs to be adjusted and the call
- stackDelta += asBCInfo[bc].stackInc;
- n += asBCTypeSize[asBCInfo[bc].type];
- }
- asASSERT( calledFunc );
- // Count the number of pointers pushed on the stack above the
- // current offset, and then adjust the offset accordingly
- asUINT numPtrs = 0;
- int currOffset = -stackDelta;
- if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
- {
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- }
- for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
- {
- if( offset <= currOffset ) break;
- if( !calledFunc->parameterTypes[p].IsPrimitive() ||
- calledFunc->parameterTypes[p].IsReference() )
- {
- // objects and references are passed by pointer
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- // The variable arg ? has an additional 32bit int with the typeid
- if( calledFunc->parameterTypes[p].IsAnyType() )
- currOffset += 1;
- }
- else
- {
- // built-in primitives or enums are passed by value
- asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
- currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
- }
- }
- // The get offset must match one of the parameter offsets
- asASSERT( offset == currOffset );
- return offset + numPtrs * (1 - AS_PTR_SIZE);
- }
- void asCWriter::WriteByteCode(asCScriptFunction *func)
- {
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- size_t length = func->scriptData->byteCode.GetLength();
- // The length cannot be stored, because it is platform dependent,
- // instead we store the number of instructions
- asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1;
- WriteEncodedInt64(count);
- asDWORD *startBC = bc;
- while( length )
- {
- asDWORD tmpBC[4]; // The biggest instructions take up 4 DWORDs
- asDWORD c = *(asBYTE*)bc;
- // Copy the instruction to a temp buffer so we can work on it before saving
- memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD));
- if( c == asBC_ALLOC ) // PTR_DW_ARG
- {
- // Translate the object type
- asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
- // Translate the constructor func id, unless it is 0
- if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 )
- {
- // Increment 1 to the translated function id, as 0 will be reserved for no function
- *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[1+AS_PTR_SIZE]]);
- }
- }
- else if( c == asBC_REFCPY || // PTR_ARG
- c == asBC_RefCpyV || // wW_PTR_ARG
- c == asBC_OBJTYPE ) // PTR_ARG
- {
- // Translate object type pointers into indices
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1));
- }
- else if( c == asBC_JitEntry ) // PTR_ARG
- {
- // We don't store the JIT argument
- *(asPWORD*)(tmpBC+1) = 0;
- }
- else if( c == asBC_TYPEID || // DW_ARG
- c == asBC_Cast ) // DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- }
- else if( c == asBC_ADDSi || // W_DW_ARG
- c == asBC_LoadThisR ) // W_DW_ARG
- {
- // Translate property offsets into indices
- *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc);
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- }
- else if( c == asBC_LoadRObjR || // rW_W_DW_ARG
- c == asBC_LoadVObjR ) // rW_W_DW_ARG
- {
- asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2));
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- // List patterns have a different way of translating the offsets
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot);
- }
- else
- {
- // Translate property offsets into indices
- *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc);
- }
- // Translate type ids into indices
- *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2));
- }
- else if( c == asBC_COPY ) // W_DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- // Update the WORDARG0 to 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmpBC) = 0;
- }
- else if( c == asBC_RET ) // W_ARG
- {
- // Save with arg 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmpBC) = 0;
- }
- else if( c == asBC_CALL || // DW_ARG
- c == asBC_CALLINTF || // DW_ARG
- c == asBC_CALLSYS || // DW_ARG
- c == asBC_Thiscall1 ) // DW_ARG
- {
- // Translate the function id
- *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]);
- }
- else if( c == asBC_FuncPtr ) // PTR_ARG
- {
- // Translate the function pointer
- *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1));
- }
- else if( c == asBC_CALLBND ) // DW_ARG
- {
- // Translate the function id
- int funcId = tmpBC[1];
- for( asUINT n = 0; n < module->m_bindInformations.GetLength(); n++ )
- if( module->m_bindInformations[n]->importedFunctionSignature->id == funcId )
- {
- funcId = n;
- break;
- }
- tmpBC[1] = funcId;
- }
- else if( c == asBC_PGA || // PTR_ARG
- c == asBC_PshGPtr || // PTR_ARG
- c == asBC_LDG || // PTR_ARG
- c == asBC_PshG4 || // PTR_ARG
- c == asBC_LdGRdR4 || // wW_PTR_ARG
- c == asBC_CpyGtoV4 || // wW_PTR_ARG
- c == asBC_CpyVtoG4 || // rW_PTR_ARG
- c == asBC_SetG4 ) // PTR_DW_ARG
- {
- // Check if the address is a global property or a string constant
- void *ptr = *(void**)(tmpBC + 1);
- if (engine->varAddressMap.MoveTo(0, ptr))
- {
- // Translate global variable pointers into indices
- // Flag the first bit to signal global property
- *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1;
- }
- else
- {
- // Only PGA and PshGPtr can hold string constants
- asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
- // Translate string constants into indices
- // Leave the first bit clear to signal string constant
- *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1;
- }
- }
- else if( c == asBC_JMP || // DW_ARG
- c == asBC_JZ ||
- c == asBC_JNZ ||
- c == asBC_JLowZ ||
- c == asBC_JLowNZ ||
- c == asBC_JS ||
- c == asBC_JNS ||
- c == asBC_JP ||
- c == asBC_JNP ) // The JMPP instruction doesn't need modification
- {
- // Get the DWORD offset from arg
- int offset = *(int*)(tmpBC+1);
- // Determine instruction number for next instruction and destination
- int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1;
- asDWORD *targetBC = bc + 2 + offset;
- int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)];
- // Set the offset in number of instructions
- *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum;
- }
- else if( c == asBC_GETOBJ || // W_ARG
- c == asBC_GETOBJREF ||
- c == asBC_GETREF ||
- c == asBC_ChkNullS )
- {
- // Adjust the offset according to the function call that comes after
- asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC));
- }
- else if( c == asBC_AllocMem )
- {
- // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader
- asBC_DWORDARG(tmpBC) = 0;
- // Determine the type of the list pattern from the variable
- short var = asBC_WORDARG0(tmpBC);
- asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var));
- // Create this helper object to adjust the offset of the elements accessed in the buffer
- listAdjusters.PushLast(asNEW(SListAdjuster)(ot));
- }
- else if( c == asBC_FREE ) // wW_PTR_ARG
- {
- // Translate object type pointers into indices
- asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
- // Pop and destroy the list adjuster helper that was created with asBC_AllocMem
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- SListAdjuster *list = listAdjusters.PopLast();
- asDELETE(list, SListAdjuster);
- }
- }
- else if( c == asBC_SetListSize )
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- // Tell the adjuster how many repeated values there are
- listAdj->SetRepeatCount(tmpBC[2]);
- }
- else if( c == asBC_PshListElmnt ) // W_DW_ARG
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- }
- else if( c == asBC_SetListType )
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- // Inform the adjuster of the type id of the next element
- listAdj->SetNextType(tmpBC[2]);
- // Translate the type id
- tmpBC[2] = FindTypeIdIdx(tmpBC[2]);
- }
- // Adjust the variable offsets
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_wW_W_ARG:
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- case asBCTYPE_rW_DW_DW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
- asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC));
- }
- break;
- default:
- // The other types don't treat variables so won't be modified
- break;
- }
- // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform.
- // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values
- // Now store the instruction in the smallest possible way
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_NO_ARG:
- {
- // Just write 1 byte
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- }
- break;
- case asBCTYPE_W_ARG:
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the word argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- }
- break;
- case asBCTYPE_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- WriteEncodedInt64((int)tmpBC[1]);
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[2]);
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- w = *(((short*)tmpBC)+3);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- case asBCTYPE_wW_W_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- int dw = tmpBC[2];
- WriteEncodedInt64(dw);
- }
- break;
- case asBCTYPE_QW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- }
- break;
- case asBCTYPE_QW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- // Write the second argument
- int dw = tmpBC[3];
- WriteEncodedInt64(dw);
- }
- break;
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_wW_QW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- }
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the short argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[2]);
- }
- break;
- default:
- {
- // This should never happen
- asASSERT(false);
- // Store the bc as is
- for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ )
- WriteData(&tmpBC[n], 4);
- }
- }
- // Move to the next instruction
- bc += asBCTypeSize[asBCInfo[c].type];
- length -= asBCTypeSize[asBCInfo[c].type];
- }
- }
- asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
- {
- asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) );
- // Find the first expected value in the list
- asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
- asASSERT( node && node->type == asLPT_START );
- patternNode = node->next;
- }
- int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatternType)
- {
- // TODO: cleanup: The listPatternType parameter is not needed
- asASSERT( patternType == listPatternType );
- UNUSED_VAR(listPatternType);
- asASSERT( offset >= lastOffset );
- // If it is the same offset being accessed again, just return the same adjusted value
- if( offset == lastOffset )
- return entries-1;
- asASSERT( offset >= nextOffset );
- // Update last offset for next call
- lastOffset = offset;
- // What is being expected at this position?
- if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
- {
- // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
- nextOffset = offset + 4;
- return entries++;
- }
- else if( patternNode->type == asLPT_TYPE )
- {
- const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
- if( dt.GetTokenType() == ttQuestion )
- {
- // The bytecode need to inform the type that will
- // come next and then adjust that position too before
- // we can move to the next node
- if( nextTypeId != -1 )
- {
- nextOffset = offset + 4;
- if( repeatCount > 0 )
- repeatCount--;
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextTypeId = -1;
- }
- }
- else
- {
- if( repeatCount > 0 )
- {
- // Was any value skipped?
- asUINT size;
- if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = dt.GetSizeInMemoryBytes();
- int count = 0;
- while( nextOffset <= offset )
- {
- count++;
- nextOffset += size;
- // Align the offset on 4 byte boundaries
- if( size >= 4 && (nextOffset & 0x3) )
- nextOffset += 4 - (nextOffset & 0x3);
- }
- if( --count > 0 )
- {
- // Skip these values
- repeatCount -= count;
- entries += count;
- }
- nextOffset = offset + size;
- repeatCount--;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- }
- return entries++;
- }
- else if( patternNode->type == asLPT_START )
- {
- if( repeatCount > 0 )
- repeatCount--;
- SInfo info = {repeatCount, patternNode};
- stack.PushLast(info);
- repeatCount = 0;
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset, listPatternType);
- }
- else if( patternNode->type == asLPT_END )
- {
- SInfo info = stack.PopLast();
- repeatCount = info.repeatCount;
- if( repeatCount )
- patternNode = info.startNode;
- else
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset, listPatternType);
- }
- else
- {
- // Something is wrong with the pattern list declaration
- asASSERT( false );
- }
- return 0;
- }
- void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc)
- {
- // Make sure the list is expecting a repeat at this location
- asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
- // Now move to the next patternNode
- patternNode = patternNode->next;
- repeatCount = rc;
- }
- void asCWriter::SListAdjuster::SetNextType(int typeId)
- {
- // Make sure the list is expecting a type at this location
- asASSERT( patternNode->type == asLPT_TYPE &&
- reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
- // Inform the type id for the next adjustment
- nextTypeId = typeId;
- }
- void asCWriter::WriteUsedTypeIds()
- {
- TimeIt("asCWriter::WriteUsedTypeIds");
- asUINT count = (asUINT)usedTypeIds.GetLength();
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < count; n++ )
- {
- asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]);
- WriteDataType(&dt);
- }
- }
- int asCWriter::FindGlobalPropPtrIndex(void *ptr)
- {
- int i = usedGlobalProperties.IndexOf(ptr);
- if( i >= 0 ) return i;
- usedGlobalProperties.PushLast(ptr);
- return (int)usedGlobalProperties.GetLength()-1;
- }
- void asCWriter::WriteUsedGlobalProps()
- {
- TimeIt("asCWriter::WriteUsedGlobalProps");
- int c = (int)usedGlobalProperties.GetLength();
- WriteEncodedInt64(c);
- for( int n = 0; n < c; n++ )
- {
- asPWORD *p = (asPWORD*)usedGlobalProperties[n];
- // Find the property descriptor from the address
- asCGlobalProperty *prop = 0;
- asSMapNode<void*, asCGlobalProperty*> *cursor;
- if( engine->varAddressMap.MoveTo(&cursor, p) )
- {
- prop = engine->varAddressMap.GetValue(cursor);
- }
- asASSERT(prop);
- // Store the name and type of the property so we can find it again on loading
- WriteString(&prop->name);
- WriteString(&prop->nameSpace->name);
- WriteDataType(&prop->type);
- // Also store whether the property is a module property or a registered property
- char moduleProp = 0;
- if( prop->realAddress == 0 )
- moduleProp = 1;
- WriteData(&moduleProp, 1);
- }
- }
- void asCWriter::WriteUsedObjectProps()
- {
- TimeIt("asCWriter::WriteUsedObjectProps");
- int c = (int)usedObjectProperties.GetLength();
- WriteEncodedInt64(c);
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- WriteTypeInfo(usedObjectProperties[n].objType);
- WriteString(&usedObjectProperties[n].prop->name);
- }
- }
- int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc)
- {
- // If the last property was a composite property, then just return 0, because it won't be translated
- static bool lastWasComposite = false;
- if (lastWasComposite)
- {
- lastWasComposite = false;
- return 0;
- }
-
- asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId);
- asCObjectProperty *objProp = 0;
- // Look for composite properties first
- for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
- {
- // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property.
- // That would also allow me to remove the typeId from the bytecode instruction itself
- // Or perhaps a new bytecode instruction all together for accessing composite properties
- // One that would do both offsets and indirection in a single go.
- // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too
- if (objType->properties[n]->compositeOffset == offset)
- {
- // This is a potential composite property. Need to check the following instructions to be sure
- objProp = objType->properties[n];
- asDWORD *bcTemp = bc;
- bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
- if (objProp->isCompositeIndirect)
- {
- // The next instruction would be a asBC_RDSPtr
- if ((*(asBYTE*)bcTemp) != asBC_RDSPtr)
- {
- objProp = 0;
- continue;
- }
- bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
- }
- // The next instruction would be asBC_ADDSi
- if ((*(asBYTE*)bcTemp) != asBC_ADDSi)
- {
- objProp = 0;
- continue;
- }
- // Make sure the offset is the expected one
- if (*(((short*)bcTemp) + 1) != objProp->byteOffset)
- {
- objProp = 0;
- continue;
- }
- }
- }
- // If none of the composite properties matched, then look for ordinary property
- for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
- {
- if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect))
- objProp = objType->properties[n];
- }
- asASSERT(objProp);
- // Remember if this is a composite property as the next call will then be for the same property
- if (objProp->compositeOffset || objProp->isCompositeIndirect)
- lastWasComposite = true;
- // Now check if the same property has already been accessed
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- if( usedObjectProperties[n].objType == objType &&
- usedObjectProperties[n].prop == objProp )
- return n;
- }
- // Insert the new property
- SObjProp prop = {objType, objProp};
- usedObjectProperties.PushLast(prop);
- return (int)usedObjectProperties.GetLength() - 1;
- }
- int asCWriter::FindFunctionIndex(asCScriptFunction *func)
- {
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- if( usedFunctions[n] == func )
- return n;
- }
- usedFunctions.PushLast(func);
- return (int)usedFunctions.GetLength() - 1;
- }
- int asCWriter::FindTypeIdIdx(int typeId)
- {
- asUINT n;
- for( n = 0; n < usedTypeIds.GetLength(); n++ )
- {
- if( usedTypeIds[n] == typeId )
- return n;
- }
- usedTypeIds.PushLast(typeId);
- return (int)usedTypeIds.GetLength() - 1;
- }
- int asCWriter::FindTypeInfoIdx(asCTypeInfo *obj)
- {
- asUINT n;
- for( n = 0; n < usedTypes.GetLength(); n++ )
- {
- if( usedTypes[n] == obj )
- return n;
- }
- usedTypes.PushLast(obj);
- return (int)usedTypes.GetLength() - 1;
- }
- #endif // AS_NO_COMPILER
- END_AS_NAMESPACE
|