123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2019 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_bytecode.cpp
- //
- // A class for constructing the final byte code
- //
- #include <stdio.h> // fopen(), fprintf(), fclose()
- #include "as_config.h"
- #ifndef AS_NO_COMPILER
- #include "as_bytecode.h"
- #include "as_debug.h" // mkdir()
- #include "as_array.h"
- #include "as_string.h"
- #include "as_scriptengine.h"
- #include "as_debug.h"
- BEGIN_AS_NAMESPACE
- asCByteCode::asCByteCode(asCScriptEngine *engine)
- {
- first = 0;
- last = 0;
- largestStackUsed = -1;
- temporaryVariables = 0;
- this->engine = engine;
- }
- asCByteCode::~asCByteCode()
- {
- ClearAll();
- }
- void asCByteCode::Finalize(const asCArray<int> &tempVariableOffsets)
- {
- temporaryVariables = &tempVariableOffsets;
- // verify the bytecode
- PostProcess();
- // Optimize the code
- Optimize();
- // Resolve jumps
- ResolveJumpAddresses();
- // Build line numbers buffer
- ExtractLineNumbers();
- }
- void asCByteCode::ClearAll()
- {
- asCByteInstruction *del = first;
- while( del )
- {
- first = del->next;
- engine->memoryMgr.FreeByteInstruction(del);
- del = first;
- }
- first = 0;
- last = 0;
- lineNumbers.SetLength(0);
- largestStackUsed = -1;
- }
- void asCByteCode::InsertIfNotExists(asCArray<int> &vars, int var)
- {
- if( !vars.Exists(var) )
- vars.PushLast(var);
- }
- void asCByteCode::GetVarsUsed(asCArray<int> &vars)
- {
- TimeIt("asCByteCode::GetVarsUsed");
- asCByteInstruction *curr = first;
- while( curr )
- {
- if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
- {
- InsertIfNotExists(vars, curr->wArg[0]);
- InsertIfNotExists(vars, curr->wArg[1]);
- InsertIfNotExists(vars, curr->wArg[2]);
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
- {
- InsertIfNotExists(vars, curr->wArg[0]);
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG )
- {
- InsertIfNotExists(vars, curr->wArg[0]);
- InsertIfNotExists(vars, curr->wArg[1]);
- }
- else if( curr->op == asBC_LoadThisR )
- {
- InsertIfNotExists(vars, 0);
- }
- curr = curr->next;
- }
- }
- bool asCByteCode::IsVarUsed(int offset)
- {
- TimeIt("asCByteCode::IsVarUsed");
- asCByteInstruction *curr = first;
- while( curr )
- {
- // Verify all ops that use variables
- if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
- {
- if( curr->wArg[0] == offset || curr->wArg[1] == offset || curr->wArg[2] == offset )
- return true;
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
- {
- if( curr->wArg[0] == offset )
- return true;
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG )
- {
- if( curr->wArg[0] == offset || curr->wArg[1] == offset )
- return true;
- }
- else if( curr->op == asBC_LoadThisR )
- {
- if( offset == 0 )
- return true;
- }
- curr = curr->next;
- }
- return false;
- }
- void asCByteCode::ExchangeVar(int oldOffset, int newOffset)
- {
- asASSERT(oldOffset != 0);
- asCByteInstruction *curr = first;
- while( curr )
- {
- // Verify all ops that use variables
- if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
- {
- if( curr->wArg[0] == oldOffset )
- curr->wArg[0] = (short)newOffset;
- if( curr->wArg[1] == oldOffset )
- curr->wArg[1] = (short)newOffset;
- if( curr->wArg[2] == oldOffset )
- curr->wArg[2] = (short)newOffset;
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
- {
- if( curr->wArg[0] == oldOffset )
- curr->wArg[0] = (short)newOffset;
- }
- else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG )
- {
- if( curr->wArg[0] == oldOffset )
- curr->wArg[0] = (short)newOffset;
- if( curr->wArg[1] == oldOffset )
- curr->wArg[1] = (short)newOffset;
- }
- curr = curr->next;
- }
- }
- void asCByteCode::AddPath(asCArray<asCByteInstruction *> &paths, asCByteInstruction *instr, int stackSize)
- {
- if( instr->marked )
- {
- // Verify the size of the stack
- asASSERT(instr->stackSize == stackSize);
- }
- else
- {
- // Add the destination to the code paths
- instr->marked = true;
- instr->stackSize = stackSize;
- paths.PushLast(instr);
- }
- }
- asCByteInstruction *asCByteCode::ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc)
- {
- curr->op = bc;
- if( curr->next ) DeleteInstruction(curr->next);
- // Continue optimization with the instruction before the altered one
- if( curr->prev )
- return curr->prev;
- else
- return curr;
- }
- asCByteInstruction *asCByteCode::DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc)
- {
- asASSERT( curr->next );
- asCByteInstruction *instr = curr->next;
- instr->op = bc;
- DeleteInstruction(curr);
- // Continue optimization with the instruction before the altered one
- if( instr->prev )
- return instr->prev;
- else
- return instr;
- }
- void asCByteCode::InsertBefore(asCByteInstruction *before, asCByteInstruction *instr)
- {
- asASSERT(instr->next == 0);
- asASSERT(instr->prev == 0);
- if( before->prev ) before->prev->next = instr;
- instr->prev = before->prev;
- before->prev = instr;
- instr->next = before;
- if( first == before ) first = instr;
- }
- void asCByteCode::RemoveInstruction(asCByteInstruction *instr)
- {
- if( instr == first ) first = first->next;
- if( instr == last ) last = last->prev;
- if( instr->prev ) instr->prev->next = instr->next;
- if( instr->next ) instr->next->prev = instr->prev;
- instr->next = 0;
- instr->prev = 0;
- }
- bool asCByteCode::CanBeSwapped(asCByteInstruction *curr)
- {
- asASSERT( curr->op == asBC_SwapPtr );
- if( !curr->prev || !curr->prev->prev ) return false;
- asCByteInstruction *b = curr->prev;
- asCByteInstruction *a = b->prev;
- if( a->op != asBC_PshNull &&
- a->op != asBC_PshVPtr &&
- a->op != asBC_PSF )
- return false;
- if( b->op != asBC_PshNull &&
- b->op != asBC_PshVPtr &&
- b->op != asBC_PSF )
- return false;
- return true;
- }
- asCByteInstruction *asCByteCode::GoBack(asCByteInstruction *curr)
- {
- // Go back 2 instructions
- if( !curr ) return 0;
- if( curr->prev ) curr = curr->prev;
- if( curr->prev ) curr = curr->prev;
- return curr;
- }
- asCByteInstruction *asCByteCode::GoForward(asCByteInstruction *curr)
- {
- // Go forward 2 instructions
- if( !curr ) return 0;
- if( curr->next ) curr = curr->next;
- if( curr->next ) curr = curr->next;
- return curr;
- }
- bool asCByteCode::PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next)
- {
- TimeIt("asCByteCode::PostponeInitOfTemp");
- // This is not done for pointers
- if( (curr->op != asBC_SetV4 && curr->op != asBC_SetV8) ||
- !IsTemporary(curr->wArg[0]) ) return false;
- // Move the initialization to just before it's use.
- // Don't move it beyond any labels or jumps.
- asCByteInstruction *use = curr->next;
- while( use )
- {
- if( IsTempVarReadByInstr(use, curr->wArg[0]) )
- break;
- if( IsTempVarOverwrittenByInstr(use, curr->wArg[0]) )
- return false;
- if( IsInstrJmpOrLabel(use) )
- return false;
- use = use->next;
- }
- if( use && use->prev != curr )
- {
- asCByteInstruction *orig = curr->next;
- // Move the instruction
- RemoveInstruction(curr);
- InsertBefore(use, curr);
- // Try a RemoveUnusedValue to see if it can be combined with the other
- if( RemoveUnusedValue(curr, 0) )
- {
- // Optimizations should continue from the instruction that uses the value
- *next = orig;
- return true;
- }
- // Return the instructions to its original position as it wasn't useful
- RemoveInstruction(curr);
- InsertBefore(orig, curr);
- }
- return false;
- }
- bool asCByteCode::RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next)
- {
- TimeIt("asCByteCode::RemoveUnusedValue");
- asCByteInstruction *dummy;
- if( next == 0 )
- next = &dummy;
- // TODO: runtime optimize: Should work for 64bit types as well
- // TODO: runtime optimize: Need a asBCTYPE_rwW_ARG to cover the instructions that read
- // and write to the same variable. Currently they are considered
- // as readers only, so they are not optimized away. This includes
- // NOT, BNOT, IncV, DecV, NEG, iTOf (and all other type casts)
- // The value isn't used for anything
- if( curr->op != asBC_FREE && // Can't remove the FREE instruction
- (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr, curr->wArg[0]) )
- {
- if( curr->op == asBC_LdGRdR4 && IsTempRegUsed(curr) )
- {
- curr->op = asBC_LDG;
- *next = GoForward(curr);
- return true;
- }
- *next = GoForward(DeleteInstruction(curr));
- return true;
- }
- if( curr->op == asBC_SetV4 && curr->next )
- {
- // The value is immediately used and then never again
- if( (curr->next->op == asBC_CMPi ||
- curr->next->op == asBC_CMPf ||
- curr->next->op == asBC_CMPu) &&
- curr->wArg[0] == curr->next->wArg[1] &&
- IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- if( curr->next->op == asBC_CMPi ) curr->next->op = asBC_CMPIi;
- else if( curr->next->op == asBC_CMPf ) curr->next->op = asBC_CMPIf;
- else if( curr->next->op == asBC_CMPu ) curr->next->op = asBC_CMPIu;
- curr->next->size = asBCTypeSize[asBCInfo[asBC_CMPIi].type];
- curr->next->arg = curr->arg;
- *next = GoForward(DeleteInstruction(curr));
- return true;
- }
- // The value is immediately used and then never again
- if( (curr->next->op == asBC_ADDi ||
- curr->next->op == asBC_SUBi ||
- curr->next->op == asBC_MULi ||
- curr->next->op == asBC_ADDf ||
- curr->next->op == asBC_SUBf ||
- curr->next->op == asBC_MULf) &&
- curr->wArg[0] == curr->next->wArg[2] &&
- (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten
- (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
- !IsTempVarRead(curr->next, curr->wArg[0]))) )
- {
- if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi;
- else if( curr->next->op == asBC_SUBi ) curr->next->op = asBC_SUBIi;
- else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi;
- else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf;
- else if( curr->next->op == asBC_SUBf ) curr->next->op = asBC_SUBIf;
- else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf;
- curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type];
- curr->next->arg = curr->arg;
- *next = GoForward(DeleteInstruction(curr));
- return true;
- }
- if( (curr->next->op == asBC_ADDi ||
- curr->next->op == asBC_MULi ||
- curr->next->op == asBC_ADDf ||
- curr->next->op == asBC_MULf) &&
- curr->wArg[0] == curr->next->wArg[1] &&
- (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten
- (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
- !IsTempVarRead(curr->next, curr->wArg[0]))) )
- {
- if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi;
- else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi;
- else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf;
- else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf;
- curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type];
- curr->next->arg = curr->arg;
- // The order of the operands are changed
- curr->next->wArg[1] = curr->next->wArg[2];
- *next = GoForward(DeleteInstruction(curr));
- return true;
- }
- // The constant value is immediately moved to another variable and then not used again
- if( curr->next->op == asBC_CpyVtoV4 &&
- curr->wArg[0] == curr->next->wArg[1] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->wArg[0] = curr->next->wArg[0];
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- // The constant is copied to a temp and then immediately pushed on the stack
- if( curr->next->op == asBC_PshV4 &&
- curr->wArg[0] == curr->next->wArg[0] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->op = asBC_PshC4;
- curr->stackInc = asBCInfo[asBC_PshC4].stackInc;
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- // The constant is copied to a global variable and then never used again
- if( curr->next->op == asBC_CpyVtoG4 &&
- curr->wArg[0] == curr->next->wArg[0] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->op = asBC_SetG4;
- curr->size = asBCTypeSize[asBCInfo[asBC_SetG4].type];
- *(((asDWORD*)&curr->arg)+AS_PTR_SIZE) = *ARG_DW(curr->arg);
- *ARG_PTR(curr->arg) = *ARG_PTR(curr->next->arg);
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- }
- // The value is immediately moved to another variable and then not used again
- if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) &&
- curr->next && curr->next->op == asBC_CpyVtoV4 &&
- curr->wArg[0] == curr->next->wArg[1] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->wArg[0] = curr->next->wArg[0];
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- // The register is copied to a temp variable and then back to the register again without being used afterwards
- if( curr->op == asBC_CpyRtoV4 && curr->next && curr->next->op == asBC_CpyVtoR4 &&
- curr->wArg[0] == curr->next->wArg[0] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- // Delete both instructions
- DeleteInstruction(curr->next);
- *next = GoForward(DeleteInstruction(curr));
- return true;
- }
- // The global value is copied to a temp and then immediately pushed on the stack
- if( curr->op == asBC_CpyGtoV4 && curr->next && curr->next->op == asBC_PshV4 &&
- curr->wArg[0] == curr->next->wArg[0] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->op = asBC_PshG4;
- curr->size = asBCTypeSize[asBCInfo[asBC_PshG4].type];
- curr->stackInc = asBCInfo[asBC_PshG4].stackInc;
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- // The constant is assigned to a variable, then the value of the variable
- // pushed on the stack, and then the variable is never used again
- if( curr->op == asBC_SetV8 && curr->next && curr->next->op == asBC_PshV8 &&
- curr->wArg[0] == curr->next->wArg[0] &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr->next, curr->wArg[0]) )
- {
- curr->op = asBC_PshC8;
- curr->stackInc = asBCInfo[asBC_PshC8].stackInc;
- *next = GoForward(DeleteInstruction(curr->next));
- return true;
- }
- return false;
- }
- bool asCByteCode::IsTemporary(int offset)
- {
- TimeIt("asCByteCode::IsTemporary");
- asASSERT(temporaryVariables);
- return temporaryVariables->Exists(offset);
- }
- void asCByteCode::OptimizeLocally(const asCArray<int> &tempVariableOffsets)
- {
- // This function performs the optimizations that doesn't require global knowledge of the
- // entire function, e.g. replacement of sequences of bytecodes for specialized instructions.
- if( !engine->ep.optimizeByteCode )
- return;
- temporaryVariables = &tempVariableOffsets;
- // TODO: runtime optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no
- // function calls that can suspend the execution.
- // TODO: runtime optimize: Remove temporary copies of handles, when the temp is just copied to yet another location
- // TODO: runtime optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve
- // loops a lot. How often do these loops really occur?
- // TODO: runtime optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call
- // TODO: optimize: Should possibly do two loops. Some of the checks are best doing by iterating from
- // the end to beginning, e.g. the removal of unused values. Other checks are best
- // doing by iterating from the beginning to end, e.g. replacement of sequences with
- // shorter ones. By doing this, we should be able to avoid backtracking with every
- // change thus avoid unnecessary duplicate checks.
- // Iterate through the bytecode instructions in the reverse order.
- // An optimization in an instruction may mean that another instruction before that
- // can also be optimized, e.g. if an add instruction is removed because the result is not
- // used, then the instructions that created the operands may potentially also be removed.
- asCByteInstruction *instr = last;
- while( instr )
- {
- asCByteInstruction *curr = instr;
- instr = instr->prev;
- // Remove instructions when the result is not used anywhere
- // This will return true if the instruction is deleted, and
- // false if it is not deleted. Observe that the instruction
- // can be modified.
- if( RemoveUnusedValue(curr, &instr) ) continue;
- // Postpone initializations so that they may be combined in the second pass.
- // If the initialization is postponed, then the optimizations should continue
- // from where the value was used, so instr will be updated to point to that.
- if( PostponeInitOfTemp(curr, &instr) ) continue;
- // Look for sequences that can be replaced with shorter ones
- const asEBCInstr currOp = curr->op;
- if( currOp == asBC_SwapPtr )
- {
- // XXX x, YYY y, SwapPtr -> YYY y, XXX x
- if( CanBeSwapped(curr) )
- {
- // Delete the SwapPtr
- DeleteInstruction(curr);
- // Swap instructions
- asCByteInstruction *a = instr->prev;
- RemoveInstruction(instr);
- InsertBefore(a, instr);
- // Continue the optimization from the second instruction
- instr = GoForward(a);
- continue;
- }
- }
- else if( currOp == asBC_ClrHi )
- {
- // T??, ClrHi -> T??
- if( instr &&
- (instr->op == asBC_TZ ||
- instr->op == asBC_TNZ ||
- instr->op == asBC_TS ||
- instr->op == asBC_TNS ||
- instr->op == asBC_TP ||
- instr->op == asBC_TNP) )
- {
- // Remove the ClrHi instruction since the test
- // instructions always clear the top bytes anyway
- instr = GoForward(DeleteInstruction(curr));
- continue;
- }
- // ClrHi, JZ -> JLowZ
- if( curr->next &&
- curr->next->op == asBC_JZ )
- {
- curr->next->op = asBC_JLowZ;
- instr = GoForward(DeleteInstruction(curr));
- continue;
- }
- // ClrHi, JNZ -> JLowNZ
- if( curr->next &&
- curr->next->op == asBC_JNZ )
- {
- curr->next->op = asBC_JLowNZ;
- instr = GoForward(DeleteInstruction(curr));
- continue;
- }
- }
- else if( currOp == asBC_LDV && curr->next )
- {
- // LDV x, INCi -> IncVi x
- if( curr->next->op == asBC_INCi && !IsTempRegUsed(curr->next) )
- {
- curr->op = asBC_IncVi;
- DeleteInstruction(curr->next);
- instr = GoForward(curr);
- }
- // LDV x, DECi -> DecVi x
- else if( curr->next->op == asBC_DECi && !IsTempRegUsed(curr->next) )
- {
- curr->op = asBC_DecVi;
- DeleteInstruction(curr->next);
- instr = GoForward(curr);
- }
- }
- else if( currOp == asBC_LDG && curr->next )
- {
- // LDG x, WRTV4 y -> CpyVtoG4 y, x
- if( curr->next->op == asBC_WRTV4 && !IsTempRegUsed(curr->next) )
- {
- curr->op = asBC_CpyVtoG4;
- curr->size = asBCTypeSize[asBCInfo[asBC_CpyVtoG4].type];
- curr->wArg[0] = curr->next->wArg[0];
- DeleteInstruction(curr->next);
- instr = GoForward(curr);
- }
- // LDG x, RDR4 y -> CpyGtoV4 y, x
- else if( curr->next->op == asBC_RDR4 )
- {
- if( !IsTempRegUsed(curr->next) )
- curr->op = asBC_CpyGtoV4;
- else
- curr->op = asBC_LdGRdR4;
- curr->size = asBCTypeSize[asBCInfo[asBC_CpyGtoV4].type];
- curr->wArg[0] = curr->next->wArg[0];
- DeleteInstruction(curr->next);
- instr = GoForward(curr);
- }
- }
- else if( currOp == asBC_CHKREF )
- {
- // CHKREF, ADDSi -> ADDSi
- // CHKREF, RDSPtr -> RDSPtr
- if( curr->next &&
- (curr->next->op == asBC_ADDSi || curr->next->op == asBC_RDSPtr) )
- {
- // As ADDSi & RDSPtr already checks the pointer the CHKREF instruction is unnecessary
- instr = GoForward(DeleteInstruction(curr));
- }
- // ADDSi, CHKREF -> ADDSi
- // PGA, CHKREF -> PGA
- // PSF, CHKREF -> PSF
- else if( instr &&
- (instr->op == asBC_ADDSi ||
- instr->op == asBC_PGA ||
- instr->op == asBC_PSF) )
- {
- // ADDSi is guaranteed to work on valid pointers so CHKREF is not necessary.
- // PGA and PSF always pushes a valid address on the stack.
- instr = GoForward(DeleteInstruction(curr));
- }
- // PGA, ChkRefS, CHKREF -> PGA, ChkRefS
- else if( instr && instr->op == asBC_ChkRefS &&
- instr->prev && instr->prev->op == asBC_PGA )
- {
- // Delete CHKREF since PGA always pushes a valid address on the stack
- instr = GoForward(DeleteInstruction(curr));
- }
- }
- else if( currOp == asBC_PopPtr )
- {
- // RDSPtr, PopPtr -> PopPtr
- if( instr && instr->op == asBC_RDSPtr )
- {
- instr = GoForward(DeleteInstruction(instr));
- }
- // PshNull, RefCpyV, PopPtr -> FREE
- else if( instr && instr->op == asBC_RefCpyV &&
- instr->prev && instr->prev->op == asBC_PshNull )
- {
- DeleteInstruction(curr);
- DeleteInstruction(instr->prev);
- instr->op = asBC_FREE;
- instr = GoForward(instr);
- }
- // PshVPtr y, PopPtr -> nothing
- // PSF y , PopPtr -> nothing
- // VAR y , PopPtr -> nothing
- // PshNull , PopPtr -> nothing
- // PshRPtr , PopPtr -> nothing
- else if( instr &&
- (instr->op == asBC_PshRPtr ||
- instr->op == asBC_PSF ||
- instr->op == asBC_VAR ||
- instr->op == asBC_PshVPtr ||
- instr->op == asBC_PshNull) )
- {
- // A pointer is pushed on the stack then immediately removed
- // Remove both instructions as they cancel each other
- DeleteInstruction(curr);
- instr = GoForward(DeleteInstruction(instr));
- }
- // PSF, ChkRefS, PopPtr -> ChkNullV
- else if( instr && instr->op == asBC_ChkRefS &&
- instr->prev && instr->prev->op == asBC_PSF )
- {
- instr = instr->prev;
- instr->op = asBC_ChkNullV;
- instr->stackInc = 0;
- // Delete the PopPtr instruction
- DeleteInstruction(curr);
- // Delete the ChkRefS instruction
- DeleteInstruction(instr->next);
- instr = GoForward(instr);
- }
- // PshVPtr, CHKREF, PopPtr -> ChkNullV
- else if( instr && instr->op == asBC_CHKREF &&
- instr->prev && instr->prev->op == asBC_PshVPtr )
- {
- instr = instr->prev;
- instr->op = asBC_ChkNullV;
- instr->stackInc = 0;
- DeleteInstruction(curr->prev);
- DeleteInstruction(curr);
- instr = GoForward(instr);
- }
- // STOREOBJ y, PSF y, RDSPtr, PSF x, REFCPY, FREE y, PopPtr -> FREE x, STOREOBJ x
- else if( instr && instr->op == asBC_FREE )
- {
- asCByteInstruction *i = instr->prev;
- if( !i || i->op != asBC_REFCPY ) continue;
- i = i->prev;
- if( !i || i->op != asBC_PSF ) continue;
- short x = i->wArg[0];
- i = i->prev;
- if( !i || i->op != asBC_RDSPtr ) continue;
- i = i->prev;
- if( !i || i->op != asBC_PSF ) continue;
- short y = i->wArg[0];
- i = i->prev;
- if( !i || i->op != asBC_STOREOBJ || i->wArg[0] != y ) continue;
- // Don't do the substitution if the var y is not a temporary, or if it is used after PopPtr
- if( !IsTemporary(y) || IsTempVarRead(curr, y) ) continue;
- // Transform the PopPtr into STOREOBJ
- curr->op = asBC_STOREOBJ;
- curr->stackInc = 0;
- curr->wArg[0] = x;
- curr->size = i->size;
- // Change arg of the FREE to x
- // TODO: runtime optimize: The FREE instruction shouldn't be necessary. STOREOBJ should free the previous value by itself
- instr->wArg[0] = x;
- // Delete all other instructions
- DeleteInstruction(instr->prev); // REFCPY
- DeleteInstruction(instr->prev); // PSF
- DeleteInstruction(instr->prev); // RDSTR
- DeleteInstruction(instr->prev); // PSF
- DeleteInstruction(instr->prev); // STOREOBJ
- instr = GoForward(curr);
- }
- }
- else if( currOp == asBC_RDSPtr )
- {
- // PGA, RDSPtr -> PshGPtr
- if( instr && instr->op == asBC_PGA )
- {
- instr->op = asBC_PshGPtr;
- DeleteInstruction(curr);
- instr = GoForward(instr);
- }
- // ChkRefS, RDSPtr -> RDSPtr, CHKREF
- else if( instr && instr->op == asBC_ChkRefS )
- {
- // This exchange removes one pointer dereference, and also
- // makes it easier to completely remove the CHKREF instruction
- curr->op = asBC_CHKREF;
- instr->op = asBC_RDSPtr;
- instr = GoForward(curr);
- }
- // PSF, RDSPtr -> PshVPtr
- else if( instr && instr->op == asBC_PSF )
- {
- instr->op = asBC_PshVPtr;
- instr = GoForward(DeleteInstruction(curr));
- }
- // PSF, ChkRefS, RDSPtr -> PshVPtr, CHKREF
- else if( instr && instr->op == asBC_ChkRefS &&
- instr->prev && instr->prev->op == asBC_PSF )
- {
- instr->prev->op = asBC_PshVPtr;
- instr->op = asBC_CHKREF;
- instr = GoForward(DeleteInstruction(curr));
- }
- }
- else if( currOp == asBC_PopRPtr )
- {
- // PshVPtr 0, ADDSi, PopRPtr -> LoadThisR
- if( instr && instr->op == asBC_ADDSi &&
- instr->prev && instr->prev->op == asBC_PshVPtr &&
- instr->prev->wArg[0] == 0 )
- {
- DeleteInstruction(instr->prev);
- ChangeFirstDeleteNext(instr, asBC_LoadThisR);
- instr = GoForward(instr);
- }
- // TODO: runtime optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0
- // PshVPtr x, ADDSi, PopRPtr -> LoadRObjR
- else if( instr && instr->op == asBC_ADDSi &&
- instr->prev && instr->prev->op == asBC_PshVPtr &&
- instr->prev->wArg[0] != 0 )
- {
- instr = instr->prev;
- instr->op = asBC_LoadRObjR;
- instr->size = asBCTypeSize[asBCInfo[asBC_LoadRObjR].type];
- instr->stackInc = asBCInfo[asBC_LoadRObjR].stackInc;
- instr->wArg[1] = instr->next->wArg[0];
- *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg;
- DeleteInstruction(instr->next);
- DeleteInstruction(curr);
- instr = GoForward(instr);
- }
- // PSF x, ADDSi, PopRPtr -> LoadVObjR
- else if( instr && instr->op == asBC_ADDSi &&
- instr->prev && instr->prev->op == asBC_PSF )
- {
- instr = instr->prev;
- instr->op = asBC_LoadVObjR;
- instr->size = asBCTypeSize[asBCInfo[asBC_LoadVObjR].type];
- instr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
- instr->wArg[1] = instr->next->wArg[0];
- *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg;
- DeleteInstruction(instr->next);
- DeleteInstruction(curr);
- instr = GoForward(instr);
- }
- }
- else if( currOp == asBC_REFCPY )
- {
- // PSF x, REFCPY -> RefCpyV x
- if( instr && instr->op == asBC_PSF )
- {
- curr->op = asBC_RefCpyV;
- curr->wArg[0] = instr->wArg[0];
- curr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
- DeleteInstruction(instr);
- instr = GoForward(curr);
- }
- }
- else if( ((currOp >= asBC_JZ && currOp <= asBC_JNP) || currOp == asBC_JLowZ || currOp == asBC_JLowNZ) && instr )
- {
- // T**; J** +x -> J** +x
- if( (instr->op == asBC_TZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TNZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNZ));
- else if( (instr->op == asBC_TNZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JZ));
- else if( (instr->op == asBC_TS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TNS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNS));
- else if( (instr->op == asBC_TNS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JS));
- else if( (instr->op == asBC_TP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TNP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNP));
- else if( (instr->op == asBC_TNP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
- (instr->op == asBC_TP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
- instr = GoForward(DeleteFirstChangeNext(instr, asBC_JP));
- }
- else if( currOp == asBC_FREE && instr )
- {
- // PSF, FREE -> FREE, PSF
- if( instr->op == asBC_PSF )
- {
- // This pattern usually happens when a function returns an object, or handle
- // and then releases a temporary variable, possibly used in one of the arguments.
- // By swapping the order of these instructions, the code can be further optimized
- // to combine the PSF with the following instructions
- RemoveInstruction(curr);
- InsertBefore(instr, curr);
- instr = GoForward(instr);
- }
- // VAR, FREE -> FREE, VAR
- else if( instr->op == asBC_VAR )
- {
- // Swap the two instructions, so that the VAR instruction
- // gets closer to its corresponding GET instruction and thus
- // has a greater chance of getting optimized
- RemoveInstruction(curr);
- InsertBefore(instr, curr);
- instr = GoForward(instr);
- }
- }
- else if( currOp == asBC_VAR )
- {
- // VAR, PSF, GETOBJREF {PTR_SIZE} -> PshVPtr, PSF
- if( curr->next && curr->next->op == asBC_PSF &&
- curr->next->next && curr->next->next->op == asBC_GETOBJREF &&
- curr->next->next->wArg[0] == AS_PTR_SIZE )
- {
- curr->op = asBC_PshVPtr;
- DeleteInstruction(curr->next->next);
- instr = GoForward(curr);
- }
- // VAR a, GETREF 0 -> PSF a
- else if( curr->next && curr->next->op == asBC_GETREF && curr->next->wArg[0] == 0 )
- {
- ChangeFirstDeleteNext(curr, asBC_PSF);
- instr = GoForward(curr);
- }
- // VAR a, GETOBJREF 0 -> PshVPtr a
- else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 )
- {
- ChangeFirstDeleteNext(curr, asBC_PshVPtr);
- instr = GoForward(curr);
- }
- // VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF
- if( curr->next && curr->next->op == asBC_PSF &&
- curr->next->next && curr->next->next->op == asBC_GETREF &&
- curr->next->next->wArg[0] == AS_PTR_SIZE )
- {
- curr->op = asBC_PSF;
- DeleteInstruction(curr->next->next);
- instr = GoForward(curr);
- }
- }
- }
- // Optimize unnecessary refcpy for return handle. This scenario only happens for return statements
- // and LOADOBJ can only be the last instruction before the RET, so doing this check after the rest of
- // the optimizations have taken place saves us time.
- if( last && last->op == asBC_LOADOBJ && IsTemporary(last->wArg[0]) )
- {
- // A temporary handle is being loaded into the object register.
- // Let's look for a trivial RefCpyV to that temporary variable, and a Free of the original
- // variable. If this is found, then we can simply load the original value into the register
- // and avoid both the RefCpy and the Free.
- short tempVar = last->wArg[0];
- asCArray<short> freedVars;
- instr = last->prev;
- asASSERT( instr && instr->op == asBC_Block );
- instr = instr->prev;
- while( instr && instr->op == asBC_FREE )
- {
- freedVars.PushLast(instr->wArg[0]);
- instr = instr->prev;
- }
- // If there is any non-trivial cleanups, e.g. call to destructors, then we skip this optimizations
- // TODO: runtime optimize: Do we need to skip it? Is there really a chance the local variable
- // will be invalidated while the destructor, or any other function for
- // that matter, is being called?
- if( instr && instr->op == asBC_Block )
- {
- // We expect a sequence PshVPtr, RefCpyV, PopPtr just before the clean up block
- instr = instr->prev;
- if( instr && instr->op == asBC_PopPtr ) instr = instr->prev;
- if( instr && instr->op == asBC_RefCpyV && instr->wArg[0] == tempVar ) instr = instr->prev;
- if( instr && instr->op == asBC_PshVPtr && freedVars.Exists(instr->wArg[0]) )
- {
- // Update the LOADOBJ to load the local variable directly
- tempVar = instr->wArg[0];
- last->wArg[0] = tempVar;
- // Remove the copy of the local variable into the temp
- DeleteInstruction(instr->next); // deletes RefCpyV
- DeleteInstruction(instr->next); // deletes PopPtr
- DeleteInstruction(instr); // deletes PshVPtr
- // Find and remove the FREE instruction for the local variable too
- instr = last->prev->prev;
- while( instr )
- {
- asASSERT( instr->op == asBC_FREE );
- if( instr->wArg[0] == tempVar )
- {
- DeleteInstruction(instr);
- break;
- }
- instr = instr->prev;
- }
- }
- }
- }
- }
- void asCByteCode::Optimize()
- {
- // This function performs the optimizations that require global knowledge of the entire function
- TimeIt("asCByteCode::Optimize");
- if( !engine->ep.optimizeByteCode )
- return;
- // TODO: runtime optimize: The optimizer should be able to inline function calls.
- // If the called function has only a few instructions, the function call should be inlined.
- // This is especially useful with the factory stubs used for template types and script classes.
- asCByteInstruction *instr = first;
- while( instr )
- {
- asCByteInstruction *curr = instr;
- instr = instr->next;
- const asEBCInstr currOp = curr->op;
- // Delete JitEntry if the JIT instructions are not supposed to be included
- if( currOp == asBC_JitEntry && !engine->ep.includeJitInstructions )
- {
- instr = GoBack(DeleteInstruction(curr));
- continue;
- }
- if( instr )
- {
- const asEBCInstr instrOp = instr->op;
- // PopPtr, RET b -> RET b
- if( currOp == asBC_PopPtr && instrOp == asBC_RET )
- {
- // We don't combine the PopPtr+RET because RET first restores
- // the previous stack pointer and then pops the arguments
- // Delete PopPtr
- instr = GoBack(DeleteInstruction(curr));
- }
- else if( currOp == asBC_SUSPEND )
- {
- // SUSPEND, JitEntry, SUSPEND -> SUSPEND
- if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_SUSPEND )
- {
- // Delete the two first instructions
- DeleteInstruction(instr);
- instr = GoBack(DeleteInstruction(curr));
- }
- // SUSPEND, SUSPEND -> SUSPEND
- else if( instrOp == asBC_SUSPEND )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- // SUSPEND, Block, SUSPEND -> Block, SUSPEND
- else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_SUSPEND )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- }
- else if( currOp == asBC_LINE )
- {
- // LINE, JitEntry, LINE -> LINE
- if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_LINE )
- {
- // Delete the two first instructions
- DeleteInstruction(instr);
- instr = GoBack(DeleteInstruction(curr));
- }
- // LINE, VarDecl, LINE -> VarDecl, LINE
- else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- // LINE, LINE -> LINE
- else if( instrOp == asBC_LINE )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- // LINE, Block, LINE -> Block, LINE
- else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_LINE )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- }
- // JMP +0 -> remove
- else if( currOp == asBC_JMP && instrOp == asBC_LABEL && *(int*)&curr->arg == instr->wArg[0] )
- instr = GoBack(DeleteInstruction(curr));
- }
- }
- }
- bool asCByteCode::IsTempVarReadByInstr(asCByteInstruction *curr, int offset)
- {
- // Which instructions read from variables?
- if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG &&
- (int(curr->wArg[1]) == offset || int(curr->wArg[2]) == offset) )
- return true;
- else if( (asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_QW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ||
- curr->op == asBC_FREE) && // FREE both read and write to the variable
- int(curr->wArg[0]) == offset )
- return true;
- else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) &&
- int(curr->wArg[1]) == offset )
- return true;
- else if( asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG &&
- (int(curr->wArg[0]) == offset || int(curr->wArg[1]) == offset) )
- return true;
- else if( curr->op == asBC_LoadThisR && offset == 0 )
- return true;
- return false;
- }
- bool asCByteCode::IsInstrJmpOrLabel(asCByteInstruction *curr)
- {
- if( curr->op == asBC_JS ||
- curr->op == asBC_JNS ||
- curr->op == asBC_JP ||
- curr->op == asBC_JNP ||
- curr->op == asBC_JMPP ||
- curr->op == asBC_JMP ||
- curr->op == asBC_JZ ||
- curr->op == asBC_JNZ ||
- curr->op == asBC_JLowZ ||
- curr->op == asBC_JLowNZ ||
- curr->op == asBC_LABEL )
- return true;
- return false;
- }
- bool asCByteCode::IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int offset)
- {
- // Which instructions overwrite the variable or discard it?
- if( curr->op == asBC_RET ||
- curr->op == asBC_SUSPEND )
- return true;
- else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) &&
- int(curr->wArg[0]) == offset )
- return true;
- return false;
- }
- bool asCByteCode::IsTempVarRead(asCByteInstruction *curr, int offset)
- {
- TimeIt("asCByteCode::IsTempVarRead");
- asCArray<asCByteInstruction *> openPaths;
- asCArray<asCByteInstruction *> closedPaths;
- // We're not interested in the first instruction, since it is the one that sets the variable
- openPaths.PushLast(curr->next);
- while( openPaths.GetLength() )
- {
- curr = openPaths.PopLast();
- // Add the instruction to the closed paths so that we don't verify it again
- closedPaths.PushLast(curr);
- while( curr )
- {
- if( IsTempVarReadByInstr(curr, offset) )
- return true;
- if( IsTempVarOverwrittenByInstr(curr, offset) ) break;
- // In case of jumps, we must follow the each of the paths
- if( curr->op == asBC_JMP )
- {
- // Find the destination. If it cannot be found it is because we're doing a localized
- // optimization and the label hasn't been added to the final bytecode yet
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &curr, 0);
- if( r >= 0 &&
- !closedPaths.Exists(curr) &&
- !openPaths.Exists(curr) )
- openPaths.PushLast(curr);
- break;
- }
- else if( curr->op == asBC_JZ || curr->op == asBC_JNZ ||
- curr->op == asBC_JS || curr->op == asBC_JNS ||
- curr->op == asBC_JP || curr->op == asBC_JNP ||
- curr->op == asBC_JLowZ || curr->op == asBC_JLowNZ )
- {
- // Find the destination. If it cannot be found it is because we're doing a localized
- // optimization and the label hasn't been added to the final bytecode yet
- asCByteInstruction *dest = 0;
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &dest, 0);
- if( r >= 0 &&
- !closedPaths.Exists(dest) &&
- !openPaths.Exists(dest) )
- openPaths.PushLast(dest);
- }
- else if( curr->op == asBC_JMPP )
- {
- // A JMPP instruction is always followed by a series of JMP instructions
- // that give the real destination (like a look-up table). We need add all
- // of these as open paths.
- curr = curr->next;
- while( curr->op == asBC_JMP )
- {
- // Find the destination. If it cannot be found it is because we're doing a localized
- // optimization and the label hasn't been added to the final bytecode yet
- asCByteInstruction *dest = 0;
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &dest, 0);
- if( r >= 0 &&
- !closedPaths.Exists(dest) &&
- !openPaths.Exists(dest) )
- openPaths.PushLast(dest);
- curr = curr->next;
- }
- // We should now be on a label which is the destination of the
- // first JMP in the sequence and is already added in the open paths
- asASSERT(curr->op == asBC_LABEL);
- break;
- }
- curr = curr->next;
- }
- }
- return false;
- }
- bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr)
- {
- TimeIt("asCByteCode::IsTempRegUsed");
- // We're not interested in the first instruction, since it is the one that sets the register
- while( curr->next )
- {
- curr = curr->next;
- // Which instructions read from the register?
- if( curr->op == asBC_INCi ||
- curr->op == asBC_INCi16 ||
- curr->op == asBC_INCi8 ||
- curr->op == asBC_INCf ||
- curr->op == asBC_INCd ||
- curr->op == asBC_DECi ||
- curr->op == asBC_DECi16 ||
- curr->op == asBC_DECi8 ||
- curr->op == asBC_DECf ||
- curr->op == asBC_DECd ||
- curr->op == asBC_WRTV1 ||
- curr->op == asBC_WRTV2 ||
- curr->op == asBC_WRTV4 ||
- curr->op == asBC_WRTV8 ||
- curr->op == asBC_RDR1 ||
- curr->op == asBC_RDR2 ||
- curr->op == asBC_RDR4 ||
- curr->op == asBC_RDR8 ||
- curr->op == asBC_PshRPtr ||
- curr->op == asBC_CpyRtoV4 ||
- curr->op == asBC_CpyRtoV8 ||
- curr->op == asBC_TZ ||
- curr->op == asBC_TNZ ||
- curr->op == asBC_TS ||
- curr->op == asBC_TNS ||
- curr->op == asBC_TP ||
- curr->op == asBC_TNP ||
- curr->op == asBC_JZ ||
- curr->op == asBC_JNZ ||
- curr->op == asBC_JLowZ ||
- curr->op == asBC_JLowNZ ||
- curr->op == asBC_JS ||
- curr->op == asBC_JNS ||
- curr->op == asBC_JP ||
- curr->op == asBC_JNP )
- return true;
- // Which instructions overwrite the register or discard the value?
- if( curr->op == asBC_CALL ||
- curr->op == asBC_PopRPtr ||
- curr->op == asBC_CALLSYS ||
- curr->op == asBC_CALLBND ||
- curr->op == asBC_Thiscall1 ||
- curr->op == asBC_SUSPEND ||
- curr->op == asBC_ALLOC ||
- curr->op == asBC_CpyVtoR4 ||
- curr->op == asBC_LdGRdR4 ||
- curr->op == asBC_LDG ||
- curr->op == asBC_LDV ||
- curr->op == asBC_TZ ||
- curr->op == asBC_TNZ ||
- curr->op == asBC_TS ||
- curr->op == asBC_TNS ||
- curr->op == asBC_TP ||
- curr->op == asBC_TNP ||
- curr->op == asBC_JS ||
- curr->op == asBC_JNS ||
- curr->op == asBC_JP ||
- curr->op == asBC_JNP ||
- curr->op == asBC_JMPP ||
- curr->op == asBC_JMP ||
- curr->op == asBC_JZ ||
- curr->op == asBC_JNZ ||
- curr->op == asBC_JLowZ ||
- curr->op == asBC_JLowNZ ||
- curr->op == asBC_CMPi ||
- curr->op == asBC_CMPu ||
- curr->op == asBC_CMPf ||
- curr->op == asBC_CMPd ||
- curr->op == asBC_CMPIi ||
- curr->op == asBC_CMPIu ||
- curr->op == asBC_CMPIf ||
- curr->op == asBC_LABEL ||
- curr->op == asBC_LoadThisR ||
- curr->op == asBC_LoadRObjR ||
- curr->op == asBC_LoadVObjR )
- return false;
- }
- return false;
- }
- bool asCByteCode::IsSimpleExpression()
- {
- // A simple expression is one that cannot be suspended at any time, i.e.
- // it doesn't have any calls to other routines, and doesn't have any suspend instructions
- asCByteInstruction *instr = first;
- while( instr )
- {
- if( instr->op == asBC_ALLOC ||
- instr->op == asBC_CALL ||
- instr->op == asBC_CALLSYS ||
- instr->op == asBC_SUSPEND ||
- instr->op == asBC_LINE ||
- instr->op == asBC_FREE ||
- instr->op == asBC_CallPtr ||
- instr->op == asBC_CALLINTF ||
- instr->op == asBC_CALLBND ||
- instr->op == asBC_Thiscall1 )
- return false;
- instr = instr->next;
- }
- return true;
- }
- void asCByteCode::ExtractLineNumbers()
- {
- // This function will extract the line number and source file for each statement by looking for LINE instructions.
- // The LINE instructions will be converted to SUSPEND instructions, or removed depending on the configuration.
- TimeIt("asCByteCode::ExtractLineNumbers");
- int lastLinePos = -1;
- int pos = 0;
- asCByteInstruction *instr = first;
- while( instr )
- {
- asCByteInstruction *curr = instr;
- instr = instr->next;
- if( curr->op == asBC_LINE )
- {
- if( lastLinePos == pos )
- {
- lineNumbers.PopLast(); // pop position
- lineNumbers.PopLast(); // pop line number
- sectionIdxs.PopLast(); // pop section index
- }
- lastLinePos = pos;
- lineNumbers.PushLast(pos);
- lineNumbers.PushLast(*(int*)ARG_DW(curr->arg));
- sectionIdxs.PushLast(*((int*)ARG_DW(curr->arg)+1));
- if( !engine->ep.buildWithoutLineCues )
- {
- // Transform BC_LINE into BC_SUSPEND
- curr->op = asBC_SUSPEND;
- curr->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type];
- pos += curr->size;
- }
- else
- {
- // Delete the instruction
- DeleteInstruction(curr);
- }
- }
- else
- pos += curr->size;
- }
- }
- void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc)
- {
- asASSERT( outFunc->scriptData );
- unsigned int pos = 0;
- asCByteInstruction *instr = first;
- int blockLevel = 0;
- while( instr )
- {
- if( instr->op == asBC_Block )
- {
- asSObjectVariableInfo info;
- info.programPos = pos;
- info.variableOffset = 0;
- info.option = instr->wArg[0] ? asBLOCK_BEGIN : asBLOCK_END;
- if( info.option == asBLOCK_BEGIN )
- {
- blockLevel++;
- outFunc->scriptData->objVariableInfo.PushLast(info);
- }
- else
- {
- blockLevel--;
- asASSERT( blockLevel >= 0 );
- if( outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].option == asBLOCK_BEGIN &&
- outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].programPos == pos )
- outFunc->scriptData->objVariableInfo.PopLast();
- else
- outFunc->scriptData->objVariableInfo.PushLast(info);
- }
- }
- else if( instr->op == asBC_ObjInfo )
- {
- asSObjectVariableInfo info;
- info.programPos = pos;
- info.variableOffset = (short)instr->wArg[0];
- info.option = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg);
- outFunc->scriptData->objVariableInfo.PushLast(info);
- }
- else if( instr->op == asBC_VarDecl )
- {
- // Record the position for debug info
- outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos;
-
- // Record declaration of object variables for try/catch handling
- // This is used for identifying if handles and objects on the heap should be cleared upon catching an exception
- // Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space
- if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() )
- {
- asSObjectVariableInfo info;
- info.programPos = pos;
- info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset;
- info.option = asOBJ_VARDECL;
- outFunc->scriptData->objVariableInfo.PushLast(info);
- }
- }
- else
- pos += instr->size;
- instr = instr->next;
- }
- asASSERT( blockLevel == 0 );
- }
- void asCByteCode::ExtractTryCatchInfo(asCScriptFunction *outFunc)
- {
- asASSERT(outFunc->scriptData);
- unsigned int pos = 0;
- asCByteInstruction *instr = first;
- while (instr)
- {
- if (instr->op == asBC_TryBlock)
- {
- asSTryCatchInfo info;
- info.tryPos = pos;
- info.catchPos = *ARG_DW(instr->arg);
- outFunc->scriptData->tryCatchInfo.PushLast(info);
- }
- pos += instr->size;
- instr = instr->next;
- }
- }
- int asCByteCode::GetSize()
- {
- int size = 0;
- asCByteInstruction *instr = first;
- while( instr )
- {
- size += instr->GetSize();
- instr = instr->next;
- }
- return size;
- }
- void asCByteCode::AddCode(asCByteCode *bc)
- {
- if( bc == this ) return;
- if( bc->first )
- {
- if( first == 0 )
- {
- first = bc->first;
- last = bc->last;
- bc->first = 0;
- bc->last = 0;
- }
- else
- {
- last->next = bc->first;
- bc->first->prev = last;
- last = bc->last;
- bc->first = 0;
- bc->last = 0;
- }
- }
- }
- int asCByteCode::AddInstruction()
- {
- void *ptr = engine->memoryMgr.AllocByteInstruction();
- if( ptr == 0 )
- {
- // Out of memory
- return 0;
- }
- asCByteInstruction *instr = new(ptr) asCByteInstruction();
- if( first == 0 )
- {
- first = last = instr;
- }
- else
- {
- last->AddAfter(instr);
- last = instr;
- }
- return 0;
- }
- int asCByteCode::AddInstructionFirst()
- {
- void *ptr = engine->memoryMgr.AllocByteInstruction();
- if( ptr == 0 )
- {
- // Out of memory
- return 0;
- }
- asCByteInstruction *instr = new(ptr) asCByteInstruction();
- if( first == 0 )
- {
- first = last = instr;
- }
- else
- {
- first->AddBefore(instr);
- first = instr;
- }
- return 0;
- }
- void asCByteCode::Call(asEBCInstr instr, int funcID, int pop)
- {
- if( AddInstruction() < 0 )
- return;
- asASSERT(asBCInfo[instr].type == asBCTYPE_DW_ARG);
- last->op = instr;
- last->size = asBCTypeSize[asBCInfo[instr].type];
- last->stackInc = -pop; // BC_CALL and BC_CALLBND doesn't pop the argument but when the callee returns the arguments are already popped
- *((int*)ARG_DW(last->arg)) = funcID;
- // Add a JitEntry instruction after function calls so that JIT's can resume execution
- InstrPTR(asBC_JitEntry, 0);
- }
- void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop)
- {
- if( AddInstruction() < 0 )
- return;
- asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG);
- last->op = instr;
- last->size = asBCTypeSize[asBCInfo[instr].type];
- last->stackInc = -pop;
- last->wArg[0] = (short)funcPtrVar;
- // Add a JitEntry instruction after function calls so that JIT's can resume execution
- InstrPTR(asBC_JitEntry, 0);
- }
- void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop)
- {
- if( AddInstruction() < 0 )
- return;
- last->op = instr;
- last->size = asBCTypeSize[asBCInfo[instr].type];
- last->stackInc = -pop; // BC_ALLOC
- asASSERT(asBCInfo[instr].type == asBCTYPE_PTR_DW_ARG);
- *ARG_PTR(last->arg) = (asPWORD)objID;
- *((int*)(ARG_DW(last->arg)+AS_PTR_SIZE)) = funcID;
- // Add a JitEntry instruction after function calls so that JIT's can resume execution
- InstrPTR(asBC_JitEntry, 0);
- }
- void asCByteCode::Ret(int pop)
- {
- if( AddInstruction() < 0 )
- return;
- asASSERT(asBCInfo[asBC_RET].type == asBCTYPE_W_ARG);
- last->op = asBC_RET;
- last->size = asBCTypeSize[asBCInfo[asBC_RET].type];
- last->stackInc = 0; // The instruction pops the argument, but it doesn't affect current function
- last->wArg[0] = (short)pop;
- }
- void asCByteCode::JmpP(int var, asDWORD max)
- {
- if( AddInstruction() < 0 )
- return;
- asASSERT(asBCInfo[asBC_JMPP].type == asBCTYPE_rW_ARG);
- last->op = asBC_JMPP;
- last->size = asBCTypeSize[asBCInfo[asBC_JMPP].type];
- last->stackInc = asBCInfo[asBC_JMPP].stackInc;
- last->wArg[0] = (short)var;
- // Store the largest jump that is made for PostProcess()
- *ARG_DW(last->arg) = max;
- }
- void asCByteCode::Label(short label)
- {
- if( AddInstruction() < 0 )
- return;
- last->op = asBC_LABEL;
- last->size = 0;
- last->stackInc = 0;
- last->wArg[0] = label;
- }
- void asCByteCode::Line(int line, int column, int scriptIdx)
- {
- if( AddInstruction() < 0 )
- return;
- last->op = asBC_LINE;
- // If the build is without line cues these instructions will be removed
- // otherwise they will be transformed into SUSPEND instructions.
- if( engine->ep.buildWithoutLineCues )
- last->size = 0;
- else
- last->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type];
- last->stackInc = 0;
- *((int*)ARG_DW(last->arg)) = (line & 0xFFFFF)|((column & 0xFFF)<<20);
- *((int*)ARG_DW(last->arg)+1) = scriptIdx;
- // Add a JitEntry after the line instruction to allow the JIT function to resume after a suspend
- InstrPTR(asBC_JitEntry, 0);
- }
- void asCByteCode::ObjInfo(int offset, int info)
- {
- if( AddInstruction() < 0 )
- return;
- // Add the special instruction that will be used to tell the exception
- // handler when an object is initialized and deinitialized.
- last->op = asBC_ObjInfo;
- last->size = 0;
- last->stackInc = 0;
- last->wArg[0] = (short)offset;
- *((int*)ARG_DW(last->arg)) = info;
- }
- void asCByteCode::Block(bool start)
- {
- if( AddInstruction() < 0 )
- return;
- last->op = asBC_Block;
- last->size = 0;
- last->stackInc = 0;
- last->wArg[0] = start ? 1 : 0;
- }
- void asCByteCode::TryBlock(short catchLabel)
- {
- if (AddInstruction() < 0)
- return;
- last->op = asBC_TryBlock;
- last->size = 0;
- last->stackInc = 0;
- *ARG_DW(last->arg) = catchLabel;
- }
- void asCByteCode::VarDecl(int varDeclIdx)
- {
- if( AddInstruction() < 0 )
- return;
- last->op = asBC_VarDecl;
- last->size = 0;
- last->stackInc = 0;
- last->wArg[0] = asWORD(varDeclIdx);
- }
- int asCByteCode::FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta)
- {
- TimeIt("asCByteCode::FindLabel");
- // Search forward
- int labelPos = -from->GetSize();
- asCByteInstruction *labelInstr = from;
- while( labelInstr )
- {
- labelPos += labelInstr->GetSize();
- labelInstr = labelInstr->next;
- if( labelInstr && labelInstr->op == asBC_LABEL )
- {
- if( labelInstr->wArg[0] == label )
- break;
- }
- }
- if( labelInstr == 0 )
- {
- // Search backwards
- labelPos = -from->GetSize();
- labelInstr = from;
- while( labelInstr )
- {
- labelInstr = labelInstr->prev;
- if( labelInstr )
- {
- labelPos -= labelInstr->GetSize();
- if( labelInstr->op == asBC_LABEL )
- {
- if( labelInstr->wArg[0] == label )
- break;
- }
- }
- }
- }
- if( labelInstr != 0 )
- {
- if( dest ) *dest = labelInstr;
- if( positionDelta ) *positionDelta = labelPos;
- return 0;
- }
- return -1;
- }
- int asCByteCode::ResolveJumpAddresses()
- {
- TimeIt("asCByteCode::ResolveJumpAddresses");
- asUINT currPos = 0;
- asCByteInstruction *instr = first;
- while( instr )
- {
- if( instr->op == asBC_JMP ||
- instr->op == asBC_JZ || instr->op == asBC_JNZ ||
- instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
- instr->op == asBC_JS || instr->op == asBC_JNS ||
- instr->op == asBC_JP || instr->op == asBC_JNP )
- {
- int label = *((int*) ARG_DW(instr->arg));
- int labelPosOffset;
- int r = FindLabel(label, instr, 0, &labelPosOffset);
- if( r == 0 )
- *((int*) ARG_DW(instr->arg)) = labelPosOffset;
- else
- return -1;
- }
- else if (instr->op == asBC_TryBlock)
- {
- int label = *((int*)ARG_DW(instr->arg));
- int labelPosOffset;
- int r = FindLabel(label, instr, 0, &labelPosOffset);
- if (r == 0)
- {
- // Should store the absolute address so the exception handler doesn't need to figure it out
- *((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset;
- }
- else
- return -1;
- }
- currPos += instr->GetSize();
- instr = instr->next;
- }
- return 0;
- }
- asCByteInstruction *asCByteCode::DeleteInstruction(asCByteInstruction *instr)
- {
- if( instr == 0 ) return 0;
- asCByteInstruction *ret = instr->prev ? instr->prev : instr->next;
- RemoveInstruction(instr);
- engine->memoryMgr.FreeByteInstruction(instr);
- return ret;
- }
- void asCByteCode::Output(asDWORD *array)
- {
- TimeIt("asCByteCode::Output");
- // TODO: Receive a script function pointer instead of the bytecode array
- asDWORD *ap = array;
- asCByteInstruction *instr = first;
- while( instr )
- {
- if( instr->GetSize() > 0 )
- {
- *(asBYTE*)ap = asBYTE(instr->op);
- *(((asBYTE*)ap)+1) = 0; // Second byte is always zero
- switch( asBCInfo[instr->op].type )
- {
- case asBCTYPE_NO_ARG:
- *(((asWORD*)ap)+1) = 0; // Clear upper bytes
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- *(((asWORD*)ap)+2) = instr->wArg[1];
- *(((asWORD*)ap)+3) = instr->wArg[2];
- break;
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- *(ap+1) = *(asDWORD*)&instr->arg;
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- *(((asWORD*)ap)+2) = instr->wArg[1];
- *(ap+2) = *(asDWORD*)&instr->arg;
- break;
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_QW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- *(asQWORD*)(ap+1) = asQWORD(instr->arg);
- break;
- case asBCTYPE_W_ARG:
- case asBCTYPE_rW_ARG:
- case asBCTYPE_wW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- case asBCTYPE_wW_W_ARG:
- *(((asWORD *)ap)+1) = instr->wArg[0];
- *(((asWORD *)ap)+2) = instr->wArg[1];
- break;
- case asBCTYPE_QW_DW_ARG:
- case asBCTYPE_DW_DW_ARG:
- case asBCTYPE_QW_ARG:
- case asBCTYPE_DW_ARG:
- *(((asWORD*)ap)+1) = 0; // Clear upper bytes
- memcpy(ap+1, &instr->arg, instr->GetSize()*4-4);
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- *(((asWORD*)ap)+1) = instr->wArg[0];
- memcpy(ap+1, &instr->arg, instr->GetSize()*4-4);
- break;
- default:
- // How did we get here?
- asASSERT(false);
- break;
- }
- }
- ap += instr->GetSize();
- instr = instr->next;
- }
- }
- void asCByteCode::PostProcess()
- {
- TimeIt("asCByteCode::PostProcess");
- if( first == 0 ) return;
- // This function will do the following
- // - Verify if there is any code that never gets executed and remove it
- // - Calculate the stack size at the position of each byte code
- // - Calculate the largest stack needed
- largestStackUsed = 0;
- asCByteInstruction *instr = first;
- while( instr )
- {
- instr->marked = false;
- instr->stackSize = -1;
- instr = instr->next;
- }
- // Add the first instruction to the list of unchecked code paths
- asCArray<asCByteInstruction *> paths;
- AddPath(paths, first, 0);
- // Go through each of the code paths
- for( asUINT p = 0; p < paths.GetLength(); ++p )
- {
- instr = paths[p];
- int stackSize = instr->stackSize;
- while( instr )
- {
- instr->marked = true;
- instr->stackSize = stackSize;
- stackSize += instr->stackInc;
- if( stackSize > largestStackUsed )
- largestStackUsed = stackSize;
- if( instr->op == asBC_JMP )
- {
- // Find the label that we should jump to
- int label = *((int*) ARG_DW(instr->arg));
- asCByteInstruction *dest = 0;
- int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
- AddPath(paths, dest, stackSize);
- break;
- }
- else if( instr->op == asBC_JZ || instr->op == asBC_JNZ ||
- instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
- instr->op == asBC_JS || instr->op == asBC_JNS ||
- instr->op == asBC_JP || instr->op == asBC_JNP ||
- instr->op == asBC_TryBlock )
- {
- // Find the label that is being jumped to
- int label = *((int*) ARG_DW(instr->arg));
- asCByteInstruction *dest = 0;
- int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
- AddPath(paths, dest, stackSize);
- // Add both paths to the code paths
- AddPath(paths, instr->next, stackSize);
- break;
- }
- else if( instr->op == asBC_JMPP )
- {
- // I need to know the largest value possible
- asDWORD max = *ARG_DW(instr->arg);
- // Add all destinations to the code paths
- asCByteInstruction *dest = instr->next;
- for( asDWORD n = 0; n <= max && dest != 0; ++n )
- {
- AddPath(paths, dest, stackSize);
- dest = dest->next;
- }
- break;
- }
- else
- {
- instr = instr->next;
- if( instr == 0 || instr->marked )
- break;
- }
- }
- }
- // Are there any instructions that didn't get visited?
- instr = first;
- while( instr )
- {
- // Don't remove asBC_Block instructions as then the start and end of blocks may become mismatched
- if( instr->marked == false && instr->op != asBC_Block )
- {
- // Remove it
- asCByteInstruction *curr = instr;
- instr = instr->next;
- DeleteInstruction(curr);
- }
- else
- {
- #ifndef AS_DEBUG
- // If the stackSize is negative, then there is a problem with the bytecode.
- // If AS_DEBUG is turned on, this same check is done in DebugOutput.
- asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO );
- #endif
- instr = instr->next;
- }
- }
- }
- #ifdef AS_DEBUG
- void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func)
- {
- #ifndef __MINGW32__
- // _mkdir is broken on mingw
- _mkdir("AS_DEBUG");
- #endif
- asCString path = "AS_DEBUG/";
- path += name;
- // Anonymous functions created from within class methods will contain :: as part of the name
- // Replace :: with __ to avoid error when creating the file for debug output
- for (asUINT n = 0; n < path.GetLength(); n++)
- if (path[n] == ':') path[n] = '_';
- #if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
- FILE *file;
- fopen_s(&file, path.AddressOf(), "w");
- #else
- FILE *file = fopen(path.AddressOf(), "w");
- #endif
- #if !defined(AS_XENON) && !defined(__MINGW32__)
- // XBox 360: When running in DVD Emu, no write is allowed
- // MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist
- asASSERT( file );
- #endif
- if( file == 0 )
- return;
- asUINT n;
- fprintf(file, "%s\n\n", func->GetDeclaration());
- fprintf(file, "Temps: ");
- for( n = 0; n < temporaryVariables->GetLength(); n++ )
- {
- fprintf(file, "%d", (*temporaryVariables)[n]);
- if( n < temporaryVariables->GetLength()-1 )
- fprintf(file, ", ");
- }
- fprintf(file, "\n\n");
- fprintf(file, "Variables: \n");
- for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
- {
- int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->variables[n]->stackOffset);
- bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
- fprintf(file, " %.3d: %s%s %s\n", func->scriptData->variables[n]->stackOffset, isOnHeap ? "(heap) " : "", func->scriptData->variables[n]->type.Format(func->nameSpace, true).AddressOf(), func->scriptData->variables[n]->name.AddressOf());
- }
- asUINT offset = 0;
- if( func->objectType )
- {
- fprintf(file, " %.3d: %s this\n", 0, func->objectType->name.AddressOf());
- offset -= AS_PTR_SIZE;
- }
- for( n = 0; n < func->parameterTypes.GetLength(); n++ )
- {
- bool found = false;
- for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ )
- {
- if( func->scriptData->variables[v]->stackOffset == (int)offset )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- int idx = func->scriptData->objVariablePos.IndexOf(offset);
- bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
- fprintf(file, " %.3d: %s%s {noname param}\n", offset, isOnHeap ? "(heap) " : "", func->parameterTypes[n].Format(func->nameSpace, true).AddressOf());
- }
- offset -= func->parameterTypes[n].GetSizeOnStackDWords();
- }
- for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
- {
- bool found = false;
- for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ )
- {
- if( func->scriptData->variables[v]->stackOffset == func->scriptData->objVariablePos[n] )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- if( func->scriptData->objVariableTypes[n] )
- {
- int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->objVariablePos[n]);
- bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
- fprintf(file, " %.3d: %s%s {noname}\n", func->scriptData->objVariablePos[n], isOnHeap ? "(heap) " : "", func->scriptData->objVariableTypes[n]->name.AddressOf());
- }
- else
- fprintf(file, " %.3d: null handle {noname}\n", func->scriptData->objVariablePos[n]);
- }
- }
- fprintf(file, "\n\n");
- bool invalidStackSize = false;
- int pos = 0;
- asUINT lineIndex = 0;
- asCByteInstruction *instr = first;
- while( instr )
- {
- if( lineIndex < lineNumbers.GetLength() && lineNumbers[lineIndex] == pos )
- {
- asDWORD line = lineNumbers[lineIndex+1];
- fprintf(file, "- %d,%d -\n", (int)(line&0xFFFFF), (int)(line>>20));
- lineIndex += 2;
- }
- if( instr->GetSize() > 0 )
- {
- fprintf(file, "%5d ", pos);
- pos += instr->GetSize();
- fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' ');
- if( instr->stackSize < 0 )
- invalidStackSize = true;
- }
- else
- {
- fprintf(file, " ");
- }
- switch( asBCInfo[instr->op].type )
- {
- case asBCTYPE_W_ARG:
- fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]);
- break;
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_ARG:
- fprintf(file, " %-8s v%d\n", asBCInfo[instr->op].name, instr->wArg[0]);
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- fprintf(file, " %-8s v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]);
- break;
- case asBCTYPE_wW_W_ARG:
- fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]);
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- switch( instr->op )
- {
- case asBC_ADDIf:
- case asBC_SUBIf:
- case asBC_MULIf:
- fprintf(file, " %-8s v%d, v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((float*) ARG_DW(instr->arg)));
- break;
- default:
- fprintf(file, " %-8s v%d, v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((int*) ARG_DW(instr->arg)));
- break;
- }
- break;
- case asBCTYPE_DW_ARG:
- switch( instr->op )
- {
- case asBC_OBJTYPE:
- {
- asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
- fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName());
- }
- break;
- case asBC_FuncPtr:
- {
- asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration());
- }
- break;
- case asBC_PshC4:
- case asBC_Cast:
- fprintf(file, " %-8s 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg)));
- break;
- case asBC_TYPEID:
- fprintf(file, " %-8s 0x%x '%s'\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), engine->GetTypeDeclaration((int)*ARG_DW(instr->arg)));
- break;
- case asBC_CALL:
- case asBC_CALLSYS:
- case asBC_CALLBND:
- case asBC_CALLINTF:
- case asBC_Thiscall1:
- {
- int funcID = *(int*)ARG_DW(instr->arg);
- asCString decl = engine->GetFunctionDeclaration(funcID);
- fprintf(file, " %-8s %d (%s)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), decl.AddressOf());
- }
- break;
- case asBC_REFCPY:
- fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)));
- break;
- case asBC_JMP:
- case asBC_JZ:
- case asBC_JLowZ:
- case asBC_JS:
- case asBC_JP:
- case asBC_JNZ:
- case asBC_JLowNZ:
- case asBC_JNS:
- case asBC_JNP:
- fprintf(file, " %-8s %+d (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg)));
- break;
- default:
- fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)));
- break;
- }
- break;
- case asBCTYPE_QW_ARG:
- switch( instr->op )
- {
- case asBC_OBJTYPE:
- {
- asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
- fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName());
- }
- break;
- case asBC_FuncPtr:
- {
- asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration());
- }
- break;
- case asBC_PGA:
- {
- void *ptr = *(void**)ARG_QW(instr->arg);
- asSMapNode<void*, asCGlobalProperty*> *cursor = 0;
- if( engine->varAddressMap.MoveTo(&cursor, ptr) )
- {
- fprintf(file, " %-8s 0x%x (var:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), cursor->value->name.AddressOf());
- }
- else
- {
- asUINT length;
- engine->stringFactory->GetRawStringData(ptr, 0, &length);
- asCString str;
- str.SetLength(length);
- engine->stringFactory->GetRawStringData(ptr, str.AddressOf(), &length);
- if (str.GetLength() > 20)
- {
- // TODO: Replace non-visible characters with space or something like it
- str.SetLength(20);
- str += "...";
- }
- fprintf(file, " %-8s 0x%x (str:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), str.AddressOf());
- }
- }
- break;
-
- default:
- #ifdef __GNUC__
- #ifdef _LP64
- fprintf(file, " %-8s 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #else
- fprintf(file, " %-8s 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #endif
- #else
- fprintf(file, " %-8s 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #endif
- }
- break;
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_QW_ARG:
- switch( instr->op )
- {
- case asBC_RefCpyV:
- case asBC_FREE:
- {
- asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
- fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName());
- }
- break;
- default:
- #ifdef __GNUC__
- #ifdef _LP64
- fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #else
- fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #endif
- #else
- fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
- #endif
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- if( instr->op == asBC_ALLOC )
- {
- asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
- asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
- fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
- }
- else
- fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1));
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- fprintf(file, " %-8s v%d, %u, %u\n", asBCInfo[instr->op].name, instr->wArg[0], *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1));
- break;
- case asBCTYPE_QW_DW_ARG:
- if( instr->op == asBC_ALLOC )
- {
- asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
- asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
- #if defined(__GNUC__) && !defined(_MSC_VER)
- #ifdef AS_64BIT_PTR
- fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
- #else
- fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
- #endif
- #else
- fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
- #endif
- }
- else
- #if defined(__GNUC__) && !defined(_MSC_VER)
- #ifdef AS_64BIT_PTR
- fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
- #else
- fprintf(file, " %-8s %llu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
- #endif
- #else
- fprintf(file, " %-8s %I64u, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
- #endif
- break;
- case asBCTYPE_INFO:
- if( instr->op == asBC_LABEL )
- fprintf(file, "%d:\n", instr->wArg[0]);
- else if( instr->op == asBC_LINE )
- fprintf(file, " %s\n", asBCInfo[instr->op].name);
- else if( instr->op == asBC_Block )
- fprintf(file, "%c\n", instr->wArg[0] ? '{' : '}');
- break;
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- if( instr->op == asBC_SetV1 )
- fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asBYTE*)ARG_DW(instr->arg));
- else if( instr->op == asBC_SetV2 )
- fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asWORD*)ARG_DW(instr->arg));
- else if( instr->op == asBC_SetV4 )
- fprintf(file, " %-8s v%d, 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg)));
- else if( instr->op == asBC_CMPIf )
- fprintf(file, " %-8s v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], *(float*)ARG_DW(instr->arg));
- else
- fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg));
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- fprintf(file, " %-8s v%d, v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], instr->wArg[2]);
- break;
- case asBCTYPE_NO_ARG:
- fprintf(file, " %s\n", asBCInfo[instr->op].name);
- break;
- default:
- asASSERT(false);
- }
- instr = instr->next;
- }
- fclose(file);
- // If the stackSize is negative then there is something wrong with the
- // bytecode, i.e. there is a bug in the compiler or in the optimizer. We
- // only check this here to have the bytecode available on file for verification
- asASSERT( !invalidStackSize );
- }
- #endif
- //=============================================================================
- int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstructionFirst() < 0 )
- return 0;
- first->op = bc;
- *ARG_DW(first->arg) = param;
- first->size = asBCTypeSize[asBCInfo[bc].type];
- first->stackInc = asBCInfo[bc].stackInc;
- return first->stackInc;
- }
- int asCByteCode::InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstructionFirst() < 0 )
- return 0;
- first->op = bc;
- *ARG_QW(first->arg) = param;
- first->size = asBCTypeSize[asBCInfo[bc].type];
- first->stackInc = asBCInfo[bc].stackInc;
- return first->stackInc;
- }
- int asCByteCode::Instr(asEBCInstr bc)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_W_W(asEBCInstr bc, int a, int b, int c)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_rW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = (short)a;
- last->wArg[1] = (short)b;
- last->wArg[2] = (short)c;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_W(asEBCInstr bc, int a, int b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_rW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = (short)a;
- last->wArg[1] = (short)b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_PTR(asEBCInstr bc, short a, void *param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_PTR_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *ARG_PTR(last->arg) = (asPWORD)param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *((int*) ARG_DW(last->arg)) = b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_rW_DW_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *(int*)ARG_DW(last->arg) = b;
- *(int*)(ARG_DW(last->arg)+1) = c;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT_B(asEBCInstr bc, short a, asBYTE b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- // We'll have to be careful to store the byte correctly, independent of endianess.
- // Some optimizing compilers may change the order of operations, so we make sure
- // the value is not overwritten even if that happens.
- asBYTE *argPtr = (asBYTE*)ARG_DW(last->arg);
- argPtr[0] = b; // The value is always stored in the lower byte
- argPtr[1] = 0; // and clear the rest of the DWORD
- argPtr[2] = 0;
- argPtr[3] = 0;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT_W(asEBCInstr bc, short a, asWORD b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- // We'll have to be careful to store the word correctly, independent of endianess.
- // Some optimizing compilers may change the order of operations, so we make sure
- // the value is not overwritten even if that happens.
- asWORD *argPtr = (asWORD*)ARG_DW(last->arg);
- argPtr[0] = b; // The value is always stored in the lower word
- argPtr[1] = 0; // and clear the rest of the DWORD
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
- asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *((int*) ARG_DW(last->arg)) = b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *ARG_QW(last->arg) = b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *ARG_QW(last->arg) = b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrW_FLOAT(asEBCInstr bc, asWORD a, float b)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc == 0);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = a;
- *((float*) ARG_DW(last->arg)) = b;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrSHORT(asEBCInstr bc, short param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_rW_ARG ||
- asBCInfo[bc].type == asBCTYPE_wW_ARG ||
- asBCInfo[bc].type == asBCTYPE_W_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrINT(asEBCInstr bc, int param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- *((int*) ARG_DW(last->arg)) = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrDWORD(asEBCInstr bc, asDWORD param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- *ARG_DW(last->arg) = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrPTR(asEBCInstr bc, void *param)
- {
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- asASSERT(asBCInfo[bc].type == asBCTYPE_PTR_ARG);
- *ARG_PTR(last->arg) = (asPWORD)param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrQWORD(asEBCInstr bc, asQWORD param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- *ARG_QW(last->arg) = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrWORD(asEBCInstr bc, asWORD param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_W_ARG ||
- asBCInfo[bc].type == asBCTYPE_rW_ARG ||
- asBCInfo[bc].type == asBCTYPE_wW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- last->wArg[0] = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrFLOAT(asEBCInstr bc, float param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- *((float*) ARG_DW(last->arg)) = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::InstrDOUBLE(asEBCInstr bc, double param)
- {
- asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
- asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
- if( AddInstruction() < 0 )
- return 0;
- last->op = bc;
- *((double*) ARG_QW(last->arg)) = param;
- last->size = asBCTypeSize[asBCInfo[bc].type];
- last->stackInc = asBCInfo[bc].stackInc;
- return last->stackInc;
- }
- int asCByteCode::GetLastInstr()
- {
- if( last == 0 ) return -1;
- return last->op;
- }
- int asCByteCode::RemoveLastInstr()
- {
- if( last == 0 ) return -1;
- if( first == last )
- {
- engine->memoryMgr.FreeByteInstruction(last);
- first = 0;
- last = 0;
- }
- else
- {
- asCByteInstruction *bc = last;
- last = bc->prev;
- bc->Remove();
- engine->memoryMgr.FreeByteInstruction(bc);
- }
- return 0;
- }
- asDWORD asCByteCode::GetLastInstrValueDW()
- {
- if( last == 0 ) return 0;
- return *ARG_DW(last->arg);
- }
- //===================================================================
- asCByteInstruction::asCByteInstruction()
- {
- next = 0;
- prev = 0;
- op = asBC_LABEL;
- arg = 0;
- wArg[0] = 0;
- wArg[1] = 0;
- wArg[2] = 0;
- size = 0;
- stackInc = 0;
- marked = false;
- stackSize = 0;
- }
- void asCByteInstruction::AddAfter(asCByteInstruction *nextCode)
- {
- if( next )
- next->prev = nextCode;
- nextCode->next = next;
- nextCode->prev = this;
- next = nextCode;
- }
- void asCByteInstruction::AddBefore(asCByteInstruction *prevCode)
- {
- if( prev )
- prev->next = prevCode;
- prevCode->prev = prev;
- prevCode->next = this;
- prev = prevCode;
- }
- int asCByteInstruction::GetSize()
- {
- return size;
- }
- int asCByteInstruction::GetStackIncrease()
- {
- return stackInc;
- }
- void asCByteInstruction::Remove()
- {
- if( prev ) prev->next = next;
- if( next ) next->prev = prev;
- prev = 0;
- next = 0;
- }
- END_AS_NAMESPACE
- #endif // AS_NO_COMPILER
|