| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2011 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"
- #include "as_bytecode.h"
- #include "as_debug.h" // mkdir()
- #include "as_array.h"
- #include "as_string.h"
- #include "as_scriptengine.h"
- BEGIN_AS_NAMESPACE
- asCByteCode::asCByteCode(asCScriptEngine *engine)
- {
- first = 0;
- last = 0;
- largestStackUsed = -1;
- this->engine = engine;
- }
- asCByteCode::~asCByteCode()
- {
- ClearAll();
- }
- void asCByteCode::Finalize()
- {
- // verify the bytecode
- PostProcess();
- // Optimize the code (optionally)
- if( engine->ep.optimizeByteCode )
- Optimize();
- // Resolve jumps
- ResolveJumpAddresses();
- // Build line numbers buffer
- ExtractLineNumbers();
- }
- void asCByteCode::ClearAll()
- {
- cByteInstruction *del = first;
- while( del )
- {
- first = del->next;
- engine->memoryMgr.FreeByteInstruction(del);
- del = first;
- }
- first = 0;
- last = 0;
- lineNumbers.SetLength(0);
- largestStackUsed = -1;
- temporaryVariables.SetLength(0);
- }
- void asCByteCode::InsertIfNotExists(asCArray<int> &vars, int var)
- {
- if( !vars.Exists(var) )
- vars.PushLast(var);
- }
- void asCByteCode::GetVarsUsed(asCArray<int> &vars)
- {
- cByteInstruction *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 )
- {
- 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)
- {
- cByteInstruction *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 )
- {
- 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);
- cByteInstruction *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 )
- {
- 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<cByteInstruction *> &paths, cByteInstruction *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);
- }
- }
- bool asCByteCode::IsCombination(cByteInstruction *curr, asEBCInstr bc1, asEBCInstr bc2)
- {
- if( curr->op == bc1 && curr->next && curr->next->op == bc2 )
- return true;
-
- return false;
- }
- bool asCByteCode::IsCombination(cByteInstruction *curr, asEBCInstr bc1, asEBCInstr bc2, asEBCInstr bc3)
- {
- if( curr->op == bc1 &&
- curr->next && curr->next->op == bc2 &&
- curr->next->next && curr->next->next->op == bc3 )
- return true;
-
- return false;
- }
- cByteInstruction *asCByteCode::ChangeFirstDeleteNext(cByteInstruction *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;
- }
- cByteInstruction *asCByteCode::DeleteFirstChangeNext(cByteInstruction *curr, asEBCInstr bc)
- {
- asASSERT( curr->next );
-
- cByteInstruction *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(cByteInstruction *before, cByteInstruction *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(cByteInstruction *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(cByteInstruction *curr)
- {
- if( !curr || !curr->next || !curr->next->next ) return false;
- if( curr->next->next->op != asBC_SWAP4 ) return false;
- cByteInstruction *next = curr->next;
- if( curr->op != asBC_PshC4 &&
- curr->op != asBC_PshV4 &&
- curr->op != asBC_PSF )
- return false;
- if( next->op != asBC_PshC4 &&
- next->op != asBC_PshV4 &&
- next->op != asBC_PSF )
- return false;
- return true;
- }
- cByteInstruction *asCByteCode::GoBack(cByteInstruction *curr)
- {
- // Go back 2 instructions
- if( !curr ) return 0;
- if( curr->prev ) curr = curr->prev;
- if( curr->prev ) curr = curr->prev;
- return curr;
- }
- bool asCByteCode::PostponeInitOfTemp(cByteInstruction *curr, cByteInstruction **next)
- {
- if( curr->op != asBC_SetV4 || !IsTemporary(curr->wArg[0]) ) return false;
- // Move the initialization to just before it's use.
- // Don't move it beyond any labels or jumps.
- cByteInstruction *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 )
- {
- *next = curr->next;
- // Move the instruction
- RemoveInstruction(curr);
- InsertBefore(use, curr);
- // Try a RemoveUnusedValue to see if it can be combined with the other
- cByteInstruction *temp;
- if( RemoveUnusedValue(curr, &temp) )
- {
- *next = GoBack(*next);
- return true;
- }
-
- // Return the instructions to its original position as it wasn't useful
- RemoveInstruction(curr);
- InsertBefore(*next, curr);
- }
- return false;
- }
- bool asCByteCode::RemoveUnusedValue(cByteInstruction *curr, cByteInstruction **next)
- {
- // TODO: optimize: Should work for 64bit types as well
- // The value isn't used for anything
- 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_DW_ARG ||
- asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) &&
- IsTemporary(curr->wArg[0]) &&
- !IsTempVarRead(curr, curr->wArg[0]) &&
- curr->op != asBC_FREE ) // Can't remove the FREE instruction
- {
- if( curr->op == asBC_LdGRdR4 && IsTempRegUsed(curr) )
- {
- curr->op = asBC_LDG;
- *next = GoBack(curr);
- return true;
- }
- *next = GoBack(DeleteInstruction(curr));
- return true;
- }
- // TODO: optimize: There should be one for doubles as well
- // The value is immediately used and then never again
- if( curr->op == asBC_SetV4 &&
- curr->next &&
- (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 = GoBack(DeleteInstruction(curr));
- return true;
- }
-
- // The value is immediately used and then never again
- if( curr->op == asBC_SetV4 &&
- curr->next &&
- (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 = GoBack(DeleteInstruction(curr));
- return true;
- }
- if( curr->op == asBC_SetV4 &&
- curr->next &&
- (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 = GoBack(DeleteInstruction(curr));
- return true;
- }
- // The values 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];
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- return true;
- }
- // The constant value is immediately moved to another variable and then not used again
- if( curr->op == asBC_SetV4 && 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];
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- 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 = GoBack(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;
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- return true;
- }
- // The constant is copied to a temp and then immediately pushed on the stack
- if( curr->op == asBC_SetV4 && 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_PshC4;
- curr->stackInc = asBCInfo[asBC_PshC4].stackInc;
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- return true;
- }
- 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;
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- return true;
- }
- // The constant is copied to a global variable and then never used again
- if( curr->op == asBC_SetV4 && curr->next && 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);
- DeleteInstruction(curr->next);
- *next = GoBack(curr);
- return true;
- }
- return false;
- }
- bool asCByteCode::IsTemporary(short offset)
- {
- for( asUINT n = 0; n < temporaryVariables.GetLength(); n++ )
- if( temporaryVariables[n] == offset )
- return true;
- return false;
- }
- int asCByteCode::Optimize()
- {
- // TODO: 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.
- // TODO: optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call
-
- // TODO: optimize: A bytecode BC_RefCpyV that copies a handle from a local variable to another local variable
- // can easily substitute the frequently appearing pattern BC_PshV4, BC_PSF, BC_REFCPY, BC_POP
- // TODO: optimize: Script class methods are currently implemented to increase the ref count of the object upon
- // entry, and then release it upon exit. When the method isn't doing anything at all, this is
- // not necessary, as the function could simply do a RET immediately. This optimization is only
- // possible if the code has been built without the line cues, as if the SUSPEND is within the
- // function, then we can't do this optimization. Of course, this optimization may not be all
- // that useful, since in a real world app, it is probably not very common that empty class
- // methods are called.
- cByteInstruction *instr = first;
- while( instr )
- {
- cByteInstruction *curr = instr;
- instr = instr->next;
- // Remove or combine instructions
- if( RemoveUnusedValue(curr, &instr) ) continue;
- // Postpone initializations so that they may be combined in the second pass
- if( PostponeInitOfTemp(curr, &instr) ) continue;
- // XXX x, YYY y, SWAP4 -> YYY y, XXX x
- if( CanBeSwapped(curr) )
- {
- // Delete SWAP4
- DeleteInstruction(instr->next);
- // Swap instructions
- RemoveInstruction(instr);
- InsertBefore(curr, instr);
- instr = GoBack(instr);
- }
- // SWAP4, OP -> OP
- else if( IsCombination(curr, asBC_SWAP4, asBC_ADDi) ||
- IsCombination(curr, asBC_SWAP4, asBC_MULi) ||
- IsCombination(curr, asBC_SWAP4, asBC_ADDf) ||
- IsCombination(curr, asBC_SWAP4, asBC_MULf) )
- instr = GoBack(DeleteInstruction(curr));
- // T??, ClrHi -> T??
- else if( IsCombination(curr, asBC_TZ, asBC_ClrHi) ||
- IsCombination(curr, asBC_TNZ, asBC_ClrHi) ||
- IsCombination(curr, asBC_TS, asBC_ClrHi) ||
- IsCombination(curr, asBC_TNS, asBC_ClrHi) ||
- IsCombination(curr, asBC_TP, asBC_ClrHi) ||
- IsCombination(curr, asBC_TNP, asBC_ClrHi) )
- {
- // Remove the ClrHi instruction, since the test instructions always clear the top bytes anyway
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PshV4 0, ADDSi, PopRPtr -> LoadThisR
- // PshV8 0, ADDSi, PopRPtr -> LoadThisR
- else if( (IsCombination(curr, asBC_PshV4, asBC_ADDSi) ||
- IsCombination(curr, asBC_PshV8, asBC_ADDSi)) &&
- IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
- curr->wArg[0] == 0 )
- {
- DeleteInstruction(curr);
- instr = GoBack(ChangeFirstDeleteNext(instr, asBC_LoadThisR));
- }
- // PshV4 x, ADDSi, PopRPtr -> LoadRObjR
- // PshV8 x, ADDSi, PopRPtr -> LoadRObjR
- else if( (IsCombination(curr, asBC_PshV4, asBC_ADDSi) ||
- IsCombination(curr, asBC_PshV8, asBC_ADDSi)) &&
- IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
- curr->wArg[0] != 0 )
- {
- curr->op = asBC_LoadRObjR;
- curr->size = asBCTypeSize[asBCInfo[asBC_LoadRObjR].type];
- curr->stackInc = asBCInfo[asBC_LoadRObjR].stackInc;
- curr->wArg[1] = instr->wArg[0];
- *(asDWORD*)&curr->arg = *(asDWORD*)&instr->arg;
- DeleteInstruction(instr->next);
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PSF x, ADDSi, PopRPtr -> LoadVObjR
- else if( IsCombination(curr, asBC_PSF, asBC_ADDSi) &&
- IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) )
- {
- curr->op = asBC_LoadVObjR;
- curr->size = asBCTypeSize[asBCInfo[asBC_LoadVObjR].type];
- curr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
- curr->wArg[1] = instr->wArg[0];
- *(asDWORD*)&curr->arg = *(asDWORD*)&instr->arg;
- DeleteInstruction(instr->next);
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PSF x, RDS4 -> PshV4 x
- else if( IsCombination(curr, asBC_PSF, asBC_RDS4) )
- instr = GoBack(ChangeFirstDeleteNext(curr, asBC_PshV4));
- // PSF x, RDS8 -> PshV8 x
- else if( IsCombination(curr, asBC_PSF, asBC_RDS8) )
- instr = GoBack(ChangeFirstDeleteNext(curr, asBC_PshV8));
- // RDS4, POP x -> POP x
- else if( IsCombination(curr, asBC_RDS4, asBC_POP) && instr->wArg[0] >= 1 )
- {
- DeleteInstruction(curr);
- // Transform the pop to remove the address instead of the 4 byte word
- instr->wArg[0] -= 1-AS_PTR_SIZE;
- instr = GoBack(instr);
- }
- // RDS8, POP 2 -> POP x-1
- else if( IsCombination(curr, asBC_RDS8, asBC_POP) && instr->wArg[0] >= 2 )
- {
- DeleteInstruction(curr);
- // Transform the pop to remove the address instead of the 8 byte word
- instr->wArg[0] -= 2-AS_PTR_SIZE;
- instr = GoBack(instr);
- }
- // LDG x, WRTV4 y -> CpyVtoG4 y, x
- else if( IsCombination(curr, asBC_LDG, asBC_WRTV4) && !IsTempRegUsed(instr) )
- {
- curr->op = asBC_CpyVtoG4;
- curr->size = asBCTypeSize[asBCInfo[asBC_CpyVtoG4].type];
- curr->wArg[0] = instr->wArg[0];
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // LDG x, RDR4 y -> CpyGtoV4 y, x
- else if( IsCombination(curr, asBC_LDG, asBC_RDR4) )
- {
- if( !IsTempRegUsed(instr) )
- curr->op = asBC_CpyGtoV4;
- else
- curr->op = asBC_LdGRdR4;
- curr->size = asBCTypeSize[asBCInfo[asBC_CpyGtoV4].type];
- curr->wArg[0] = instr->wArg[0];
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // LDV x, INCi -> IncVi x
- else if( IsCombination(curr, asBC_LDV, asBC_INCi) && !IsTempRegUsed(instr) )
- {
- curr->op = asBC_IncVi;
-
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // LDV x, DECi -> DecVi x
- else if( IsCombination(curr, asBC_LDV, asBC_DECi) && !IsTempRegUsed(instr) )
- {
- curr->op = asBC_DecVi;
-
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // POP a, RET b -> RET b
- else if( IsCombination(curr, asBC_POP, asBC_RET) )
- {
- // We don't combine the POP+RET because RET first restores
- // the previous stack pointer and then pops the arguments
- // Delete POP
- instr = GoBack(DeleteInstruction(curr));
- }
- // Delete JitEntry if the JIT instructions are not supposed to be included
- else if( curr->op == asBC_JitEntry && !engine->ep.includeJitInstructions )
- {
- instr = GoBack(DeleteInstruction(curr));
- }
- // SUSPEND, JitEntry, SUSPEND -> SUSPEND
- // LINE, JitEntry, LINE -> LINE
- else if( (IsCombination(curr, asBC_SUSPEND, asBC_JitEntry) && IsCombination(instr, asBC_JitEntry, asBC_SUSPEND)) ||
- (IsCombination(curr, asBC_LINE, asBC_JitEntry) && IsCombination(instr, asBC_JitEntry, asBC_LINE)) )
- {
- // Delete the two first instructions
- DeleteInstruction(instr);
- instr = GoBack(DeleteInstruction(curr));
- }
- // SUSPEND, SUSPEND -> SUSPEND
- // LINE, LINE -> LINE
- else if( IsCombination(curr, asBC_SUSPEND, asBC_SUSPEND) ||
- IsCombination(curr, asBC_LINE, asBC_LINE) )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- // SUSPEND, Block, SUSPEND -> Block, SUSPEND
- else if( (IsCombination(curr, asBC_SUSPEND, asBC_Block) && IsCombination(instr, asBC_Block, asBC_SUSPEND)) ||
- (IsCombination(curr, asBC_LINE, asBC_Block) && IsCombination(instr, asBC_Block, asBC_LINE)) )
- {
- // Delete the first instruction
- instr = GoBack(DeleteInstruction(curr));
- }
- // PUSH a, PUSH b -> PUSH a+b
- else if( IsCombination(curr, asBC_PUSH, asBC_PUSH) )
- {
- // Combine the two PUSH
- instr->wArg[0] = curr->wArg[0] + instr->wArg[0];
- // Delete current
- DeleteInstruction(curr);
- // Continue with the instruction before the one removed
- instr = GoBack(instr);
- }
- // PshC4 a, GETREF 0 -> PSF a
- else if( IsCombination(curr, asBC_PshC4, asBC_GETREF) && instr->wArg[0] == 0 )
- {
- // Convert PshC4 a, to PSF a
- curr->wArg[0] = (short)*ARG_DW(curr->arg);
- curr->size = asBCTypeSize[asBCInfo[asBC_PSF].type];
- curr->op = asBC_PSF;
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PGA, CHKREF -> PGA
- // PSF, CHKREF -> PSF
- else if( IsCombination(curr, asBC_PGA, asBC_CHKREF) ||
- IsCombination(curr, asBC_PSF, asBC_CHKREF) )
- {
- // Delete CHKREF since PGA and PSF always pushes a valid address on the stack
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PGA, ChkRefS, CHKREF -> PGA, ChkRefS
- else if( IsCombination(curr, asBC_PGA, asBC_ChkRefS) &&
- IsCombination(instr, asBC_ChkRefS, asBC_CHKREF) )
- {
- // Delete CHKREF since PGA always pushes a valid address on the stack
- DeleteInstruction(instr->next);
- instr = GoBack(curr);
- }
- // PSF, FREE -> FREE, PSF
- else if( IsCombination(curr, asBC_PSF, asBC_FREE) )
- {
- // 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(instr);
- InsertBefore(curr, instr);
- instr = GoBack(instr);
- }
- // PshV4 y, POP x -> POP x-1
- // PshC4 y, POP x -> POP x-1
- else if( (IsCombination(curr, asBC_PshV4, asBC_POP) ||
- IsCombination(curr, asBC_PshC4, asBC_POP)) && instr->wArg[0] >= 1 )
- {
- DeleteInstruction(curr);
- instr->wArg[0]--;
- instr = GoBack(instr);
- }
- // PshRPtr, POP x -> POP x - 1
- else if( (IsCombination(curr, asBC_PshRPtr, asBC_POP) ||
- IsCombination(curr, asBC_PSF , asBC_POP) ||
- IsCombination(curr, asBC_VAR , asBC_POP))
- && instr->wArg[0] >= AS_PTR_SIZE )
- {
- DeleteInstruction(curr);
- instr->wArg[0] -= AS_PTR_SIZE;
- instr = GoBack(instr);
- }
- // PshV8 y, POP x -> POP x-2
- // PshC8 y, POP x -> POP x-2
- else if( (IsCombination(curr, asBC_PshV8, asBC_POP) ||
- IsCombination(curr, asBC_PshC8, asBC_POP)) && instr->wArg[0] >= 2 )
- {
- DeleteInstruction(curr);
- instr->wArg[0] -= 2;
- instr = GoBack(instr);
- }
- // POP 0 -> remove
- // PUSH 0 -> remove
- else if( (curr->op == asBC_POP || curr->op == asBC_PUSH ) && curr->wArg[0] == 0 )
- instr = GoBack(DeleteInstruction(curr));
- // Begin PATTERN
- // T**; J** +x -> J** +x
- else if( IsCombination(curr, asBC_TZ , asBC_JZ ) ||
- IsCombination(curr, asBC_TNZ, asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JNZ));
- else if( IsCombination(curr, asBC_TNZ, asBC_JZ ) ||
- IsCombination(curr, asBC_TZ , asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JZ));
- else if( IsCombination(curr, asBC_TS , asBC_JZ ) ||
- IsCombination(curr, asBC_TNS, asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JNS));
- else if( IsCombination(curr, asBC_TNS, asBC_JZ ) ||
- IsCombination(curr, asBC_TS , asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JS));
- else if( IsCombination(curr, asBC_TP , asBC_JZ ) ||
- IsCombination(curr, asBC_TNP, asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JNP));
- else if( IsCombination(curr, asBC_TNP, asBC_JZ ) ||
- IsCombination(curr, asBC_TP , asBC_JNZ) )
- instr = GoBack(DeleteFirstChangeNext(curr, asBC_JP));
- // End PATTERN
- // JMP +0 -> remove
- else if( IsCombination(curr, asBC_JMP, asBC_LABEL) && *(int*)&curr->arg == instr->wArg[0] )
- instr = GoBack(DeleteInstruction(curr));
- // PSF, ChkRefS, RDS4 -> PshV4, CHKREF
- else if( IsCombination(curr, asBC_PSF, asBC_ChkRefS) &&
- IsCombination(instr, asBC_ChkRefS, asBC_RDS4) )
- {
- asASSERT( AS_PTR_SIZE == 1 );
- curr->op = asBC_PshV4;
- instr->op = asBC_CHKREF;
- DeleteInstruction(instr->next);
- instr = GoBack(curr);
- }
- // PSF, ChkRefS, RDS8 -> PshV8, CHKREF
- else if( IsCombination(curr, asBC_PSF, asBC_ChkRefS) &&
- IsCombination(instr, asBC_ChkRefS, asBC_RDS8) )
- {
- asASSERT( AS_PTR_SIZE == 2 );
- curr->op = asBC_PshV8;
- instr->op = asBC_CHKREF;
- DeleteInstruction(instr->next);
- instr = GoBack(curr);
- }
- // PSF, ChkRefS, POP -> ChkNullV
- else if( (IsCombination(curr, asBC_PSF, asBC_ChkRefS) &&
- IsCombination(instr, asBC_ChkRefS, asBC_POP) &&
- instr->next->wArg[0] >= AS_PTR_SIZE) )
- {
- curr->op = asBC_ChkNullV;
- curr->stackInc = 0;
- // Decrease the number of DWORDs popped
- instr->next->wArg[0] -= AS_PTR_SIZE;
- // Delete the ChkRefS instruction
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PshV4, CHKREF, POP -> ChkNullV
- else if( (IsCombination(curr, asBC_PshV4, asBC_CHKREF) &&
- IsCombination(instr, asBC_CHKREF, asBC_POP) &&
- instr->next->wArg[0] >= 1) )
- {
- asASSERT( AS_PTR_SIZE == 1 );
- curr->op = asBC_ChkNullV;
- curr->stackInc = 0;
- DeleteInstruction(instr->next);
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- // PshV8, CHKREF, POP -> ChkNullV
- else if( (IsCombination(curr, asBC_PshV8, asBC_CHKREF) &&
- IsCombination(instr, asBC_CHKREF, asBC_POP) &&
- instr->next->wArg[0] >= 2) )
- {
- asASSERT( AS_PTR_SIZE == 2 );
- curr->op = asBC_ChkNullV;
- curr->stackInc = 0;
- DeleteInstruction(instr->next);
- DeleteInstruction(instr);
- instr = GoBack(curr);
- }
- }
- return 0;
- }
- bool asCByteCode::IsTempVarReadByInstr(cByteInstruction *curr, int offset)
- {
- // Which instructions read from variables?
- if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG &&
- (curr->wArg[1] == offset || 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 ||
- curr->op == asBC_FREE) && // FREE both read and write to the variable
- 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) &&
- curr->wArg[1] == offset )
- return true;
- else if( asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG &&
- ((signed)curr->wArg[0] == offset || (signed)curr->wArg[1] == offset) )
- return true;
- else if( curr->op == asBC_LoadThisR && offset == 0 )
- return true;
- return false;
- }
- bool asCByteCode::IsInstrJmpOrLabel(cByteInstruction *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_LABEL )
- return true;
- return false;
- }
- bool asCByteCode::IsTempVarOverwrittenByInstr(cByteInstruction *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) &&
- curr->wArg[0] == offset )
- return true;
- return false;
- }
- bool asCByteCode::IsTempVarRead(cByteInstruction *curr, int offset)
- {
- asCArray<cByteInstruction *> openPaths;
- asCArray<cByteInstruction *> 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 )
- {
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &curr, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
- if( !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 )
- {
- cByteInstruction *dest = 0;
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
- if( !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 )
- {
- cByteInstruction *dest = 0;
- int label = *((int*)ARG_DW(curr->arg));
- int r = FindLabel(label, curr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
- if( !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(cByteInstruction *curr)
- {
- // 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_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_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
- cByteInstruction *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()
- {
- int lastLinePos = -1;
- int pos = 0;
- cByteInstruction *instr = first;
- while( instr )
- {
- cByteInstruction *curr = instr;
- instr = instr->next;
-
- if( curr->op == asBC_LINE )
- {
- if( lastLinePos == pos )
- {
- lineNumbers.PopLast();
- lineNumbers.PopLast();
- }
- lastLinePos = pos;
- lineNumbers.PushLast(pos);
- lineNumbers.PushLast(*(int*)ARG_DW(curr->arg));
- 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)
- {
- int pos = 0;
- cByteInstruction *instr = first;
- while( instr )
- {
- if( instr->op == asBC_Block )
- {
- asSObjectVariableInfo info;
- info.programPos = pos;
- info.variableOffset = 0;
- info.option = instr->wArg[0] ? asBLOCK_BEGIN : asBLOCK_END;
- outFunc->objVariableInfo.PushLast(info);
- }
- else if( instr->op == asBC_ObjInfo )
- {
- asSObjectVariableInfo info;
- info.programPos = pos;
- info.variableOffset = (short)instr->wArg[0];
- info.option = *(int*)ARG_DW(instr->arg);
- outFunc->objVariableInfo.PushLast(info);
- }
- else if( instr->op == asBC_VarDecl )
- {
- outFunc->variables[instr->wArg[0]]->declaredAtProgramPos = pos;
- }
- else
- pos += instr->size;
- instr = instr->next;
- }
- }
- int asCByteCode::GetSize()
- {
- int size = 0;
- cByteInstruction *instr = first;
- while( instr )
- {
- size += instr->GetSize();
- instr = instr->next;
- }
- return size;
- }
- void asCByteCode::AddCode(asCByteCode *bc)
- {
- 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()
- {
- cByteInstruction *instr = new(engine->memoryMgr.AllocByteInstruction()) cByteInstruction();
- if( first == 0 )
- {
- first = last = instr;
- }
- else
- {
- last->AddAfter(instr);
- last = instr;
- }
- return 0;
- }
- int asCByteCode::AddInstructionFirst()
- {
- cByteInstruction *instr = new(engine->memoryMgr.AllocByteInstruction()) cByteInstruction();
- 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) = (asPTRWORD)(size_t)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)
- {
- 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);
- // 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, cByteInstruction *from, cByteInstruction **dest, int *positionDelta)
- {
- // Search forward
- int labelPos = -from->GetSize();
- cByteInstruction *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()
- {
- int pos = 0;
- cByteInstruction *instr = first;
- while( instr )
- {
- // The program pointer is updated as the instruction is read
- pos += instr->GetSize();
- if( instr->op == asBC_JMP ||
- instr->op == asBC_JZ || instr->op == asBC_JNZ ||
- 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;
- }
- cByteInstruction *asCByteCode::DeleteInstruction(cByteInstruction *instr)
- {
- if( instr == 0 ) return 0;
- cByteInstruction *ret = instr->prev ? instr->prev : instr->next;
-
- RemoveInstruction(instr);
- engine->memoryMgr.FreeByteInstruction(instr);
- return ret;
- }
- void asCByteCode::Output(asDWORD *array)
- {
- // TODO: Receive a script function pointer
- asDWORD *ap = array;
- cByteInstruction *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;
- default:
- // How did we get here?
- asASSERT(false);
- break;
- }
- }
- ap += instr->GetSize();
- instr = instr->next;
- }
- }
- void 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;
- cByteInstruction *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<cByteInstruction *> 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));
- cByteInstruction *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_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));
- cByteInstruction *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
- cByteInstruction *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 )
- {
- if( instr->marked == false )
- {
- // TODO: Give warning of unvisited code
- // Remove it
- cByteInstruction *curr = instr;
- instr = instr->next;
- DeleteInstruction(curr);
- }
- else
- instr = instr->next;
- }
- }
- #ifdef AS_DEBUG
- void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScriptFunction *func)
- {
- _mkdir("AS_DEBUG");
- asCString str = "AS_DEBUG/";
- str += name;
- #if _MSC_VER >= 1500
- FILE *file;
- fopen_s(&file, str.AddressOf(), "w");
- #else
- FILE *file = fopen(str.AddressOf(), "w");
- #endif
- #ifdef AS_XENON // XBox 360
- // When running in DVD Emu, no write is allowed
- if( file == 0 )
- return;
- #endif
- 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->variables.GetLength(); n++ )
- {
- fprintf(file, " %.3d: %s %s\n", func->variables[n]->stackOffset, func->variables[n]->type.Format().AddressOf(), func->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->variables.GetLength(); v++ )
- {
- if( func->variables[v]->stackOffset == (int)offset )
- {
- found = true;
- break;
- }
- }
- if( !found )
- fprintf(file, " %.3d: %s {noname param}\n", offset, func->parameterTypes[n].Format().AddressOf());
- offset -= func->parameterTypes[n].GetSizeOnStackDWords();
- }
- for( n = 0; n < func->objVariablePos.GetLength(); n++ )
- {
- bool found = false;
- for( asUINT v = 0; v < func->variables.GetLength(); v++ )
- {
- if( func->variables[v]->stackOffset == func->objVariablePos[n] )
- {
- found = true;
- break;
- }
- }
- if( !found )
- fprintf(file, " %.3d: %s {noname}\n", func->objVariablePos[n], func->objVariableTypes[n]->name.AddressOf());
- }
- fprintf(file, "\n\n");
- int pos = 0;
- asUINT lineIndex = 0;
- cByteInstruction *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;
- }
- fprintf(file, "%5d ", pos);
- pos += instr->GetSize();
- fprintf(file, "%3d %c ", instr->stackSize, instr->marked ? '*' : ' ');
- switch( asBCInfo[instr->op].type )
- {
- case asBCTYPE_W_ARG:
- if( instr->op == asBC_STR )
- {
- int id = instr->wArg[0];
- const asCString &str = engine->GetConstantString(id);
- fprintf(file, " %-8s %d (l:%ld s:\"%.10s\")\n", asBCInfo[instr->op].name, 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:
- fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg));
- 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:
- {
- 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_JS:
- case asBC_JP:
- case asBC_JNZ:
- 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:
- #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:
- #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);
- fprintf(file, " %-8s 0x%x, %d (type:%s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName());
- }
- 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_QW_DW_ARG:
- if( instr->op == asBC_ALLOC )
- {
- asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
- #ifdef __GNUC__
- #ifdef AS_64BIT_PTR
- fprintf(file, " %-8s 0x%lx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
- #else
- fprintf(file, " %-8s 0x%llx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
- #endif
- #else
- fprintf(file, " %-8s 0x%I64x, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
- #endif
- }
- else
- #ifdef __GNUC__
- #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);
- }
- #endif
- //=============================================================================
- // Decrease stack with "numDwords"
- int asCByteCode::Pop(int numDwords)
- {
- asASSERT(asBCInfo[asBC_POP].type == asBCTYPE_W_ARG);
- if( AddInstruction() < 0 )
- return 0;
- last->op = asBC_POP;
- last->wArg[0] = (short)numDwords;
- last->size = asBCTypeSize[asBCInfo[asBC_POP].type];
- last->stackInc = -numDwords;
- return last->stackInc;
- }
- // Increase stack with "numDwords"
- int asCByteCode::Push(int numDwords)
- {
- asASSERT(asBCInfo[asBC_PUSH].type == asBCTYPE_W_ARG);
- if( AddInstruction() < 0 )
- return 0;
- last->op = asBC_PUSH;
- last->wArg[0] = (short)numDwords;
- last->size = asBCTypeSize[asBCInfo[asBC_PUSH].type];
- last->stackInc = numDwords;
- return last->stackInc;
- }
- 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) = (asPTRWORD)(size_t)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_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) = (asPTRWORD)(size_t)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
- {
- cByteInstruction *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);
- }
- void asCByteCode::DefineTemporaryVariable(int varOffset)
- {
- temporaryVariables.PushLast(varOffset);
- }
- //===================================================================
- cByteInstruction::cByteInstruction()
- {
- 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 cByteInstruction::AddAfter(cByteInstruction *nextCode)
- {
- if( next )
- next->prev = nextCode;
- nextCode->next = next;
- nextCode->prev = this;
- next = nextCode;
- }
- void cByteInstruction::AddBefore(cByteInstruction *prevCode)
- {
- if( prev )
- prev->next = prevCode;
- prevCode->prev = prev;
- prevCode->next = this;
- prev = prevCode;
- }
- int cByteInstruction::GetSize()
- {
- return size;
- }
- int cByteInstruction::GetStackIncrease()
- {
- return stackInc;
- }
- void cByteInstruction::Remove()
- {
- if( prev ) prev->next = next;
- if( next ) next->prev = prev;
- prev = 0;
- next = 0;
- }
- END_AS_NAMESPACE
|