| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2016 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
- [email protected]
- */
- //
- // 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, 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_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 )
- 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 )
- {
- outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos;
- }
- else
- pos += instr->size;
- instr = instr->next;
- }
- asASSERT( blockLevel == 0 );
- }
- 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::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");
- 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;
- }
- 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 )
- {
- // 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)
- {
- _mkdir("AS_DEBUG");
- 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) // XBox 360: When running in DVD Emu, no write is allowed
- 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).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).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:
- if( instr->op == asBC_STR )
- {
- int id = asWORD(instr->wArg[0]);
- const asCString &str = engine->GetConstantString(id);
- fprintf(file, " %-8s %d (l:%ld s:\"%.10s\")\n", asBCInfo[instr->op].name, asWORD(instr->wArg[0]), (long int)str.GetLength(), str.AddressOf());
- }
- else
- 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;
-
- 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
|