| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2015 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;
- asCByteInstruction *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 = *(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, asCScriptEngine *engine, asCScriptFunction *func)
- {
- _mkdir("AS_DEBUG");
- asCString str = "AS_DEBUG/";
- str += name;
- #if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
- FILE *file;
- fopen_s(&file, str.AddressOf(), "w");
- #else
- FILE *file = fopen(str.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 *func = *(asCScriptFunction**)ARG_DW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), func->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 *func = *(asCScriptFunction**)ARG_QW(instr->arg);
- fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), func->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 *func = 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(), func ? func->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 *func = engine->scriptFunctions[instr->wArg[0]];
- #ifdef __GNUC__
- #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(), func ? func->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(), func ? func->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(), func ? func->GetDeclaration() : "{no func}");
- #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);
- // 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
|