as_bytecode.cpp 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2019 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_bytecode.cpp
  25. //
  26. // A class for constructing the final byte code
  27. //
  28. #include <stdio.h> // fopen(), fprintf(), fclose()
  29. #include "as_config.h"
  30. #ifndef AS_NO_COMPILER
  31. #include "as_bytecode.h"
  32. #include "as_debug.h" // mkdir()
  33. #include "as_array.h"
  34. #include "as_string.h"
  35. #include "as_scriptengine.h"
  36. #include "as_debug.h"
  37. BEGIN_AS_NAMESPACE
  38. asCByteCode::asCByteCode(asCScriptEngine *engine)
  39. {
  40. first = 0;
  41. last = 0;
  42. largestStackUsed = -1;
  43. temporaryVariables = 0;
  44. this->engine = engine;
  45. }
  46. asCByteCode::~asCByteCode()
  47. {
  48. ClearAll();
  49. }
  50. void asCByteCode::Finalize(const asCArray<int> &tempVariableOffsets)
  51. {
  52. temporaryVariables = &tempVariableOffsets;
  53. // verify the bytecode
  54. PostProcess();
  55. // Optimize the code
  56. Optimize();
  57. // Resolve jumps
  58. ResolveJumpAddresses();
  59. // Build line numbers buffer
  60. ExtractLineNumbers();
  61. }
  62. void asCByteCode::ClearAll()
  63. {
  64. asCByteInstruction *del = first;
  65. while( del )
  66. {
  67. first = del->next;
  68. engine->memoryMgr.FreeByteInstruction(del);
  69. del = first;
  70. }
  71. first = 0;
  72. last = 0;
  73. lineNumbers.SetLength(0);
  74. largestStackUsed = -1;
  75. }
  76. void asCByteCode::InsertIfNotExists(asCArray<int> &vars, int var)
  77. {
  78. if( !vars.Exists(var) )
  79. vars.PushLast(var);
  80. }
  81. void asCByteCode::GetVarsUsed(asCArray<int> &vars)
  82. {
  83. TimeIt("asCByteCode::GetVarsUsed");
  84. asCByteInstruction *curr = first;
  85. while( curr )
  86. {
  87. if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
  88. {
  89. InsertIfNotExists(vars, curr->wArg[0]);
  90. InsertIfNotExists(vars, curr->wArg[1]);
  91. InsertIfNotExists(vars, curr->wArg[2]);
  92. }
  93. else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
  94. asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
  95. asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
  96. asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
  97. asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
  98. asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
  99. asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
  100. asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
  101. {
  102. InsertIfNotExists(vars, curr->wArg[0]);
  103. }
  104. else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  105. asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ||
  106. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG )
  107. {
  108. InsertIfNotExists(vars, curr->wArg[0]);
  109. InsertIfNotExists(vars, curr->wArg[1]);
  110. }
  111. else if( curr->op == asBC_LoadThisR )
  112. {
  113. InsertIfNotExists(vars, 0);
  114. }
  115. curr = curr->next;
  116. }
  117. }
  118. bool asCByteCode::IsVarUsed(int offset)
  119. {
  120. TimeIt("asCByteCode::IsVarUsed");
  121. asCByteInstruction *curr = first;
  122. while( curr )
  123. {
  124. // Verify all ops that use variables
  125. if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
  126. {
  127. if( curr->wArg[0] == offset || curr->wArg[1] == offset || curr->wArg[2] == offset )
  128. return true;
  129. }
  130. else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
  131. asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
  132. asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
  133. asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
  134. asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
  135. asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
  136. asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
  137. asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
  138. {
  139. if( curr->wArg[0] == offset )
  140. return true;
  141. }
  142. else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  143. asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ||
  144. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG )
  145. {
  146. if( curr->wArg[0] == offset || curr->wArg[1] == offset )
  147. return true;
  148. }
  149. else if( curr->op == asBC_LoadThisR )
  150. {
  151. if( offset == 0 )
  152. return true;
  153. }
  154. curr = curr->next;
  155. }
  156. return false;
  157. }
  158. void asCByteCode::ExchangeVar(int oldOffset, int newOffset)
  159. {
  160. asASSERT(oldOffset != 0);
  161. asCByteInstruction *curr = first;
  162. while( curr )
  163. {
  164. // Verify all ops that use variables
  165. if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG )
  166. {
  167. if( curr->wArg[0] == oldOffset )
  168. curr->wArg[0] = (short)newOffset;
  169. if( curr->wArg[1] == oldOffset )
  170. curr->wArg[1] = (short)newOffset;
  171. if( curr->wArg[2] == oldOffset )
  172. curr->wArg[2] = (short)newOffset;
  173. }
  174. else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
  175. asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
  176. asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
  177. asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
  178. asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
  179. asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG ||
  180. asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
  181. asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG )
  182. {
  183. if( curr->wArg[0] == oldOffset )
  184. curr->wArg[0] = (short)newOffset;
  185. }
  186. else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  187. asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG )
  188. {
  189. if( curr->wArg[0] == oldOffset )
  190. curr->wArg[0] = (short)newOffset;
  191. if( curr->wArg[1] == oldOffset )
  192. curr->wArg[1] = (short)newOffset;
  193. }
  194. curr = curr->next;
  195. }
  196. }
  197. void asCByteCode::AddPath(asCArray<asCByteInstruction *> &paths, asCByteInstruction *instr, int stackSize)
  198. {
  199. if( instr->marked )
  200. {
  201. // Verify the size of the stack
  202. asASSERT(instr->stackSize == stackSize);
  203. }
  204. else
  205. {
  206. // Add the destination to the code paths
  207. instr->marked = true;
  208. instr->stackSize = stackSize;
  209. paths.PushLast(instr);
  210. }
  211. }
  212. asCByteInstruction *asCByteCode::ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc)
  213. {
  214. curr->op = bc;
  215. if( curr->next ) DeleteInstruction(curr->next);
  216. // Continue optimization with the instruction before the altered one
  217. if( curr->prev )
  218. return curr->prev;
  219. else
  220. return curr;
  221. }
  222. asCByteInstruction *asCByteCode::DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc)
  223. {
  224. asASSERT( curr->next );
  225. asCByteInstruction *instr = curr->next;
  226. instr->op = bc;
  227. DeleteInstruction(curr);
  228. // Continue optimization with the instruction before the altered one
  229. if( instr->prev )
  230. return instr->prev;
  231. else
  232. return instr;
  233. }
  234. void asCByteCode::InsertBefore(asCByteInstruction *before, asCByteInstruction *instr)
  235. {
  236. asASSERT(instr->next == 0);
  237. asASSERT(instr->prev == 0);
  238. if( before->prev ) before->prev->next = instr;
  239. instr->prev = before->prev;
  240. before->prev = instr;
  241. instr->next = before;
  242. if( first == before ) first = instr;
  243. }
  244. void asCByteCode::RemoveInstruction(asCByteInstruction *instr)
  245. {
  246. if( instr == first ) first = first->next;
  247. if( instr == last ) last = last->prev;
  248. if( instr->prev ) instr->prev->next = instr->next;
  249. if( instr->next ) instr->next->prev = instr->prev;
  250. instr->next = 0;
  251. instr->prev = 0;
  252. }
  253. bool asCByteCode::CanBeSwapped(asCByteInstruction *curr)
  254. {
  255. asASSERT( curr->op == asBC_SwapPtr );
  256. if( !curr->prev || !curr->prev->prev ) return false;
  257. asCByteInstruction *b = curr->prev;
  258. asCByteInstruction *a = b->prev;
  259. if( a->op != asBC_PshNull &&
  260. a->op != asBC_PshVPtr &&
  261. a->op != asBC_PSF )
  262. return false;
  263. if( b->op != asBC_PshNull &&
  264. b->op != asBC_PshVPtr &&
  265. b->op != asBC_PSF )
  266. return false;
  267. return true;
  268. }
  269. asCByteInstruction *asCByteCode::GoBack(asCByteInstruction *curr)
  270. {
  271. // Go back 2 instructions
  272. if( !curr ) return 0;
  273. if( curr->prev ) curr = curr->prev;
  274. if( curr->prev ) curr = curr->prev;
  275. return curr;
  276. }
  277. asCByteInstruction *asCByteCode::GoForward(asCByteInstruction *curr)
  278. {
  279. // Go forward 2 instructions
  280. if( !curr ) return 0;
  281. if( curr->next ) curr = curr->next;
  282. if( curr->next ) curr = curr->next;
  283. return curr;
  284. }
  285. bool asCByteCode::PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next)
  286. {
  287. TimeIt("asCByteCode::PostponeInitOfTemp");
  288. // This is not done for pointers
  289. if( (curr->op != asBC_SetV4 && curr->op != asBC_SetV8) ||
  290. !IsTemporary(curr->wArg[0]) ) return false;
  291. // Move the initialization to just before it's use.
  292. // Don't move it beyond any labels or jumps.
  293. asCByteInstruction *use = curr->next;
  294. while( use )
  295. {
  296. if( IsTempVarReadByInstr(use, curr->wArg[0]) )
  297. break;
  298. if( IsTempVarOverwrittenByInstr(use, curr->wArg[0]) )
  299. return false;
  300. if( IsInstrJmpOrLabel(use) )
  301. return false;
  302. use = use->next;
  303. }
  304. if( use && use->prev != curr )
  305. {
  306. asCByteInstruction *orig = curr->next;
  307. // Move the instruction
  308. RemoveInstruction(curr);
  309. InsertBefore(use, curr);
  310. // Try a RemoveUnusedValue to see if it can be combined with the other
  311. if( RemoveUnusedValue(curr, 0) )
  312. {
  313. // Optimizations should continue from the instruction that uses the value
  314. *next = orig;
  315. return true;
  316. }
  317. // Return the instructions to its original position as it wasn't useful
  318. RemoveInstruction(curr);
  319. InsertBefore(orig, curr);
  320. }
  321. return false;
  322. }
  323. bool asCByteCode::RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next)
  324. {
  325. TimeIt("asCByteCode::RemoveUnusedValue");
  326. asCByteInstruction *dummy;
  327. if( next == 0 )
  328. next = &dummy;
  329. // TODO: runtime optimize: Should work for 64bit types as well
  330. // TODO: runtime optimize: Need a asBCTYPE_rwW_ARG to cover the instructions that read
  331. // and write to the same variable. Currently they are considered
  332. // as readers only, so they are not optimized away. This includes
  333. // NOT, BNOT, IncV, DecV, NEG, iTOf (and all other type casts)
  334. // The value isn't used for anything
  335. if( curr->op != asBC_FREE && // Can't remove the FREE instruction
  336. (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
  337. asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  338. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ||
  339. asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
  340. asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
  341. asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) &&
  342. IsTemporary(curr->wArg[0]) &&
  343. !IsTempVarRead(curr, curr->wArg[0]) )
  344. {
  345. if( curr->op == asBC_LdGRdR4 && IsTempRegUsed(curr) )
  346. {
  347. curr->op = asBC_LDG;
  348. *next = GoForward(curr);
  349. return true;
  350. }
  351. *next = GoForward(DeleteInstruction(curr));
  352. return true;
  353. }
  354. if( curr->op == asBC_SetV4 && curr->next )
  355. {
  356. // The value is immediately used and then never again
  357. if( (curr->next->op == asBC_CMPi ||
  358. curr->next->op == asBC_CMPf ||
  359. curr->next->op == asBC_CMPu) &&
  360. curr->wArg[0] == curr->next->wArg[1] &&
  361. IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
  362. !IsTempVarRead(curr->next, curr->wArg[0]) )
  363. {
  364. if( curr->next->op == asBC_CMPi ) curr->next->op = asBC_CMPIi;
  365. else if( curr->next->op == asBC_CMPf ) curr->next->op = asBC_CMPIf;
  366. else if( curr->next->op == asBC_CMPu ) curr->next->op = asBC_CMPIu;
  367. curr->next->size = asBCTypeSize[asBCInfo[asBC_CMPIi].type];
  368. curr->next->arg = curr->arg;
  369. *next = GoForward(DeleteInstruction(curr));
  370. return true;
  371. }
  372. // The value is immediately used and then never again
  373. if( (curr->next->op == asBC_ADDi ||
  374. curr->next->op == asBC_SUBi ||
  375. curr->next->op == asBC_MULi ||
  376. curr->next->op == asBC_ADDf ||
  377. curr->next->op == asBC_SUBf ||
  378. curr->next->op == asBC_MULf) &&
  379. curr->wArg[0] == curr->next->wArg[2] &&
  380. (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten
  381. (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
  382. !IsTempVarRead(curr->next, curr->wArg[0]))) )
  383. {
  384. if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi;
  385. else if( curr->next->op == asBC_SUBi ) curr->next->op = asBC_SUBIi;
  386. else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi;
  387. else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf;
  388. else if( curr->next->op == asBC_SUBf ) curr->next->op = asBC_SUBIf;
  389. else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf;
  390. curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type];
  391. curr->next->arg = curr->arg;
  392. *next = GoForward(DeleteInstruction(curr));
  393. return true;
  394. }
  395. if( (curr->next->op == asBC_ADDi ||
  396. curr->next->op == asBC_MULi ||
  397. curr->next->op == asBC_ADDf ||
  398. curr->next->op == asBC_MULf) &&
  399. curr->wArg[0] == curr->next->wArg[1] &&
  400. (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten
  401. (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again
  402. !IsTempVarRead(curr->next, curr->wArg[0]))) )
  403. {
  404. if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi;
  405. else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi;
  406. else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf;
  407. else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf;
  408. curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type];
  409. curr->next->arg = curr->arg;
  410. // The order of the operands are changed
  411. curr->next->wArg[1] = curr->next->wArg[2];
  412. *next = GoForward(DeleteInstruction(curr));
  413. return true;
  414. }
  415. // The constant value is immediately moved to another variable and then not used again
  416. if( curr->next->op == asBC_CpyVtoV4 &&
  417. curr->wArg[0] == curr->next->wArg[1] &&
  418. IsTemporary(curr->wArg[0]) &&
  419. !IsTempVarRead(curr->next, curr->wArg[0]) )
  420. {
  421. curr->wArg[0] = curr->next->wArg[0];
  422. *next = GoForward(DeleteInstruction(curr->next));
  423. return true;
  424. }
  425. // The constant is copied to a temp and then immediately pushed on the stack
  426. if( curr->next->op == asBC_PshV4 &&
  427. curr->wArg[0] == curr->next->wArg[0] &&
  428. IsTemporary(curr->wArg[0]) &&
  429. !IsTempVarRead(curr->next, curr->wArg[0]) )
  430. {
  431. curr->op = asBC_PshC4;
  432. curr->stackInc = asBCInfo[asBC_PshC4].stackInc;
  433. *next = GoForward(DeleteInstruction(curr->next));
  434. return true;
  435. }
  436. // The constant is copied to a global variable and then never used again
  437. if( curr->next->op == asBC_CpyVtoG4 &&
  438. curr->wArg[0] == curr->next->wArg[0] &&
  439. IsTemporary(curr->wArg[0]) &&
  440. !IsTempVarRead(curr->next, curr->wArg[0]) )
  441. {
  442. curr->op = asBC_SetG4;
  443. curr->size = asBCTypeSize[asBCInfo[asBC_SetG4].type];
  444. *(((asDWORD*)&curr->arg)+AS_PTR_SIZE) = *ARG_DW(curr->arg);
  445. *ARG_PTR(curr->arg) = *ARG_PTR(curr->next->arg);
  446. *next = GoForward(DeleteInstruction(curr->next));
  447. return true;
  448. }
  449. }
  450. // The value is immediately moved to another variable and then not used again
  451. if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
  452. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) &&
  453. curr->next && curr->next->op == asBC_CpyVtoV4 &&
  454. curr->wArg[0] == curr->next->wArg[1] &&
  455. IsTemporary(curr->wArg[0]) &&
  456. !IsTempVarRead(curr->next, curr->wArg[0]) )
  457. {
  458. curr->wArg[0] = curr->next->wArg[0];
  459. *next = GoForward(DeleteInstruction(curr->next));
  460. return true;
  461. }
  462. // The register is copied to a temp variable and then back to the register again without being used afterwards
  463. if( curr->op == asBC_CpyRtoV4 && curr->next && curr->next->op == asBC_CpyVtoR4 &&
  464. curr->wArg[0] == curr->next->wArg[0] &&
  465. IsTemporary(curr->wArg[0]) &&
  466. !IsTempVarRead(curr->next, curr->wArg[0]) )
  467. {
  468. // Delete both instructions
  469. DeleteInstruction(curr->next);
  470. *next = GoForward(DeleteInstruction(curr));
  471. return true;
  472. }
  473. // The global value is copied to a temp and then immediately pushed on the stack
  474. if( curr->op == asBC_CpyGtoV4 && curr->next && curr->next->op == asBC_PshV4 &&
  475. curr->wArg[0] == curr->next->wArg[0] &&
  476. IsTemporary(curr->wArg[0]) &&
  477. !IsTempVarRead(curr->next, curr->wArg[0]) )
  478. {
  479. curr->op = asBC_PshG4;
  480. curr->size = asBCTypeSize[asBCInfo[asBC_PshG4].type];
  481. curr->stackInc = asBCInfo[asBC_PshG4].stackInc;
  482. *next = GoForward(DeleteInstruction(curr->next));
  483. return true;
  484. }
  485. // The constant is assigned to a variable, then the value of the variable
  486. // pushed on the stack, and then the variable is never used again
  487. if( curr->op == asBC_SetV8 && curr->next && curr->next->op == asBC_PshV8 &&
  488. curr->wArg[0] == curr->next->wArg[0] &&
  489. IsTemporary(curr->wArg[0]) &&
  490. !IsTempVarRead(curr->next, curr->wArg[0]) )
  491. {
  492. curr->op = asBC_PshC8;
  493. curr->stackInc = asBCInfo[asBC_PshC8].stackInc;
  494. *next = GoForward(DeleteInstruction(curr->next));
  495. return true;
  496. }
  497. return false;
  498. }
  499. bool asCByteCode::IsTemporary(int offset)
  500. {
  501. TimeIt("asCByteCode::IsTemporary");
  502. asASSERT(temporaryVariables);
  503. return temporaryVariables->Exists(offset);
  504. }
  505. void asCByteCode::OptimizeLocally(const asCArray<int> &tempVariableOffsets)
  506. {
  507. // This function performs the optimizations that doesn't require global knowledge of the
  508. // entire function, e.g. replacement of sequences of bytecodes for specialized instructions.
  509. if( !engine->ep.optimizeByteCode )
  510. return;
  511. temporaryVariables = &tempVariableOffsets;
  512. // TODO: runtime optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no
  513. // function calls that can suspend the execution.
  514. // TODO: runtime optimize: Remove temporary copies of handles, when the temp is just copied to yet another location
  515. // TODO: runtime optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve
  516. // loops a lot. How often do these loops really occur?
  517. // TODO: runtime optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call
  518. // TODO: optimize: Should possibly do two loops. Some of the checks are best doing by iterating from
  519. // the end to beginning, e.g. the removal of unused values. Other checks are best
  520. // doing by iterating from the beginning to end, e.g. replacement of sequences with
  521. // shorter ones. By doing this, we should be able to avoid backtracking with every
  522. // change thus avoid unnecessary duplicate checks.
  523. // Iterate through the bytecode instructions in the reverse order.
  524. // An optimization in an instruction may mean that another instruction before that
  525. // can also be optimized, e.g. if an add instruction is removed because the result is not
  526. // used, then the instructions that created the operands may potentially also be removed.
  527. asCByteInstruction *instr = last;
  528. while( instr )
  529. {
  530. asCByteInstruction *curr = instr;
  531. instr = instr->prev;
  532. // Remove instructions when the result is not used anywhere
  533. // This will return true if the instruction is deleted, and
  534. // false if it is not deleted. Observe that the instruction
  535. // can be modified.
  536. if( RemoveUnusedValue(curr, &instr) ) continue;
  537. // Postpone initializations so that they may be combined in the second pass.
  538. // If the initialization is postponed, then the optimizations should continue
  539. // from where the value was used, so instr will be updated to point to that.
  540. if( PostponeInitOfTemp(curr, &instr) ) continue;
  541. // Look for sequences that can be replaced with shorter ones
  542. const asEBCInstr currOp = curr->op;
  543. if( currOp == asBC_SwapPtr )
  544. {
  545. // XXX x, YYY y, SwapPtr -> YYY y, XXX x
  546. if( CanBeSwapped(curr) )
  547. {
  548. // Delete the SwapPtr
  549. DeleteInstruction(curr);
  550. // Swap instructions
  551. asCByteInstruction *a = instr->prev;
  552. RemoveInstruction(instr);
  553. InsertBefore(a, instr);
  554. // Continue the optimization from the second instruction
  555. instr = GoForward(a);
  556. continue;
  557. }
  558. }
  559. else if( currOp == asBC_ClrHi )
  560. {
  561. // T??, ClrHi -> T??
  562. if( instr &&
  563. (instr->op == asBC_TZ ||
  564. instr->op == asBC_TNZ ||
  565. instr->op == asBC_TS ||
  566. instr->op == asBC_TNS ||
  567. instr->op == asBC_TP ||
  568. instr->op == asBC_TNP) )
  569. {
  570. // Remove the ClrHi instruction since the test
  571. // instructions always clear the top bytes anyway
  572. instr = GoForward(DeleteInstruction(curr));
  573. continue;
  574. }
  575. // ClrHi, JZ -> JLowZ
  576. if( curr->next &&
  577. curr->next->op == asBC_JZ )
  578. {
  579. curr->next->op = asBC_JLowZ;
  580. instr = GoForward(DeleteInstruction(curr));
  581. continue;
  582. }
  583. // ClrHi, JNZ -> JLowNZ
  584. if( curr->next &&
  585. curr->next->op == asBC_JNZ )
  586. {
  587. curr->next->op = asBC_JLowNZ;
  588. instr = GoForward(DeleteInstruction(curr));
  589. continue;
  590. }
  591. }
  592. else if( currOp == asBC_LDV && curr->next )
  593. {
  594. // LDV x, INCi -> IncVi x
  595. if( curr->next->op == asBC_INCi && !IsTempRegUsed(curr->next) )
  596. {
  597. curr->op = asBC_IncVi;
  598. DeleteInstruction(curr->next);
  599. instr = GoForward(curr);
  600. }
  601. // LDV x, DECi -> DecVi x
  602. else if( curr->next->op == asBC_DECi && !IsTempRegUsed(curr->next) )
  603. {
  604. curr->op = asBC_DecVi;
  605. DeleteInstruction(curr->next);
  606. instr = GoForward(curr);
  607. }
  608. }
  609. else if( currOp == asBC_LDG && curr->next )
  610. {
  611. // LDG x, WRTV4 y -> CpyVtoG4 y, x
  612. if( curr->next->op == asBC_WRTV4 && !IsTempRegUsed(curr->next) )
  613. {
  614. curr->op = asBC_CpyVtoG4;
  615. curr->size = asBCTypeSize[asBCInfo[asBC_CpyVtoG4].type];
  616. curr->wArg[0] = curr->next->wArg[0];
  617. DeleteInstruction(curr->next);
  618. instr = GoForward(curr);
  619. }
  620. // LDG x, RDR4 y -> CpyGtoV4 y, x
  621. else if( curr->next->op == asBC_RDR4 )
  622. {
  623. if( !IsTempRegUsed(curr->next) )
  624. curr->op = asBC_CpyGtoV4;
  625. else
  626. curr->op = asBC_LdGRdR4;
  627. curr->size = asBCTypeSize[asBCInfo[asBC_CpyGtoV4].type];
  628. curr->wArg[0] = curr->next->wArg[0];
  629. DeleteInstruction(curr->next);
  630. instr = GoForward(curr);
  631. }
  632. }
  633. else if( currOp == asBC_CHKREF )
  634. {
  635. // CHKREF, ADDSi -> ADDSi
  636. // CHKREF, RDSPtr -> RDSPtr
  637. if( curr->next &&
  638. (curr->next->op == asBC_ADDSi || curr->next->op == asBC_RDSPtr) )
  639. {
  640. // As ADDSi & RDSPtr already checks the pointer the CHKREF instruction is unnecessary
  641. instr = GoForward(DeleteInstruction(curr));
  642. }
  643. // ADDSi, CHKREF -> ADDSi
  644. // PGA, CHKREF -> PGA
  645. // PSF, CHKREF -> PSF
  646. else if( instr &&
  647. (instr->op == asBC_ADDSi ||
  648. instr->op == asBC_PGA ||
  649. instr->op == asBC_PSF) )
  650. {
  651. // ADDSi is guaranteed to work on valid pointers so CHKREF is not necessary.
  652. // PGA and PSF always pushes a valid address on the stack.
  653. instr = GoForward(DeleteInstruction(curr));
  654. }
  655. // PGA, ChkRefS, CHKREF -> PGA, ChkRefS
  656. else if( instr && instr->op == asBC_ChkRefS &&
  657. instr->prev && instr->prev->op == asBC_PGA )
  658. {
  659. // Delete CHKREF since PGA always pushes a valid address on the stack
  660. instr = GoForward(DeleteInstruction(curr));
  661. }
  662. }
  663. else if( currOp == asBC_PopPtr )
  664. {
  665. // RDSPtr, PopPtr -> PopPtr
  666. if( instr && instr->op == asBC_RDSPtr )
  667. {
  668. instr = GoForward(DeleteInstruction(instr));
  669. }
  670. // PshNull, RefCpyV, PopPtr -> FREE
  671. else if( instr && instr->op == asBC_RefCpyV &&
  672. instr->prev && instr->prev->op == asBC_PshNull )
  673. {
  674. DeleteInstruction(curr);
  675. DeleteInstruction(instr->prev);
  676. instr->op = asBC_FREE;
  677. instr = GoForward(instr);
  678. }
  679. // PshVPtr y, PopPtr -> nothing
  680. // PSF y , PopPtr -> nothing
  681. // VAR y , PopPtr -> nothing
  682. // PshNull , PopPtr -> nothing
  683. // PshRPtr , PopPtr -> nothing
  684. else if( instr &&
  685. (instr->op == asBC_PshRPtr ||
  686. instr->op == asBC_PSF ||
  687. instr->op == asBC_VAR ||
  688. instr->op == asBC_PshVPtr ||
  689. instr->op == asBC_PshNull) )
  690. {
  691. // A pointer is pushed on the stack then immediately removed
  692. // Remove both instructions as they cancel each other
  693. DeleteInstruction(curr);
  694. instr = GoForward(DeleteInstruction(instr));
  695. }
  696. // PSF, ChkRefS, PopPtr -> ChkNullV
  697. else if( instr && instr->op == asBC_ChkRefS &&
  698. instr->prev && instr->prev->op == asBC_PSF )
  699. {
  700. instr = instr->prev;
  701. instr->op = asBC_ChkNullV;
  702. instr->stackInc = 0;
  703. // Delete the PopPtr instruction
  704. DeleteInstruction(curr);
  705. // Delete the ChkRefS instruction
  706. DeleteInstruction(instr->next);
  707. instr = GoForward(instr);
  708. }
  709. // PshVPtr, CHKREF, PopPtr -> ChkNullV
  710. else if( instr && instr->op == asBC_CHKREF &&
  711. instr->prev && instr->prev->op == asBC_PshVPtr )
  712. {
  713. instr = instr->prev;
  714. instr->op = asBC_ChkNullV;
  715. instr->stackInc = 0;
  716. DeleteInstruction(curr->prev);
  717. DeleteInstruction(curr);
  718. instr = GoForward(instr);
  719. }
  720. // STOREOBJ y, PSF y, RDSPtr, PSF x, REFCPY, FREE y, PopPtr -> FREE x, STOREOBJ x
  721. else if( instr && instr->op == asBC_FREE )
  722. {
  723. asCByteInstruction *i = instr->prev;
  724. if( !i || i->op != asBC_REFCPY ) continue;
  725. i = i->prev;
  726. if( !i || i->op != asBC_PSF ) continue;
  727. short x = i->wArg[0];
  728. i = i->prev;
  729. if( !i || i->op != asBC_RDSPtr ) continue;
  730. i = i->prev;
  731. if( !i || i->op != asBC_PSF ) continue;
  732. short y = i->wArg[0];
  733. i = i->prev;
  734. if( !i || i->op != asBC_STOREOBJ || i->wArg[0] != y ) continue;
  735. // Don't do the substitution if the var y is not a temporary, or if it is used after PopPtr
  736. if( !IsTemporary(y) || IsTempVarRead(curr, y) ) continue;
  737. // Transform the PopPtr into STOREOBJ
  738. curr->op = asBC_STOREOBJ;
  739. curr->stackInc = 0;
  740. curr->wArg[0] = x;
  741. curr->size = i->size;
  742. // Change arg of the FREE to x
  743. // TODO: runtime optimize: The FREE instruction shouldn't be necessary. STOREOBJ should free the previous value by itself
  744. instr->wArg[0] = x;
  745. // Delete all other instructions
  746. DeleteInstruction(instr->prev); // REFCPY
  747. DeleteInstruction(instr->prev); // PSF
  748. DeleteInstruction(instr->prev); // RDSTR
  749. DeleteInstruction(instr->prev); // PSF
  750. DeleteInstruction(instr->prev); // STOREOBJ
  751. instr = GoForward(curr);
  752. }
  753. }
  754. else if( currOp == asBC_RDSPtr )
  755. {
  756. // PGA, RDSPtr -> PshGPtr
  757. if( instr && instr->op == asBC_PGA )
  758. {
  759. instr->op = asBC_PshGPtr;
  760. DeleteInstruction(curr);
  761. instr = GoForward(instr);
  762. }
  763. // ChkRefS, RDSPtr -> RDSPtr, CHKREF
  764. else if( instr && instr->op == asBC_ChkRefS )
  765. {
  766. // This exchange removes one pointer dereference, and also
  767. // makes it easier to completely remove the CHKREF instruction
  768. curr->op = asBC_CHKREF;
  769. instr->op = asBC_RDSPtr;
  770. instr = GoForward(curr);
  771. }
  772. // PSF, RDSPtr -> PshVPtr
  773. else if( instr && instr->op == asBC_PSF )
  774. {
  775. instr->op = asBC_PshVPtr;
  776. instr = GoForward(DeleteInstruction(curr));
  777. }
  778. // PSF, ChkRefS, RDSPtr -> PshVPtr, CHKREF
  779. else if( instr && instr->op == asBC_ChkRefS &&
  780. instr->prev && instr->prev->op == asBC_PSF )
  781. {
  782. instr->prev->op = asBC_PshVPtr;
  783. instr->op = asBC_CHKREF;
  784. instr = GoForward(DeleteInstruction(curr));
  785. }
  786. }
  787. else if( currOp == asBC_PopRPtr )
  788. {
  789. // PshVPtr 0, ADDSi, PopRPtr -> LoadThisR
  790. if( instr && instr->op == asBC_ADDSi &&
  791. instr->prev && instr->prev->op == asBC_PshVPtr &&
  792. instr->prev->wArg[0] == 0 )
  793. {
  794. DeleteInstruction(instr->prev);
  795. ChangeFirstDeleteNext(instr, asBC_LoadThisR);
  796. instr = GoForward(instr);
  797. }
  798. // TODO: runtime optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0
  799. // PshVPtr x, ADDSi, PopRPtr -> LoadRObjR
  800. else if( instr && instr->op == asBC_ADDSi &&
  801. instr->prev && instr->prev->op == asBC_PshVPtr &&
  802. instr->prev->wArg[0] != 0 )
  803. {
  804. instr = instr->prev;
  805. instr->op = asBC_LoadRObjR;
  806. instr->size = asBCTypeSize[asBCInfo[asBC_LoadRObjR].type];
  807. instr->stackInc = asBCInfo[asBC_LoadRObjR].stackInc;
  808. instr->wArg[1] = instr->next->wArg[0];
  809. *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg;
  810. DeleteInstruction(instr->next);
  811. DeleteInstruction(curr);
  812. instr = GoForward(instr);
  813. }
  814. // PSF x, ADDSi, PopRPtr -> LoadVObjR
  815. else if( instr && instr->op == asBC_ADDSi &&
  816. instr->prev && instr->prev->op == asBC_PSF )
  817. {
  818. instr = instr->prev;
  819. instr->op = asBC_LoadVObjR;
  820. instr->size = asBCTypeSize[asBCInfo[asBC_LoadVObjR].type];
  821. instr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
  822. instr->wArg[1] = instr->next->wArg[0];
  823. *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg;
  824. DeleteInstruction(instr->next);
  825. DeleteInstruction(curr);
  826. instr = GoForward(instr);
  827. }
  828. }
  829. else if( currOp == asBC_REFCPY )
  830. {
  831. // PSF x, REFCPY -> RefCpyV x
  832. if( instr && instr->op == asBC_PSF )
  833. {
  834. curr->op = asBC_RefCpyV;
  835. curr->wArg[0] = instr->wArg[0];
  836. curr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
  837. DeleteInstruction(instr);
  838. instr = GoForward(curr);
  839. }
  840. }
  841. else if( ((currOp >= asBC_JZ && currOp <= asBC_JNP) || currOp == asBC_JLowZ || currOp == asBC_JLowNZ) && instr )
  842. {
  843. // T**; J** +x -> J** +x
  844. if( (instr->op == asBC_TZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  845. (instr->op == asBC_TNZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  846. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNZ));
  847. else if( (instr->op == asBC_TNZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  848. (instr->op == asBC_TZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  849. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JZ));
  850. else if( (instr->op == asBC_TS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  851. (instr->op == asBC_TNS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  852. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNS));
  853. else if( (instr->op == asBC_TNS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  854. (instr->op == asBC_TS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  855. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JS));
  856. else if( (instr->op == asBC_TP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  857. (instr->op == asBC_TNP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  858. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNP));
  859. else if( (instr->op == asBC_TNP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) ||
  860. (instr->op == asBC_TP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) )
  861. instr = GoForward(DeleteFirstChangeNext(instr, asBC_JP));
  862. }
  863. else if( currOp == asBC_FREE && instr )
  864. {
  865. // PSF, FREE -> FREE, PSF
  866. if( instr->op == asBC_PSF )
  867. {
  868. // This pattern usually happens when a function returns an object, or handle
  869. // and then releases a temporary variable, possibly used in one of the arguments.
  870. // By swapping the order of these instructions, the code can be further optimized
  871. // to combine the PSF with the following instructions
  872. RemoveInstruction(curr);
  873. InsertBefore(instr, curr);
  874. instr = GoForward(instr);
  875. }
  876. // VAR, FREE -> FREE, VAR
  877. else if( instr->op == asBC_VAR )
  878. {
  879. // Swap the two instructions, so that the VAR instruction
  880. // gets closer to its corresponding GET instruction and thus
  881. // has a greater chance of getting optimized
  882. RemoveInstruction(curr);
  883. InsertBefore(instr, curr);
  884. instr = GoForward(instr);
  885. }
  886. }
  887. else if( currOp == asBC_VAR )
  888. {
  889. // VAR, PSF, GETOBJREF {PTR_SIZE} -> PshVPtr, PSF
  890. if( curr->next && curr->next->op == asBC_PSF &&
  891. curr->next->next && curr->next->next->op == asBC_GETOBJREF &&
  892. curr->next->next->wArg[0] == AS_PTR_SIZE )
  893. {
  894. curr->op = asBC_PshVPtr;
  895. DeleteInstruction(curr->next->next);
  896. instr = GoForward(curr);
  897. }
  898. // VAR a, GETREF 0 -> PSF a
  899. else if( curr->next && curr->next->op == asBC_GETREF && curr->next->wArg[0] == 0 )
  900. {
  901. ChangeFirstDeleteNext(curr, asBC_PSF);
  902. instr = GoForward(curr);
  903. }
  904. // VAR a, GETOBJREF 0 -> PshVPtr a
  905. else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 )
  906. {
  907. ChangeFirstDeleteNext(curr, asBC_PshVPtr);
  908. instr = GoForward(curr);
  909. }
  910. // VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF
  911. if( curr->next && curr->next->op == asBC_PSF &&
  912. curr->next->next && curr->next->next->op == asBC_GETREF &&
  913. curr->next->next->wArg[0] == AS_PTR_SIZE )
  914. {
  915. curr->op = asBC_PSF;
  916. DeleteInstruction(curr->next->next);
  917. instr = GoForward(curr);
  918. }
  919. }
  920. }
  921. // Optimize unnecessary refcpy for return handle. This scenario only happens for return statements
  922. // and LOADOBJ can only be the last instruction before the RET, so doing this check after the rest of
  923. // the optimizations have taken place saves us time.
  924. if( last && last->op == asBC_LOADOBJ && IsTemporary(last->wArg[0]) )
  925. {
  926. // A temporary handle is being loaded into the object register.
  927. // Let's look for a trivial RefCpyV to that temporary variable, and a Free of the original
  928. // variable. If this is found, then we can simply load the original value into the register
  929. // and avoid both the RefCpy and the Free.
  930. short tempVar = last->wArg[0];
  931. asCArray<short> freedVars;
  932. instr = last->prev;
  933. asASSERT( instr && instr->op == asBC_Block );
  934. instr = instr->prev;
  935. while( instr && instr->op == asBC_FREE )
  936. {
  937. freedVars.PushLast(instr->wArg[0]);
  938. instr = instr->prev;
  939. }
  940. // If there is any non-trivial cleanups, e.g. call to destructors, then we skip this optimizations
  941. // TODO: runtime optimize: Do we need to skip it? Is there really a chance the local variable
  942. // will be invalidated while the destructor, or any other function for
  943. // that matter, is being called?
  944. if( instr && instr->op == asBC_Block )
  945. {
  946. // We expect a sequence PshVPtr, RefCpyV, PopPtr just before the clean up block
  947. instr = instr->prev;
  948. if( instr && instr->op == asBC_PopPtr ) instr = instr->prev;
  949. if( instr && instr->op == asBC_RefCpyV && instr->wArg[0] == tempVar ) instr = instr->prev;
  950. if( instr && instr->op == asBC_PshVPtr && freedVars.Exists(instr->wArg[0]) )
  951. {
  952. // Update the LOADOBJ to load the local variable directly
  953. tempVar = instr->wArg[0];
  954. last->wArg[0] = tempVar;
  955. // Remove the copy of the local variable into the temp
  956. DeleteInstruction(instr->next); // deletes RefCpyV
  957. DeleteInstruction(instr->next); // deletes PopPtr
  958. DeleteInstruction(instr); // deletes PshVPtr
  959. // Find and remove the FREE instruction for the local variable too
  960. instr = last->prev->prev;
  961. while( instr )
  962. {
  963. asASSERT( instr->op == asBC_FREE );
  964. if( instr->wArg[0] == tempVar )
  965. {
  966. DeleteInstruction(instr);
  967. break;
  968. }
  969. instr = instr->prev;
  970. }
  971. }
  972. }
  973. }
  974. }
  975. void asCByteCode::Optimize()
  976. {
  977. // This function performs the optimizations that require global knowledge of the entire function
  978. TimeIt("asCByteCode::Optimize");
  979. if( !engine->ep.optimizeByteCode )
  980. return;
  981. // TODO: runtime optimize: The optimizer should be able to inline function calls.
  982. // If the called function has only a few instructions, the function call should be inlined.
  983. // This is especially useful with the factory stubs used for template types and script classes.
  984. asCByteInstruction *instr = first;
  985. while( instr )
  986. {
  987. asCByteInstruction *curr = instr;
  988. instr = instr->next;
  989. const asEBCInstr currOp = curr->op;
  990. // Delete JitEntry if the JIT instructions are not supposed to be included
  991. if( currOp == asBC_JitEntry && !engine->ep.includeJitInstructions )
  992. {
  993. instr = GoBack(DeleteInstruction(curr));
  994. continue;
  995. }
  996. if( instr )
  997. {
  998. const asEBCInstr instrOp = instr->op;
  999. // PopPtr, RET b -> RET b
  1000. if( currOp == asBC_PopPtr && instrOp == asBC_RET )
  1001. {
  1002. // We don't combine the PopPtr+RET because RET first restores
  1003. // the previous stack pointer and then pops the arguments
  1004. // Delete PopPtr
  1005. instr = GoBack(DeleteInstruction(curr));
  1006. }
  1007. else if( currOp == asBC_SUSPEND )
  1008. {
  1009. // SUSPEND, JitEntry, SUSPEND -> SUSPEND
  1010. if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_SUSPEND )
  1011. {
  1012. // Delete the two first instructions
  1013. DeleteInstruction(instr);
  1014. instr = GoBack(DeleteInstruction(curr));
  1015. }
  1016. // SUSPEND, SUSPEND -> SUSPEND
  1017. else if( instrOp == asBC_SUSPEND )
  1018. {
  1019. // Delete the first instruction
  1020. instr = GoBack(DeleteInstruction(curr));
  1021. }
  1022. // SUSPEND, Block, SUSPEND -> Block, SUSPEND
  1023. else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_SUSPEND )
  1024. {
  1025. // Delete the first instruction
  1026. instr = GoBack(DeleteInstruction(curr));
  1027. }
  1028. }
  1029. else if( currOp == asBC_LINE )
  1030. {
  1031. // LINE, JitEntry, LINE -> LINE
  1032. if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_LINE )
  1033. {
  1034. // Delete the two first instructions
  1035. DeleteInstruction(instr);
  1036. instr = GoBack(DeleteInstruction(curr));
  1037. }
  1038. // LINE, VarDecl, LINE -> VarDecl, LINE
  1039. else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE )
  1040. {
  1041. // Delete the first instruction
  1042. instr = GoBack(DeleteInstruction(curr));
  1043. }
  1044. // LINE, LINE -> LINE
  1045. else if( instrOp == asBC_LINE )
  1046. {
  1047. // Delete the first instruction
  1048. instr = GoBack(DeleteInstruction(curr));
  1049. }
  1050. // LINE, Block, LINE -> Block, LINE
  1051. else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_LINE )
  1052. {
  1053. // Delete the first instruction
  1054. instr = GoBack(DeleteInstruction(curr));
  1055. }
  1056. }
  1057. // JMP +0 -> remove
  1058. else if( currOp == asBC_JMP && instrOp == asBC_LABEL && *(int*)&curr->arg == instr->wArg[0] )
  1059. instr = GoBack(DeleteInstruction(curr));
  1060. }
  1061. }
  1062. }
  1063. bool asCByteCode::IsTempVarReadByInstr(asCByteInstruction *curr, int offset)
  1064. {
  1065. // Which instructions read from variables?
  1066. if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG &&
  1067. (int(curr->wArg[1]) == offset || int(curr->wArg[2]) == offset) )
  1068. return true;
  1069. else if( (asBCInfo[curr->op].type == asBCTYPE_rW_ARG ||
  1070. asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG ||
  1071. asBCInfo[curr->op].type == asBCTYPE_rW_QW_ARG ||
  1072. asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG ||
  1073. asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ||
  1074. curr->op == asBC_FREE) && // FREE both read and write to the variable
  1075. int(curr->wArg[0]) == offset )
  1076. return true;
  1077. else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  1078. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) &&
  1079. int(curr->wArg[1]) == offset )
  1080. return true;
  1081. else if( asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG &&
  1082. (int(curr->wArg[0]) == offset || int(curr->wArg[1]) == offset) )
  1083. return true;
  1084. else if( curr->op == asBC_LoadThisR && offset == 0 )
  1085. return true;
  1086. return false;
  1087. }
  1088. bool asCByteCode::IsInstrJmpOrLabel(asCByteInstruction *curr)
  1089. {
  1090. if( curr->op == asBC_JS ||
  1091. curr->op == asBC_JNS ||
  1092. curr->op == asBC_JP ||
  1093. curr->op == asBC_JNP ||
  1094. curr->op == asBC_JMPP ||
  1095. curr->op == asBC_JMP ||
  1096. curr->op == asBC_JZ ||
  1097. curr->op == asBC_JNZ ||
  1098. curr->op == asBC_JLowZ ||
  1099. curr->op == asBC_JLowNZ ||
  1100. curr->op == asBC_LABEL )
  1101. return true;
  1102. return false;
  1103. }
  1104. bool asCByteCode::IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int offset)
  1105. {
  1106. // Which instructions overwrite the variable or discard it?
  1107. if( curr->op == asBC_RET ||
  1108. curr->op == asBC_SUSPEND )
  1109. return true;
  1110. else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
  1111. asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG ||
  1112. asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ||
  1113. asBCInfo[curr->op].type == asBCTYPE_wW_ARG ||
  1114. asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG ||
  1115. asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG ||
  1116. asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) &&
  1117. int(curr->wArg[0]) == offset )
  1118. return true;
  1119. return false;
  1120. }
  1121. bool asCByteCode::IsTempVarRead(asCByteInstruction *curr, int offset)
  1122. {
  1123. TimeIt("asCByteCode::IsTempVarRead");
  1124. asCArray<asCByteInstruction *> openPaths;
  1125. asCArray<asCByteInstruction *> closedPaths;
  1126. // We're not interested in the first instruction, since it is the one that sets the variable
  1127. openPaths.PushLast(curr->next);
  1128. while( openPaths.GetLength() )
  1129. {
  1130. curr = openPaths.PopLast();
  1131. // Add the instruction to the closed paths so that we don't verify it again
  1132. closedPaths.PushLast(curr);
  1133. while( curr )
  1134. {
  1135. if( IsTempVarReadByInstr(curr, offset) )
  1136. return true;
  1137. if( IsTempVarOverwrittenByInstr(curr, offset) ) break;
  1138. // In case of jumps, we must follow the each of the paths
  1139. if( curr->op == asBC_JMP )
  1140. {
  1141. // Find the destination. If it cannot be found it is because we're doing a localized
  1142. // optimization and the label hasn't been added to the final bytecode yet
  1143. int label = *((int*)ARG_DW(curr->arg));
  1144. int r = FindLabel(label, curr, &curr, 0);
  1145. if( r >= 0 &&
  1146. !closedPaths.Exists(curr) &&
  1147. !openPaths.Exists(curr) )
  1148. openPaths.PushLast(curr);
  1149. break;
  1150. }
  1151. else if( curr->op == asBC_JZ || curr->op == asBC_JNZ ||
  1152. curr->op == asBC_JS || curr->op == asBC_JNS ||
  1153. curr->op == asBC_JP || curr->op == asBC_JNP ||
  1154. curr->op == asBC_JLowZ || curr->op == asBC_JLowNZ )
  1155. {
  1156. // Find the destination. If it cannot be found it is because we're doing a localized
  1157. // optimization and the label hasn't been added to the final bytecode yet
  1158. asCByteInstruction *dest = 0;
  1159. int label = *((int*)ARG_DW(curr->arg));
  1160. int r = FindLabel(label, curr, &dest, 0);
  1161. if( r >= 0 &&
  1162. !closedPaths.Exists(dest) &&
  1163. !openPaths.Exists(dest) )
  1164. openPaths.PushLast(dest);
  1165. }
  1166. else if( curr->op == asBC_JMPP )
  1167. {
  1168. // A JMPP instruction is always followed by a series of JMP instructions
  1169. // that give the real destination (like a look-up table). We need add all
  1170. // of these as open paths.
  1171. curr = curr->next;
  1172. while( curr->op == asBC_JMP )
  1173. {
  1174. // Find the destination. If it cannot be found it is because we're doing a localized
  1175. // optimization and the label hasn't been added to the final bytecode yet
  1176. asCByteInstruction *dest = 0;
  1177. int label = *((int*)ARG_DW(curr->arg));
  1178. int r = FindLabel(label, curr, &dest, 0);
  1179. if( r >= 0 &&
  1180. !closedPaths.Exists(dest) &&
  1181. !openPaths.Exists(dest) )
  1182. openPaths.PushLast(dest);
  1183. curr = curr->next;
  1184. }
  1185. // We should now be on a label which is the destination of the
  1186. // first JMP in the sequence and is already added in the open paths
  1187. asASSERT(curr->op == asBC_LABEL);
  1188. break;
  1189. }
  1190. curr = curr->next;
  1191. }
  1192. }
  1193. return false;
  1194. }
  1195. bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr)
  1196. {
  1197. TimeIt("asCByteCode::IsTempRegUsed");
  1198. // We're not interested in the first instruction, since it is the one that sets the register
  1199. while( curr->next )
  1200. {
  1201. curr = curr->next;
  1202. // Which instructions read from the register?
  1203. if( curr->op == asBC_INCi ||
  1204. curr->op == asBC_INCi16 ||
  1205. curr->op == asBC_INCi8 ||
  1206. curr->op == asBC_INCf ||
  1207. curr->op == asBC_INCd ||
  1208. curr->op == asBC_DECi ||
  1209. curr->op == asBC_DECi16 ||
  1210. curr->op == asBC_DECi8 ||
  1211. curr->op == asBC_DECf ||
  1212. curr->op == asBC_DECd ||
  1213. curr->op == asBC_WRTV1 ||
  1214. curr->op == asBC_WRTV2 ||
  1215. curr->op == asBC_WRTV4 ||
  1216. curr->op == asBC_WRTV8 ||
  1217. curr->op == asBC_RDR1 ||
  1218. curr->op == asBC_RDR2 ||
  1219. curr->op == asBC_RDR4 ||
  1220. curr->op == asBC_RDR8 ||
  1221. curr->op == asBC_PshRPtr ||
  1222. curr->op == asBC_CpyRtoV4 ||
  1223. curr->op == asBC_CpyRtoV8 ||
  1224. curr->op == asBC_TZ ||
  1225. curr->op == asBC_TNZ ||
  1226. curr->op == asBC_TS ||
  1227. curr->op == asBC_TNS ||
  1228. curr->op == asBC_TP ||
  1229. curr->op == asBC_TNP ||
  1230. curr->op == asBC_JZ ||
  1231. curr->op == asBC_JNZ ||
  1232. curr->op == asBC_JLowZ ||
  1233. curr->op == asBC_JLowNZ ||
  1234. curr->op == asBC_JS ||
  1235. curr->op == asBC_JNS ||
  1236. curr->op == asBC_JP ||
  1237. curr->op == asBC_JNP )
  1238. return true;
  1239. // Which instructions overwrite the register or discard the value?
  1240. if( curr->op == asBC_CALL ||
  1241. curr->op == asBC_PopRPtr ||
  1242. curr->op == asBC_CALLSYS ||
  1243. curr->op == asBC_CALLBND ||
  1244. curr->op == asBC_Thiscall1 ||
  1245. curr->op == asBC_SUSPEND ||
  1246. curr->op == asBC_ALLOC ||
  1247. curr->op == asBC_CpyVtoR4 ||
  1248. curr->op == asBC_LdGRdR4 ||
  1249. curr->op == asBC_LDG ||
  1250. curr->op == asBC_LDV ||
  1251. curr->op == asBC_TZ ||
  1252. curr->op == asBC_TNZ ||
  1253. curr->op == asBC_TS ||
  1254. curr->op == asBC_TNS ||
  1255. curr->op == asBC_TP ||
  1256. curr->op == asBC_TNP ||
  1257. curr->op == asBC_JS ||
  1258. curr->op == asBC_JNS ||
  1259. curr->op == asBC_JP ||
  1260. curr->op == asBC_JNP ||
  1261. curr->op == asBC_JMPP ||
  1262. curr->op == asBC_JMP ||
  1263. curr->op == asBC_JZ ||
  1264. curr->op == asBC_JNZ ||
  1265. curr->op == asBC_JLowZ ||
  1266. curr->op == asBC_JLowNZ ||
  1267. curr->op == asBC_CMPi ||
  1268. curr->op == asBC_CMPu ||
  1269. curr->op == asBC_CMPf ||
  1270. curr->op == asBC_CMPd ||
  1271. curr->op == asBC_CMPIi ||
  1272. curr->op == asBC_CMPIu ||
  1273. curr->op == asBC_CMPIf ||
  1274. curr->op == asBC_LABEL ||
  1275. curr->op == asBC_LoadThisR ||
  1276. curr->op == asBC_LoadRObjR ||
  1277. curr->op == asBC_LoadVObjR )
  1278. return false;
  1279. }
  1280. return false;
  1281. }
  1282. bool asCByteCode::IsSimpleExpression()
  1283. {
  1284. // A simple expression is one that cannot be suspended at any time, i.e.
  1285. // it doesn't have any calls to other routines, and doesn't have any suspend instructions
  1286. asCByteInstruction *instr = first;
  1287. while( instr )
  1288. {
  1289. if( instr->op == asBC_ALLOC ||
  1290. instr->op == asBC_CALL ||
  1291. instr->op == asBC_CALLSYS ||
  1292. instr->op == asBC_SUSPEND ||
  1293. instr->op == asBC_LINE ||
  1294. instr->op == asBC_FREE ||
  1295. instr->op == asBC_CallPtr ||
  1296. instr->op == asBC_CALLINTF ||
  1297. instr->op == asBC_CALLBND ||
  1298. instr->op == asBC_Thiscall1 )
  1299. return false;
  1300. instr = instr->next;
  1301. }
  1302. return true;
  1303. }
  1304. void asCByteCode::ExtractLineNumbers()
  1305. {
  1306. // This function will extract the line number and source file for each statement by looking for LINE instructions.
  1307. // The LINE instructions will be converted to SUSPEND instructions, or removed depending on the configuration.
  1308. TimeIt("asCByteCode::ExtractLineNumbers");
  1309. int lastLinePos = -1;
  1310. int pos = 0;
  1311. asCByteInstruction *instr = first;
  1312. while( instr )
  1313. {
  1314. asCByteInstruction *curr = instr;
  1315. instr = instr->next;
  1316. if( curr->op == asBC_LINE )
  1317. {
  1318. if( lastLinePos == pos )
  1319. {
  1320. lineNumbers.PopLast(); // pop position
  1321. lineNumbers.PopLast(); // pop line number
  1322. sectionIdxs.PopLast(); // pop section index
  1323. }
  1324. lastLinePos = pos;
  1325. lineNumbers.PushLast(pos);
  1326. lineNumbers.PushLast(*(int*)ARG_DW(curr->arg));
  1327. sectionIdxs.PushLast(*((int*)ARG_DW(curr->arg)+1));
  1328. if( !engine->ep.buildWithoutLineCues )
  1329. {
  1330. // Transform BC_LINE into BC_SUSPEND
  1331. curr->op = asBC_SUSPEND;
  1332. curr->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type];
  1333. pos += curr->size;
  1334. }
  1335. else
  1336. {
  1337. // Delete the instruction
  1338. DeleteInstruction(curr);
  1339. }
  1340. }
  1341. else
  1342. pos += curr->size;
  1343. }
  1344. }
  1345. void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc)
  1346. {
  1347. asASSERT( outFunc->scriptData );
  1348. unsigned int pos = 0;
  1349. asCByteInstruction *instr = first;
  1350. int blockLevel = 0;
  1351. while( instr )
  1352. {
  1353. if( instr->op == asBC_Block )
  1354. {
  1355. asSObjectVariableInfo info;
  1356. info.programPos = pos;
  1357. info.variableOffset = 0;
  1358. info.option = instr->wArg[0] ? asBLOCK_BEGIN : asBLOCK_END;
  1359. if( info.option == asBLOCK_BEGIN )
  1360. {
  1361. blockLevel++;
  1362. outFunc->scriptData->objVariableInfo.PushLast(info);
  1363. }
  1364. else
  1365. {
  1366. blockLevel--;
  1367. asASSERT( blockLevel >= 0 );
  1368. if( outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].option == asBLOCK_BEGIN &&
  1369. outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].programPos == pos )
  1370. outFunc->scriptData->objVariableInfo.PopLast();
  1371. else
  1372. outFunc->scriptData->objVariableInfo.PushLast(info);
  1373. }
  1374. }
  1375. else if( instr->op == asBC_ObjInfo )
  1376. {
  1377. asSObjectVariableInfo info;
  1378. info.programPos = pos;
  1379. info.variableOffset = (short)instr->wArg[0];
  1380. info.option = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg);
  1381. outFunc->scriptData->objVariableInfo.PushLast(info);
  1382. }
  1383. else if( instr->op == asBC_VarDecl )
  1384. {
  1385. // Record the position for debug info
  1386. outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos;
  1387. // Record declaration of object variables for try/catch handling
  1388. // This is used for identifying if handles and objects on the heap should be cleared upon catching an exception
  1389. // Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space
  1390. if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() )
  1391. {
  1392. asSObjectVariableInfo info;
  1393. info.programPos = pos;
  1394. info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset;
  1395. info.option = asOBJ_VARDECL;
  1396. outFunc->scriptData->objVariableInfo.PushLast(info);
  1397. }
  1398. }
  1399. else
  1400. pos += instr->size;
  1401. instr = instr->next;
  1402. }
  1403. asASSERT( blockLevel == 0 );
  1404. }
  1405. void asCByteCode::ExtractTryCatchInfo(asCScriptFunction *outFunc)
  1406. {
  1407. asASSERT(outFunc->scriptData);
  1408. unsigned int pos = 0;
  1409. asCByteInstruction *instr = first;
  1410. while (instr)
  1411. {
  1412. if (instr->op == asBC_TryBlock)
  1413. {
  1414. asSTryCatchInfo info;
  1415. info.tryPos = pos;
  1416. info.catchPos = *ARG_DW(instr->arg);
  1417. outFunc->scriptData->tryCatchInfo.PushLast(info);
  1418. }
  1419. pos += instr->size;
  1420. instr = instr->next;
  1421. }
  1422. }
  1423. int asCByteCode::GetSize()
  1424. {
  1425. int size = 0;
  1426. asCByteInstruction *instr = first;
  1427. while( instr )
  1428. {
  1429. size += instr->GetSize();
  1430. instr = instr->next;
  1431. }
  1432. return size;
  1433. }
  1434. void asCByteCode::AddCode(asCByteCode *bc)
  1435. {
  1436. if( bc == this ) return;
  1437. if( bc->first )
  1438. {
  1439. if( first == 0 )
  1440. {
  1441. first = bc->first;
  1442. last = bc->last;
  1443. bc->first = 0;
  1444. bc->last = 0;
  1445. }
  1446. else
  1447. {
  1448. last->next = bc->first;
  1449. bc->first->prev = last;
  1450. last = bc->last;
  1451. bc->first = 0;
  1452. bc->last = 0;
  1453. }
  1454. }
  1455. }
  1456. int asCByteCode::AddInstruction()
  1457. {
  1458. void *ptr = engine->memoryMgr.AllocByteInstruction();
  1459. if( ptr == 0 )
  1460. {
  1461. // Out of memory
  1462. return 0;
  1463. }
  1464. asCByteInstruction *instr = new(ptr) asCByteInstruction();
  1465. if( first == 0 )
  1466. {
  1467. first = last = instr;
  1468. }
  1469. else
  1470. {
  1471. last->AddAfter(instr);
  1472. last = instr;
  1473. }
  1474. return 0;
  1475. }
  1476. int asCByteCode::AddInstructionFirst()
  1477. {
  1478. void *ptr = engine->memoryMgr.AllocByteInstruction();
  1479. if( ptr == 0 )
  1480. {
  1481. // Out of memory
  1482. return 0;
  1483. }
  1484. asCByteInstruction *instr = new(ptr) asCByteInstruction();
  1485. if( first == 0 )
  1486. {
  1487. first = last = instr;
  1488. }
  1489. else
  1490. {
  1491. first->AddBefore(instr);
  1492. first = instr;
  1493. }
  1494. return 0;
  1495. }
  1496. void asCByteCode::Call(asEBCInstr instr, int funcID, int pop)
  1497. {
  1498. if( AddInstruction() < 0 )
  1499. return;
  1500. asASSERT(asBCInfo[instr].type == asBCTYPE_DW_ARG);
  1501. last->op = instr;
  1502. last->size = asBCTypeSize[asBCInfo[instr].type];
  1503. last->stackInc = -pop; // BC_CALL and BC_CALLBND doesn't pop the argument but when the callee returns the arguments are already popped
  1504. *((int*)ARG_DW(last->arg)) = funcID;
  1505. // Add a JitEntry instruction after function calls so that JIT's can resume execution
  1506. InstrPTR(asBC_JitEntry, 0);
  1507. }
  1508. void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop)
  1509. {
  1510. if( AddInstruction() < 0 )
  1511. return;
  1512. asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG);
  1513. last->op = instr;
  1514. last->size = asBCTypeSize[asBCInfo[instr].type];
  1515. last->stackInc = -pop;
  1516. last->wArg[0] = (short)funcPtrVar;
  1517. // Add a JitEntry instruction after function calls so that JIT's can resume execution
  1518. InstrPTR(asBC_JitEntry, 0);
  1519. }
  1520. void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop)
  1521. {
  1522. if( AddInstruction() < 0 )
  1523. return;
  1524. last->op = instr;
  1525. last->size = asBCTypeSize[asBCInfo[instr].type];
  1526. last->stackInc = -pop; // BC_ALLOC
  1527. asASSERT(asBCInfo[instr].type == asBCTYPE_PTR_DW_ARG);
  1528. *ARG_PTR(last->arg) = (asPWORD)objID;
  1529. *((int*)(ARG_DW(last->arg)+AS_PTR_SIZE)) = funcID;
  1530. // Add a JitEntry instruction after function calls so that JIT's can resume execution
  1531. InstrPTR(asBC_JitEntry, 0);
  1532. }
  1533. void asCByteCode::Ret(int pop)
  1534. {
  1535. if( AddInstruction() < 0 )
  1536. return;
  1537. asASSERT(asBCInfo[asBC_RET].type == asBCTYPE_W_ARG);
  1538. last->op = asBC_RET;
  1539. last->size = asBCTypeSize[asBCInfo[asBC_RET].type];
  1540. last->stackInc = 0; // The instruction pops the argument, but it doesn't affect current function
  1541. last->wArg[0] = (short)pop;
  1542. }
  1543. void asCByteCode::JmpP(int var, asDWORD max)
  1544. {
  1545. if( AddInstruction() < 0 )
  1546. return;
  1547. asASSERT(asBCInfo[asBC_JMPP].type == asBCTYPE_rW_ARG);
  1548. last->op = asBC_JMPP;
  1549. last->size = asBCTypeSize[asBCInfo[asBC_JMPP].type];
  1550. last->stackInc = asBCInfo[asBC_JMPP].stackInc;
  1551. last->wArg[0] = (short)var;
  1552. // Store the largest jump that is made for PostProcess()
  1553. *ARG_DW(last->arg) = max;
  1554. }
  1555. void asCByteCode::Label(short label)
  1556. {
  1557. if( AddInstruction() < 0 )
  1558. return;
  1559. last->op = asBC_LABEL;
  1560. last->size = 0;
  1561. last->stackInc = 0;
  1562. last->wArg[0] = label;
  1563. }
  1564. void asCByteCode::Line(int line, int column, int scriptIdx)
  1565. {
  1566. if( AddInstruction() < 0 )
  1567. return;
  1568. last->op = asBC_LINE;
  1569. // If the build is without line cues these instructions will be removed
  1570. // otherwise they will be transformed into SUSPEND instructions.
  1571. if( engine->ep.buildWithoutLineCues )
  1572. last->size = 0;
  1573. else
  1574. last->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type];
  1575. last->stackInc = 0;
  1576. *((int*)ARG_DW(last->arg)) = (line & 0xFFFFF)|((column & 0xFFF)<<20);
  1577. *((int*)ARG_DW(last->arg)+1) = scriptIdx;
  1578. // Add a JitEntry after the line instruction to allow the JIT function to resume after a suspend
  1579. InstrPTR(asBC_JitEntry, 0);
  1580. }
  1581. void asCByteCode::ObjInfo(int offset, int info)
  1582. {
  1583. if( AddInstruction() < 0 )
  1584. return;
  1585. // Add the special instruction that will be used to tell the exception
  1586. // handler when an object is initialized and deinitialized.
  1587. last->op = asBC_ObjInfo;
  1588. last->size = 0;
  1589. last->stackInc = 0;
  1590. last->wArg[0] = (short)offset;
  1591. *((int*)ARG_DW(last->arg)) = info;
  1592. }
  1593. void asCByteCode::Block(bool start)
  1594. {
  1595. if( AddInstruction() < 0 )
  1596. return;
  1597. last->op = asBC_Block;
  1598. last->size = 0;
  1599. last->stackInc = 0;
  1600. last->wArg[0] = start ? 1 : 0;
  1601. }
  1602. void asCByteCode::TryBlock(short catchLabel)
  1603. {
  1604. if (AddInstruction() < 0)
  1605. return;
  1606. last->op = asBC_TryBlock;
  1607. last->size = 0;
  1608. last->stackInc = 0;
  1609. *ARG_DW(last->arg) = catchLabel;
  1610. }
  1611. void asCByteCode::VarDecl(int varDeclIdx)
  1612. {
  1613. if( AddInstruction() < 0 )
  1614. return;
  1615. last->op = asBC_VarDecl;
  1616. last->size = 0;
  1617. last->stackInc = 0;
  1618. last->wArg[0] = asWORD(varDeclIdx);
  1619. }
  1620. int asCByteCode::FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta)
  1621. {
  1622. TimeIt("asCByteCode::FindLabel");
  1623. // Search forward
  1624. int labelPos = -from->GetSize();
  1625. asCByteInstruction *labelInstr = from;
  1626. while( labelInstr )
  1627. {
  1628. labelPos += labelInstr->GetSize();
  1629. labelInstr = labelInstr->next;
  1630. if( labelInstr && labelInstr->op == asBC_LABEL )
  1631. {
  1632. if( labelInstr->wArg[0] == label )
  1633. break;
  1634. }
  1635. }
  1636. if( labelInstr == 0 )
  1637. {
  1638. // Search backwards
  1639. labelPos = -from->GetSize();
  1640. labelInstr = from;
  1641. while( labelInstr )
  1642. {
  1643. labelInstr = labelInstr->prev;
  1644. if( labelInstr )
  1645. {
  1646. labelPos -= labelInstr->GetSize();
  1647. if( labelInstr->op == asBC_LABEL )
  1648. {
  1649. if( labelInstr->wArg[0] == label )
  1650. break;
  1651. }
  1652. }
  1653. }
  1654. }
  1655. if( labelInstr != 0 )
  1656. {
  1657. if( dest ) *dest = labelInstr;
  1658. if( positionDelta ) *positionDelta = labelPos;
  1659. return 0;
  1660. }
  1661. return -1;
  1662. }
  1663. int asCByteCode::ResolveJumpAddresses()
  1664. {
  1665. TimeIt("asCByteCode::ResolveJumpAddresses");
  1666. asUINT currPos = 0;
  1667. asCByteInstruction *instr = first;
  1668. while( instr )
  1669. {
  1670. if( instr->op == asBC_JMP ||
  1671. instr->op == asBC_JZ || instr->op == asBC_JNZ ||
  1672. instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
  1673. instr->op == asBC_JS || instr->op == asBC_JNS ||
  1674. instr->op == asBC_JP || instr->op == asBC_JNP )
  1675. {
  1676. int label = *((int*) ARG_DW(instr->arg));
  1677. int labelPosOffset;
  1678. int r = FindLabel(label, instr, 0, &labelPosOffset);
  1679. if( r == 0 )
  1680. *((int*) ARG_DW(instr->arg)) = labelPosOffset;
  1681. else
  1682. return -1;
  1683. }
  1684. else if (instr->op == asBC_TryBlock)
  1685. {
  1686. int label = *((int*)ARG_DW(instr->arg));
  1687. int labelPosOffset;
  1688. int r = FindLabel(label, instr, 0, &labelPosOffset);
  1689. if (r == 0)
  1690. {
  1691. // Should store the absolute address so the exception handler doesn't need to figure it out
  1692. *((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset;
  1693. }
  1694. else
  1695. return -1;
  1696. }
  1697. currPos += instr->GetSize();
  1698. instr = instr->next;
  1699. }
  1700. return 0;
  1701. }
  1702. asCByteInstruction *asCByteCode::DeleteInstruction(asCByteInstruction *instr)
  1703. {
  1704. if( instr == 0 ) return 0;
  1705. asCByteInstruction *ret = instr->prev ? instr->prev : instr->next;
  1706. RemoveInstruction(instr);
  1707. engine->memoryMgr.FreeByteInstruction(instr);
  1708. return ret;
  1709. }
  1710. void asCByteCode::Output(asDWORD *array)
  1711. {
  1712. TimeIt("asCByteCode::Output");
  1713. // TODO: Receive a script function pointer instead of the bytecode array
  1714. asDWORD *ap = array;
  1715. asCByteInstruction *instr = first;
  1716. while( instr )
  1717. {
  1718. if( instr->GetSize() > 0 )
  1719. {
  1720. *(asBYTE*)ap = asBYTE(instr->op);
  1721. *(((asBYTE*)ap)+1) = 0; // Second byte is always zero
  1722. switch( asBCInfo[instr->op].type )
  1723. {
  1724. case asBCTYPE_NO_ARG:
  1725. *(((asWORD*)ap)+1) = 0; // Clear upper bytes
  1726. break;
  1727. case asBCTYPE_wW_rW_rW_ARG:
  1728. *(((asWORD*)ap)+1) = instr->wArg[0];
  1729. *(((asWORD*)ap)+2) = instr->wArg[1];
  1730. *(((asWORD*)ap)+3) = instr->wArg[2];
  1731. break;
  1732. case asBCTYPE_wW_DW_ARG:
  1733. case asBCTYPE_rW_DW_ARG:
  1734. case asBCTYPE_W_DW_ARG:
  1735. *(((asWORD*)ap)+1) = instr->wArg[0];
  1736. *(ap+1) = *(asDWORD*)&instr->arg;
  1737. break;
  1738. case asBCTYPE_wW_rW_DW_ARG:
  1739. case asBCTYPE_rW_W_DW_ARG:
  1740. *(((asWORD*)ap)+1) = instr->wArg[0];
  1741. *(((asWORD*)ap)+2) = instr->wArg[1];
  1742. *(ap+2) = *(asDWORD*)&instr->arg;
  1743. break;
  1744. case asBCTYPE_wW_QW_ARG:
  1745. case asBCTYPE_rW_QW_ARG:
  1746. *(((asWORD*)ap)+1) = instr->wArg[0];
  1747. *(asQWORD*)(ap+1) = asQWORD(instr->arg);
  1748. break;
  1749. case asBCTYPE_W_ARG:
  1750. case asBCTYPE_rW_ARG:
  1751. case asBCTYPE_wW_ARG:
  1752. *(((asWORD*)ap)+1) = instr->wArg[0];
  1753. break;
  1754. case asBCTYPE_wW_rW_ARG:
  1755. case asBCTYPE_rW_rW_ARG:
  1756. case asBCTYPE_wW_W_ARG:
  1757. *(((asWORD *)ap)+1) = instr->wArg[0];
  1758. *(((asWORD *)ap)+2) = instr->wArg[1];
  1759. break;
  1760. case asBCTYPE_QW_DW_ARG:
  1761. case asBCTYPE_DW_DW_ARG:
  1762. case asBCTYPE_QW_ARG:
  1763. case asBCTYPE_DW_ARG:
  1764. *(((asWORD*)ap)+1) = 0; // Clear upper bytes
  1765. memcpy(ap+1, &instr->arg, instr->GetSize()*4-4);
  1766. break;
  1767. case asBCTYPE_rW_DW_DW_ARG:
  1768. *(((asWORD*)ap)+1) = instr->wArg[0];
  1769. memcpy(ap+1, &instr->arg, instr->GetSize()*4-4);
  1770. break;
  1771. default:
  1772. // How did we get here?
  1773. asASSERT(false);
  1774. break;
  1775. }
  1776. }
  1777. ap += instr->GetSize();
  1778. instr = instr->next;
  1779. }
  1780. }
  1781. void asCByteCode::PostProcess()
  1782. {
  1783. TimeIt("asCByteCode::PostProcess");
  1784. if( first == 0 ) return;
  1785. // This function will do the following
  1786. // - Verify if there is any code that never gets executed and remove it
  1787. // - Calculate the stack size at the position of each byte code
  1788. // - Calculate the largest stack needed
  1789. largestStackUsed = 0;
  1790. asCByteInstruction *instr = first;
  1791. while( instr )
  1792. {
  1793. instr->marked = false;
  1794. instr->stackSize = -1;
  1795. instr = instr->next;
  1796. }
  1797. // Add the first instruction to the list of unchecked code paths
  1798. asCArray<asCByteInstruction *> paths;
  1799. AddPath(paths, first, 0);
  1800. // Go through each of the code paths
  1801. for( asUINT p = 0; p < paths.GetLength(); ++p )
  1802. {
  1803. instr = paths[p];
  1804. int stackSize = instr->stackSize;
  1805. while( instr )
  1806. {
  1807. instr->marked = true;
  1808. instr->stackSize = stackSize;
  1809. stackSize += instr->stackInc;
  1810. if( stackSize > largestStackUsed )
  1811. largestStackUsed = stackSize;
  1812. if( instr->op == asBC_JMP )
  1813. {
  1814. // Find the label that we should jump to
  1815. int label = *((int*) ARG_DW(instr->arg));
  1816. asCByteInstruction *dest = 0;
  1817. int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
  1818. AddPath(paths, dest, stackSize);
  1819. break;
  1820. }
  1821. else if( instr->op == asBC_JZ || instr->op == asBC_JNZ ||
  1822. instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
  1823. instr->op == asBC_JS || instr->op == asBC_JNS ||
  1824. instr->op == asBC_JP || instr->op == asBC_JNP ||
  1825. instr->op == asBC_TryBlock )
  1826. {
  1827. // Find the label that is being jumped to
  1828. int label = *((int*) ARG_DW(instr->arg));
  1829. asCByteInstruction *dest = 0;
  1830. int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r);
  1831. AddPath(paths, dest, stackSize);
  1832. // Add both paths to the code paths
  1833. AddPath(paths, instr->next, stackSize);
  1834. break;
  1835. }
  1836. else if( instr->op == asBC_JMPP )
  1837. {
  1838. // I need to know the largest value possible
  1839. asDWORD max = *ARG_DW(instr->arg);
  1840. // Add all destinations to the code paths
  1841. asCByteInstruction *dest = instr->next;
  1842. for( asDWORD n = 0; n <= max && dest != 0; ++n )
  1843. {
  1844. AddPath(paths, dest, stackSize);
  1845. dest = dest->next;
  1846. }
  1847. break;
  1848. }
  1849. else
  1850. {
  1851. instr = instr->next;
  1852. if( instr == 0 || instr->marked )
  1853. break;
  1854. }
  1855. }
  1856. }
  1857. // Are there any instructions that didn't get visited?
  1858. instr = first;
  1859. while( instr )
  1860. {
  1861. // Don't remove asBC_Block instructions as then the start and end of blocks may become mismatched
  1862. if( instr->marked == false && instr->op != asBC_Block )
  1863. {
  1864. // Remove it
  1865. asCByteInstruction *curr = instr;
  1866. instr = instr->next;
  1867. DeleteInstruction(curr);
  1868. }
  1869. else
  1870. {
  1871. #ifndef AS_DEBUG
  1872. // If the stackSize is negative, then there is a problem with the bytecode.
  1873. // If AS_DEBUG is turned on, this same check is done in DebugOutput.
  1874. asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO );
  1875. #endif
  1876. instr = instr->next;
  1877. }
  1878. }
  1879. }
  1880. #ifdef AS_DEBUG
  1881. void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func)
  1882. {
  1883. #ifndef __MINGW32__
  1884. // _mkdir is broken on mingw
  1885. _mkdir("AS_DEBUG");
  1886. #endif
  1887. asCString path = "AS_DEBUG/";
  1888. path += name;
  1889. // Anonymous functions created from within class methods will contain :: as part of the name
  1890. // Replace :: with __ to avoid error when creating the file for debug output
  1891. for (asUINT n = 0; n < path.GetLength(); n++)
  1892. if (path[n] == ':') path[n] = '_';
  1893. #if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
  1894. FILE *file;
  1895. fopen_s(&file, path.AddressOf(), "w");
  1896. #else
  1897. FILE *file = fopen(path.AddressOf(), "w");
  1898. #endif
  1899. #if !defined(AS_XENON) && !defined(__MINGW32__)
  1900. // XBox 360: When running in DVD Emu, no write is allowed
  1901. // MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist
  1902. asASSERT( file );
  1903. #endif
  1904. if( file == 0 )
  1905. return;
  1906. asUINT n;
  1907. fprintf(file, "%s\n\n", func->GetDeclaration());
  1908. fprintf(file, "Temps: ");
  1909. for( n = 0; n < temporaryVariables->GetLength(); n++ )
  1910. {
  1911. fprintf(file, "%d", (*temporaryVariables)[n]);
  1912. if( n < temporaryVariables->GetLength()-1 )
  1913. fprintf(file, ", ");
  1914. }
  1915. fprintf(file, "\n\n");
  1916. fprintf(file, "Variables: \n");
  1917. for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
  1918. {
  1919. int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->variables[n]->stackOffset);
  1920. bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
  1921. fprintf(file, " %.3d: %s%s %s\n", func->scriptData->variables[n]->stackOffset, isOnHeap ? "(heap) " : "", func->scriptData->variables[n]->type.Format(func->nameSpace, true).AddressOf(), func->scriptData->variables[n]->name.AddressOf());
  1922. }
  1923. asUINT offset = 0;
  1924. if( func->objectType )
  1925. {
  1926. fprintf(file, " %.3d: %s this\n", 0, func->objectType->name.AddressOf());
  1927. offset -= AS_PTR_SIZE;
  1928. }
  1929. for( n = 0; n < func->parameterTypes.GetLength(); n++ )
  1930. {
  1931. bool found = false;
  1932. for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ )
  1933. {
  1934. if( func->scriptData->variables[v]->stackOffset == (int)offset )
  1935. {
  1936. found = true;
  1937. break;
  1938. }
  1939. }
  1940. if( !found )
  1941. {
  1942. int idx = func->scriptData->objVariablePos.IndexOf(offset);
  1943. bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
  1944. fprintf(file, " %.3d: %s%s {noname param}\n", offset, isOnHeap ? "(heap) " : "", func->parameterTypes[n].Format(func->nameSpace, true).AddressOf());
  1945. }
  1946. offset -= func->parameterTypes[n].GetSizeOnStackDWords();
  1947. }
  1948. for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
  1949. {
  1950. bool found = false;
  1951. for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ )
  1952. {
  1953. if( func->scriptData->variables[v]->stackOffset == func->scriptData->objVariablePos[n] )
  1954. {
  1955. found = true;
  1956. break;
  1957. }
  1958. }
  1959. if( !found )
  1960. {
  1961. if( func->scriptData->objVariableTypes[n] )
  1962. {
  1963. int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->objVariablePos[n]);
  1964. bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
  1965. fprintf(file, " %.3d: %s%s {noname}\n", func->scriptData->objVariablePos[n], isOnHeap ? "(heap) " : "", func->scriptData->objVariableTypes[n]->name.AddressOf());
  1966. }
  1967. else
  1968. fprintf(file, " %.3d: null handle {noname}\n", func->scriptData->objVariablePos[n]);
  1969. }
  1970. }
  1971. fprintf(file, "\n\n");
  1972. bool invalidStackSize = false;
  1973. int pos = 0;
  1974. asUINT lineIndex = 0;
  1975. asCByteInstruction *instr = first;
  1976. while( instr )
  1977. {
  1978. if( lineIndex < lineNumbers.GetLength() && lineNumbers[lineIndex] == pos )
  1979. {
  1980. asDWORD line = lineNumbers[lineIndex+1];
  1981. fprintf(file, "- %d,%d -\n", (int)(line&0xFFFFF), (int)(line>>20));
  1982. lineIndex += 2;
  1983. }
  1984. if( instr->GetSize() > 0 )
  1985. {
  1986. fprintf(file, "%5d ", pos);
  1987. pos += instr->GetSize();
  1988. fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' ');
  1989. if( instr->stackSize < 0 )
  1990. invalidStackSize = true;
  1991. }
  1992. else
  1993. {
  1994. fprintf(file, " ");
  1995. }
  1996. switch( asBCInfo[instr->op].type )
  1997. {
  1998. case asBCTYPE_W_ARG:
  1999. fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]);
  2000. break;
  2001. case asBCTYPE_wW_ARG:
  2002. case asBCTYPE_rW_ARG:
  2003. fprintf(file, " %-8s v%d\n", asBCInfo[instr->op].name, instr->wArg[0]);
  2004. break;
  2005. case asBCTYPE_wW_rW_ARG:
  2006. case asBCTYPE_rW_rW_ARG:
  2007. fprintf(file, " %-8s v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]);
  2008. break;
  2009. case asBCTYPE_wW_W_ARG:
  2010. fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]);
  2011. break;
  2012. case asBCTYPE_wW_rW_DW_ARG:
  2013. case asBCTYPE_rW_W_DW_ARG:
  2014. switch( instr->op )
  2015. {
  2016. case asBC_ADDIf:
  2017. case asBC_SUBIf:
  2018. case asBC_MULIf:
  2019. fprintf(file, " %-8s v%d, v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((float*) ARG_DW(instr->arg)));
  2020. break;
  2021. default:
  2022. fprintf(file, " %-8s v%d, v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((int*) ARG_DW(instr->arg)));
  2023. break;
  2024. }
  2025. break;
  2026. case asBCTYPE_DW_ARG:
  2027. switch( instr->op )
  2028. {
  2029. case asBC_OBJTYPE:
  2030. {
  2031. asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
  2032. fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName());
  2033. }
  2034. break;
  2035. case asBC_FuncPtr:
  2036. {
  2037. asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg);
  2038. fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration());
  2039. }
  2040. break;
  2041. case asBC_PshC4:
  2042. case asBC_Cast:
  2043. 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)));
  2044. break;
  2045. case asBC_TYPEID:
  2046. fprintf(file, " %-8s 0x%x '%s'\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), engine->GetTypeDeclaration((int)*ARG_DW(instr->arg)));
  2047. break;
  2048. case asBC_CALL:
  2049. case asBC_CALLSYS:
  2050. case asBC_CALLBND:
  2051. case asBC_CALLINTF:
  2052. case asBC_Thiscall1:
  2053. {
  2054. int funcID = *(int*)ARG_DW(instr->arg);
  2055. asCString decl = engine->GetFunctionDeclaration(funcID);
  2056. fprintf(file, " %-8s %d (%s)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), decl.AddressOf());
  2057. }
  2058. break;
  2059. case asBC_REFCPY:
  2060. fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)));
  2061. break;
  2062. case asBC_JMP:
  2063. case asBC_JZ:
  2064. case asBC_JLowZ:
  2065. case asBC_JS:
  2066. case asBC_JP:
  2067. case asBC_JNZ:
  2068. case asBC_JLowNZ:
  2069. case asBC_JNS:
  2070. case asBC_JNP:
  2071. fprintf(file, " %-8s %+d (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg)));
  2072. break;
  2073. default:
  2074. fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)));
  2075. break;
  2076. }
  2077. break;
  2078. case asBCTYPE_QW_ARG:
  2079. switch( instr->op )
  2080. {
  2081. case asBC_OBJTYPE:
  2082. {
  2083. asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
  2084. fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName());
  2085. }
  2086. break;
  2087. case asBC_FuncPtr:
  2088. {
  2089. asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg);
  2090. fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration());
  2091. }
  2092. break;
  2093. case asBC_PGA:
  2094. {
  2095. void *ptr = *(void**)ARG_QW(instr->arg);
  2096. asSMapNode<void*, asCGlobalProperty*> *cursor = 0;
  2097. if( engine->varAddressMap.MoveTo(&cursor, ptr) )
  2098. {
  2099. fprintf(file, " %-8s 0x%x (var:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), cursor->value->name.AddressOf());
  2100. }
  2101. else
  2102. {
  2103. asUINT length;
  2104. engine->stringFactory->GetRawStringData(ptr, 0, &length);
  2105. asCString str;
  2106. str.SetLength(length);
  2107. engine->stringFactory->GetRawStringData(ptr, str.AddressOf(), &length);
  2108. if (str.GetLength() > 20)
  2109. {
  2110. // TODO: Replace non-visible characters with space or something like it
  2111. str.SetLength(20);
  2112. str += "...";
  2113. }
  2114. fprintf(file, " %-8s 0x%x (str:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), str.AddressOf());
  2115. }
  2116. }
  2117. break;
  2118. default:
  2119. #ifdef __GNUC__
  2120. #ifdef _LP64
  2121. 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)));
  2122. #else
  2123. 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)));
  2124. #endif
  2125. #else
  2126. 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)));
  2127. #endif
  2128. }
  2129. break;
  2130. case asBCTYPE_wW_QW_ARG:
  2131. case asBCTYPE_rW_QW_ARG:
  2132. switch( instr->op )
  2133. {
  2134. case asBC_RefCpyV:
  2135. case asBC_FREE:
  2136. {
  2137. asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
  2138. fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName());
  2139. }
  2140. break;
  2141. default:
  2142. #ifdef __GNUC__
  2143. #ifdef _LP64
  2144. 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)));
  2145. #else
  2146. 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)));
  2147. #endif
  2148. #else
  2149. 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)));
  2150. #endif
  2151. }
  2152. break;
  2153. case asBCTYPE_DW_DW_ARG:
  2154. if( instr->op == asBC_ALLOC )
  2155. {
  2156. asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
  2157. asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
  2158. fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
  2159. }
  2160. else
  2161. fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1));
  2162. break;
  2163. case asBCTYPE_rW_DW_DW_ARG:
  2164. 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));
  2165. break;
  2166. case asBCTYPE_QW_DW_ARG:
  2167. if( instr->op == asBC_ALLOC )
  2168. {
  2169. asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
  2170. asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]];
  2171. #if defined(__GNUC__) && !defined(_MSC_VER)
  2172. #ifdef AS_64BIT_PTR
  2173. fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
  2174. #else
  2175. fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
  2176. #endif
  2177. #else
  2178. fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}");
  2179. #endif
  2180. }
  2181. else
  2182. #if defined(__GNUC__) && !defined(_MSC_VER)
  2183. #ifdef AS_64BIT_PTR
  2184. fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
  2185. #else
  2186. fprintf(file, " %-8s %llu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
  2187. #endif
  2188. #else
  2189. fprintf(file, " %-8s %I64u, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2));
  2190. #endif
  2191. break;
  2192. case asBCTYPE_INFO:
  2193. if( instr->op == asBC_LABEL )
  2194. fprintf(file, "%d:\n", instr->wArg[0]);
  2195. else if( instr->op == asBC_LINE )
  2196. fprintf(file, " %s\n", asBCInfo[instr->op].name);
  2197. else if( instr->op == asBC_Block )
  2198. fprintf(file, "%c\n", instr->wArg[0] ? '{' : '}');
  2199. break;
  2200. case asBCTYPE_rW_DW_ARG:
  2201. case asBCTYPE_wW_DW_ARG:
  2202. case asBCTYPE_W_DW_ARG:
  2203. if( instr->op == asBC_SetV1 )
  2204. fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asBYTE*)ARG_DW(instr->arg));
  2205. else if( instr->op == asBC_SetV2 )
  2206. fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asWORD*)ARG_DW(instr->arg));
  2207. else if( instr->op == asBC_SetV4 )
  2208. 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)));
  2209. else if( instr->op == asBC_CMPIf )
  2210. fprintf(file, " %-8s v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], *(float*)ARG_DW(instr->arg));
  2211. else
  2212. fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg));
  2213. break;
  2214. case asBCTYPE_wW_rW_rW_ARG:
  2215. fprintf(file, " %-8s v%d, v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], instr->wArg[2]);
  2216. break;
  2217. case asBCTYPE_NO_ARG:
  2218. fprintf(file, " %s\n", asBCInfo[instr->op].name);
  2219. break;
  2220. default:
  2221. asASSERT(false);
  2222. }
  2223. instr = instr->next;
  2224. }
  2225. fclose(file);
  2226. // If the stackSize is negative then there is something wrong with the
  2227. // bytecode, i.e. there is a bug in the compiler or in the optimizer. We
  2228. // only check this here to have the bytecode available on file for verification
  2229. asASSERT( !invalidStackSize );
  2230. }
  2231. #endif
  2232. //=============================================================================
  2233. int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param)
  2234. {
  2235. asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
  2236. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2237. if( AddInstructionFirst() < 0 )
  2238. return 0;
  2239. first->op = bc;
  2240. *ARG_DW(first->arg) = param;
  2241. first->size = asBCTypeSize[asBCInfo[bc].type];
  2242. first->stackInc = asBCInfo[bc].stackInc;
  2243. return first->stackInc;
  2244. }
  2245. int asCByteCode::InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param)
  2246. {
  2247. asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
  2248. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2249. if( AddInstructionFirst() < 0 )
  2250. return 0;
  2251. first->op = bc;
  2252. *ARG_QW(first->arg) = param;
  2253. first->size = asBCTypeSize[asBCInfo[bc].type];
  2254. first->stackInc = asBCInfo[bc].stackInc;
  2255. return first->stackInc;
  2256. }
  2257. int asCByteCode::Instr(asEBCInstr bc)
  2258. {
  2259. asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG);
  2260. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2261. if( AddInstruction() < 0 )
  2262. return 0;
  2263. last->op = bc;
  2264. last->size = asBCTypeSize[asBCInfo[bc].type];
  2265. last->stackInc = asBCInfo[bc].stackInc;
  2266. return last->stackInc;
  2267. }
  2268. int asCByteCode::InstrW_W_W(asEBCInstr bc, int a, int b, int c)
  2269. {
  2270. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_rW_ARG);
  2271. asASSERT(asBCInfo[bc].stackInc == 0);
  2272. if( AddInstruction() < 0 )
  2273. return 0;
  2274. last->op = bc;
  2275. last->wArg[0] = (short)a;
  2276. last->wArg[1] = (short)b;
  2277. last->wArg[2] = (short)c;
  2278. last->size = asBCTypeSize[asBCInfo[bc].type];
  2279. last->stackInc = asBCInfo[bc].stackInc;
  2280. return last->stackInc;
  2281. }
  2282. int asCByteCode::InstrW_W(asEBCInstr bc, int a, int b)
  2283. {
  2284. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_ARG ||
  2285. asBCInfo[bc].type == asBCTYPE_rW_rW_ARG);
  2286. asASSERT(asBCInfo[bc].stackInc == 0);
  2287. if( AddInstruction() < 0 )
  2288. return 0;
  2289. last->op = bc;
  2290. last->wArg[0] = (short)a;
  2291. last->wArg[1] = (short)b;
  2292. last->size = asBCTypeSize[asBCInfo[bc].type];
  2293. last->stackInc = asBCInfo[bc].stackInc;
  2294. return last->stackInc;
  2295. }
  2296. int asCByteCode::InstrW_PTR(asEBCInstr bc, short a, void *param)
  2297. {
  2298. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_PTR_ARG);
  2299. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2300. if( AddInstruction() < 0 )
  2301. return 0;
  2302. last->op = bc;
  2303. last->wArg[0] = a;
  2304. *ARG_PTR(last->arg) = (asPWORD)param;
  2305. last->size = asBCTypeSize[asBCInfo[bc].type];
  2306. last->stackInc = asBCInfo[bc].stackInc;
  2307. return last->stackInc;
  2308. }
  2309. int asCByteCode::InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b)
  2310. {
  2311. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
  2312. asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
  2313. asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
  2314. asASSERT(asBCInfo[bc].stackInc == 0);
  2315. if( AddInstruction() < 0 )
  2316. return 0;
  2317. last->op = bc;
  2318. last->wArg[0] = a;
  2319. *((int*) ARG_DW(last->arg)) = b;
  2320. last->size = asBCTypeSize[asBCInfo[bc].type];
  2321. last->stackInc = asBCInfo[bc].stackInc;
  2322. return last->stackInc;
  2323. }
  2324. int asCByteCode::InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c)
  2325. {
  2326. asASSERT(asBCInfo[bc].type == asBCTYPE_rW_DW_DW_ARG);
  2327. asASSERT(asBCInfo[bc].stackInc == 0);
  2328. if( AddInstruction() < 0 )
  2329. return 0;
  2330. last->op = bc;
  2331. last->wArg[0] = a;
  2332. *(int*)ARG_DW(last->arg) = b;
  2333. *(int*)(ARG_DW(last->arg)+1) = c;
  2334. last->size = asBCTypeSize[asBCInfo[bc].type];
  2335. last->stackInc = asBCInfo[bc].stackInc;
  2336. return last->stackInc;
  2337. }
  2338. int asCByteCode::InstrSHORT_B(asEBCInstr bc, short a, asBYTE b)
  2339. {
  2340. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
  2341. asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
  2342. asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
  2343. asASSERT(asBCInfo[bc].stackInc == 0);
  2344. if( AddInstruction() < 0 )
  2345. return 0;
  2346. last->op = bc;
  2347. last->wArg[0] = a;
  2348. // We'll have to be careful to store the byte correctly, independent of endianess.
  2349. // Some optimizing compilers may change the order of operations, so we make sure
  2350. // the value is not overwritten even if that happens.
  2351. asBYTE *argPtr = (asBYTE*)ARG_DW(last->arg);
  2352. argPtr[0] = b; // The value is always stored in the lower byte
  2353. argPtr[1] = 0; // and clear the rest of the DWORD
  2354. argPtr[2] = 0;
  2355. argPtr[3] = 0;
  2356. last->size = asBCTypeSize[asBCInfo[bc].type];
  2357. last->stackInc = asBCInfo[bc].stackInc;
  2358. return last->stackInc;
  2359. }
  2360. int asCByteCode::InstrSHORT_W(asEBCInstr bc, short a, asWORD b)
  2361. {
  2362. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
  2363. asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
  2364. asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
  2365. asASSERT(asBCInfo[bc].stackInc == 0);
  2366. if( AddInstruction() < 0 )
  2367. return 0;
  2368. last->op = bc;
  2369. last->wArg[0] = a;
  2370. // We'll have to be careful to store the word correctly, independent of endianess.
  2371. // Some optimizing compilers may change the order of operations, so we make sure
  2372. // the value is not overwritten even if that happens.
  2373. asWORD *argPtr = (asWORD*)ARG_DW(last->arg);
  2374. argPtr[0] = b; // The value is always stored in the lower word
  2375. argPtr[1] = 0; // and clear the rest of the DWORD
  2376. last->size = asBCTypeSize[asBCInfo[bc].type];
  2377. last->stackInc = asBCInfo[bc].stackInc;
  2378. return last->stackInc;
  2379. }
  2380. int asCByteCode::InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b)
  2381. {
  2382. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG ||
  2383. asBCInfo[bc].type == asBCTYPE_rW_DW_ARG ||
  2384. asBCInfo[bc].type == asBCTYPE_W_DW_ARG);
  2385. if( AddInstruction() < 0 )
  2386. return 0;
  2387. last->op = bc;
  2388. last->wArg[0] = a;
  2389. *((int*) ARG_DW(last->arg)) = b;
  2390. last->size = asBCTypeSize[asBCInfo[bc].type];
  2391. last->stackInc = asBCInfo[bc].stackInc;
  2392. return last->stackInc;
  2393. }
  2394. int asCByteCode::InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b)
  2395. {
  2396. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG);
  2397. asASSERT(asBCInfo[bc].stackInc == 0);
  2398. if( AddInstruction() < 0 )
  2399. return 0;
  2400. last->op = bc;
  2401. last->wArg[0] = a;
  2402. *ARG_QW(last->arg) = b;
  2403. last->size = asBCTypeSize[asBCInfo[bc].type];
  2404. last->stackInc = asBCInfo[bc].stackInc;
  2405. return last->stackInc;
  2406. }
  2407. int asCByteCode::InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b)
  2408. {
  2409. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG);
  2410. asASSERT(asBCInfo[bc].stackInc == 0);
  2411. if( AddInstruction() < 0 )
  2412. return 0;
  2413. last->op = bc;
  2414. last->wArg[0] = a;
  2415. *ARG_QW(last->arg) = b;
  2416. last->size = asBCTypeSize[asBCInfo[bc].type];
  2417. last->stackInc = asBCInfo[bc].stackInc;
  2418. return last->stackInc;
  2419. }
  2420. int asCByteCode::InstrW_FLOAT(asEBCInstr bc, asWORD a, float b)
  2421. {
  2422. asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG);
  2423. asASSERT(asBCInfo[bc].stackInc == 0);
  2424. if( AddInstruction() < 0 )
  2425. return 0;
  2426. last->op = bc;
  2427. last->wArg[0] = a;
  2428. *((float*) ARG_DW(last->arg)) = b;
  2429. last->size = asBCTypeSize[asBCInfo[bc].type];
  2430. last->stackInc = asBCInfo[bc].stackInc;
  2431. return last->stackInc;
  2432. }
  2433. int asCByteCode::InstrSHORT(asEBCInstr bc, short param)
  2434. {
  2435. asASSERT(asBCInfo[bc].type == asBCTYPE_rW_ARG ||
  2436. asBCInfo[bc].type == asBCTYPE_wW_ARG ||
  2437. asBCInfo[bc].type == asBCTYPE_W_ARG);
  2438. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2439. if( AddInstruction() < 0 )
  2440. return 0;
  2441. last->op = bc;
  2442. last->wArg[0] = param;
  2443. last->size = asBCTypeSize[asBCInfo[bc].type];
  2444. last->stackInc = asBCInfo[bc].stackInc;
  2445. return last->stackInc;
  2446. }
  2447. int asCByteCode::InstrINT(asEBCInstr bc, int param)
  2448. {
  2449. asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
  2450. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2451. if( AddInstruction() < 0 )
  2452. return 0;
  2453. last->op = bc;
  2454. *((int*) ARG_DW(last->arg)) = param;
  2455. last->size = asBCTypeSize[asBCInfo[bc].type];
  2456. last->stackInc = asBCInfo[bc].stackInc;
  2457. return last->stackInc;
  2458. }
  2459. int asCByteCode::InstrDWORD(asEBCInstr bc, asDWORD param)
  2460. {
  2461. asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
  2462. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2463. if( AddInstruction() < 0 )
  2464. return 0;
  2465. last->op = bc;
  2466. *ARG_DW(last->arg) = param;
  2467. last->size = asBCTypeSize[asBCInfo[bc].type];
  2468. last->stackInc = asBCInfo[bc].stackInc;
  2469. return last->stackInc;
  2470. }
  2471. int asCByteCode::InstrPTR(asEBCInstr bc, void *param)
  2472. {
  2473. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2474. if( AddInstruction() < 0 )
  2475. return 0;
  2476. last->op = bc;
  2477. asASSERT(asBCInfo[bc].type == asBCTYPE_PTR_ARG);
  2478. *ARG_PTR(last->arg) = (asPWORD)param;
  2479. last->size = asBCTypeSize[asBCInfo[bc].type];
  2480. last->stackInc = asBCInfo[bc].stackInc;
  2481. return last->stackInc;
  2482. }
  2483. int asCByteCode::InstrQWORD(asEBCInstr bc, asQWORD param)
  2484. {
  2485. asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
  2486. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2487. if( AddInstruction() < 0 )
  2488. return 0;
  2489. last->op = bc;
  2490. *ARG_QW(last->arg) = param;
  2491. last->size = asBCTypeSize[asBCInfo[bc].type];
  2492. last->stackInc = asBCInfo[bc].stackInc;
  2493. return last->stackInc;
  2494. }
  2495. int asCByteCode::InstrWORD(asEBCInstr bc, asWORD param)
  2496. {
  2497. asASSERT(asBCInfo[bc].type == asBCTYPE_W_ARG ||
  2498. asBCInfo[bc].type == asBCTYPE_rW_ARG ||
  2499. asBCInfo[bc].type == asBCTYPE_wW_ARG);
  2500. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2501. if( AddInstruction() < 0 )
  2502. return 0;
  2503. last->op = bc;
  2504. last->wArg[0] = param;
  2505. last->size = asBCTypeSize[asBCInfo[bc].type];
  2506. last->stackInc = asBCInfo[bc].stackInc;
  2507. return last->stackInc;
  2508. }
  2509. int asCByteCode::InstrFLOAT(asEBCInstr bc, float param)
  2510. {
  2511. asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
  2512. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2513. if( AddInstruction() < 0 )
  2514. return 0;
  2515. last->op = bc;
  2516. *((float*) ARG_DW(last->arg)) = param;
  2517. last->size = asBCTypeSize[asBCInfo[bc].type];
  2518. last->stackInc = asBCInfo[bc].stackInc;
  2519. return last->stackInc;
  2520. }
  2521. int asCByteCode::InstrDOUBLE(asEBCInstr bc, double param)
  2522. {
  2523. asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG);
  2524. asASSERT(asBCInfo[bc].stackInc != 0xFFFF);
  2525. if( AddInstruction() < 0 )
  2526. return 0;
  2527. last->op = bc;
  2528. *((double*) ARG_QW(last->arg)) = param;
  2529. last->size = asBCTypeSize[asBCInfo[bc].type];
  2530. last->stackInc = asBCInfo[bc].stackInc;
  2531. return last->stackInc;
  2532. }
  2533. int asCByteCode::GetLastInstr()
  2534. {
  2535. if( last == 0 ) return -1;
  2536. return last->op;
  2537. }
  2538. int asCByteCode::RemoveLastInstr()
  2539. {
  2540. if( last == 0 ) return -1;
  2541. if( first == last )
  2542. {
  2543. engine->memoryMgr.FreeByteInstruction(last);
  2544. first = 0;
  2545. last = 0;
  2546. }
  2547. else
  2548. {
  2549. asCByteInstruction *bc = last;
  2550. last = bc->prev;
  2551. bc->Remove();
  2552. engine->memoryMgr.FreeByteInstruction(bc);
  2553. }
  2554. return 0;
  2555. }
  2556. asDWORD asCByteCode::GetLastInstrValueDW()
  2557. {
  2558. if( last == 0 ) return 0;
  2559. return *ARG_DW(last->arg);
  2560. }
  2561. //===================================================================
  2562. asCByteInstruction::asCByteInstruction()
  2563. {
  2564. next = 0;
  2565. prev = 0;
  2566. op = asBC_LABEL;
  2567. arg = 0;
  2568. wArg[0] = 0;
  2569. wArg[1] = 0;
  2570. wArg[2] = 0;
  2571. size = 0;
  2572. stackInc = 0;
  2573. marked = false;
  2574. stackSize = 0;
  2575. }
  2576. void asCByteInstruction::AddAfter(asCByteInstruction *nextCode)
  2577. {
  2578. if( next )
  2579. next->prev = nextCode;
  2580. nextCode->next = next;
  2581. nextCode->prev = this;
  2582. next = nextCode;
  2583. }
  2584. void asCByteInstruction::AddBefore(asCByteInstruction *prevCode)
  2585. {
  2586. if( prev )
  2587. prev->next = prevCode;
  2588. prevCode->prev = prev;
  2589. prevCode->next = this;
  2590. prev = prevCode;
  2591. }
  2592. int asCByteInstruction::GetSize()
  2593. {
  2594. return size;
  2595. }
  2596. int asCByteInstruction::GetStackIncrease()
  2597. {
  2598. return stackInc;
  2599. }
  2600. void asCByteInstruction::Remove()
  2601. {
  2602. if( prev ) prev->next = next;
  2603. if( next ) next->prev = prev;
  2604. prev = 0;
  2605. next = 0;
  2606. }
  2607. END_AS_NAMESPACE
  2608. #endif // AS_NO_COMPILER