as_context.cpp 135 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2013 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. [email protected]
  22. */
  23. //
  24. // as_context.cpp
  25. //
  26. // This class handles the execution of the byte code
  27. //
  28. #include <math.h> // fmodf()
  29. #include "as_config.h"
  30. #include "as_context.h"
  31. #include "as_scriptengine.h"
  32. #include "as_tokendef.h"
  33. #include "as_texts.h"
  34. #include "as_callfunc.h"
  35. #include "as_generic.h"
  36. #include "as_debug.h" // mkdir()
  37. #include "as_bytecode.h"
  38. #include "as_scriptobject.h"
  39. #ifdef _MSC_VER
  40. #pragma warning(disable:4702) // unreachable code
  41. #endif
  42. BEGIN_AS_NAMESPACE
  43. // We need at least 2 PTRs reserved for exception handling
  44. // We need at least 1 PTR reserved for calling system functions
  45. const int RESERVE_STACK = 2*AS_PTR_SIZE;
  46. // For each script function call we push 9 PTRs on the call stack
  47. const int CALLSTACK_FRAME_SIZE = 9;
  48. #if defined(AS_DEBUG)
  49. class asCDebugStats
  50. {
  51. public:
  52. asCDebugStats()
  53. {
  54. memset(instrCount, 0, sizeof(instrCount));
  55. memset(instrCount2, 0, sizeof(instrCount2));
  56. lastBC = 255;
  57. }
  58. ~asCDebugStats()
  59. {
  60. // This code writes out some statistics for the VM.
  61. // It's useful for determining what needs to be optimized.
  62. _mkdir("AS_DEBUG");
  63. #if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
  64. FILE *f;
  65. fopen_s(&f, "AS_DEBUG/stats.txt", "wt");
  66. #else
  67. FILE *f = fopen("AS_DEBUG/stats.txt", "wt");
  68. #endif
  69. if( f )
  70. {
  71. // Output instruction statistics
  72. fprintf(f, "\nTotal count\n");
  73. int n;
  74. for( n = 0; n < asBC_MAXBYTECODE; n++ )
  75. {
  76. if( asBCInfo[n].name && instrCount[n] > 0 )
  77. fprintf(f, "%-10.10s : %.0f\n", asBCInfo[n].name, instrCount[n]);
  78. }
  79. fprintf(f, "\nNever executed\n");
  80. for( n = 0; n < asBC_MAXBYTECODE; n++ )
  81. {
  82. if( asBCInfo[n].name && instrCount[n] == 0 )
  83. fprintf(f, "%-10.10s\n", asBCInfo[n].name);
  84. }
  85. fprintf(f, "\nSequences\n");
  86. for( n = 0; n < 256; n++ )
  87. {
  88. if( asBCInfo[n].name )
  89. {
  90. for( int m = 0; m < 256; m++ )
  91. {
  92. if( instrCount2[n][m] )
  93. fprintf(f, "%-10.10s, %-10.10s : %.0f\n", asBCInfo[n].name, asBCInfo[m].name, instrCount2[n][m]);
  94. }
  95. }
  96. }
  97. fclose(f);
  98. }
  99. }
  100. void Instr(asBYTE bc)
  101. {
  102. ++instrCount[bc];
  103. ++instrCount2[lastBC][bc];
  104. lastBC = bc;
  105. }
  106. // Instruction statistics
  107. double instrCount[256];
  108. double instrCount2[256][256];
  109. int lastBC;
  110. } stats;
  111. #endif
  112. AS_API asIScriptContext *asGetActiveContext()
  113. {
  114. asCThreadLocalData *tld = asCThreadManager::GetLocalData();
  115. if( tld->activeContexts.GetLength() == 0 )
  116. return 0;
  117. return tld->activeContexts[tld->activeContexts.GetLength()-1];
  118. }
  119. asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx)
  120. {
  121. asCThreadLocalData *tld = asCThreadManager::GetLocalData();
  122. tld->activeContexts.PushLast(ctx);
  123. return tld;
  124. }
  125. asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
  126. {
  127. m_refCount.set(1);
  128. m_holdEngineRef = holdRef;
  129. if( holdRef )
  130. engine->AddRef();
  131. m_engine = engine;
  132. m_status = asEXECUTION_UNINITIALIZED;
  133. m_stackBlockSize = 0;
  134. m_originalStackPointer = 0;
  135. m_inExceptionHandler = false;
  136. m_isStackMemoryNotAllocated = false;
  137. m_needToCleanupArgs = false;
  138. m_currentFunction = 0;
  139. m_callingSystemFunction = 0;
  140. m_regs.objectRegister = 0;
  141. m_initialFunction = 0;
  142. m_lineCallback = false;
  143. m_exceptionCallback = false;
  144. m_regs.doProcessSuspend = false;
  145. m_doSuspend = false;
  146. m_userData = 0;
  147. m_regs.ctx = this;
  148. }
  149. asCContext::~asCContext()
  150. {
  151. DetachEngine();
  152. }
  153. // interface
  154. bool asCContext::IsNested(asUINT *nestCount) const
  155. {
  156. if( nestCount )
  157. *nestCount = 0;
  158. asUINT c = GetCallstackSize();
  159. if( c == 0 )
  160. return false;
  161. // Search for a marker on the call stack
  162. // This loop starts at 2 because the 0th entry is not stored in m_callStack,
  163. // and then we need to subtract one more to get the base of each frame
  164. for( asUINT n = 2; n <= c; n++ )
  165. {
  166. const asPWORD *s = m_callStack.AddressOf() + (c - n)*CALLSTACK_FRAME_SIZE;
  167. if( s && s[0] == 0 )
  168. {
  169. if( nestCount )
  170. (*nestCount)++;
  171. else
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. // interface
  178. int asCContext::AddRef() const
  179. {
  180. return m_refCount.atomicInc();
  181. }
  182. // interface
  183. int asCContext::Release() const
  184. {
  185. int r = m_refCount.atomicDec();
  186. if( r == 0 )
  187. {
  188. asDELETE(const_cast<asCContext*>(this),asCContext);
  189. return 0;
  190. }
  191. return r;
  192. }
  193. // internal
  194. void asCContext::DetachEngine()
  195. {
  196. if( m_engine == 0 ) return;
  197. // Clean up all calls, included nested ones
  198. do
  199. {
  200. // Abort any execution
  201. Abort();
  202. // Free all resources
  203. Unprepare();
  204. }
  205. while( IsNested() );
  206. // Free the stack blocks
  207. for( asUINT n = 0; n < m_stackBlocks.GetLength(); n++ )
  208. {
  209. if( m_stackBlocks[n] )
  210. {
  211. asDELETEARRAY(m_stackBlocks[n]);
  212. }
  213. }
  214. m_stackBlocks.SetLength(0);
  215. m_stackBlockSize = 0;
  216. // Clean the user data
  217. if( m_userData && m_engine->cleanContextFunc )
  218. m_engine->cleanContextFunc(this);
  219. // Clear engine pointer
  220. if( m_holdEngineRef )
  221. m_engine->Release();
  222. m_engine = 0;
  223. }
  224. // interface
  225. asIScriptEngine *asCContext::GetEngine() const
  226. {
  227. return m_engine;
  228. }
  229. // interface
  230. void *asCContext::SetUserData(void *data)
  231. {
  232. void *oldData = m_userData;
  233. m_userData = data;
  234. return oldData;
  235. }
  236. // interface
  237. void *asCContext::GetUserData() const
  238. {
  239. return m_userData;
  240. }
  241. // interface
  242. asIScriptFunction *asCContext::GetSystemFunction()
  243. {
  244. return m_callingSystemFunction;
  245. }
  246. // interface
  247. int asCContext::Prepare(asIScriptFunction *func)
  248. {
  249. if( func == 0 )
  250. {
  251. asCString str;
  252. str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", "null", asNO_FUNCTION);
  253. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  254. return asNO_FUNCTION;
  255. }
  256. if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
  257. {
  258. asCString str;
  259. str.Format(TXT_FAILED_IN_FUNC_s_d, "Prepare", asCONTEXT_ACTIVE);
  260. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  261. return asCONTEXT_ACTIVE;
  262. }
  263. // Clean the stack if not done before
  264. if( m_status != asEXECUTION_FINISHED && m_status != asEXECUTION_UNINITIALIZED )
  265. CleanStack();
  266. // Release the returned object (if any)
  267. CleanReturnObject();
  268. if( m_initialFunction && m_initialFunction == func )
  269. {
  270. // If the same function is executed again, we can skip a lot of the setup
  271. m_currentFunction = m_initialFunction;
  272. // Reset stack pointer
  273. m_regs.stackPointer = m_originalStackPointer;
  274. // Make sure the stack pointer is pointing to the original position,
  275. // otherwise something is wrong with the way it is being updated
  276. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  277. }
  278. else
  279. {
  280. asASSERT( m_engine );
  281. if( m_initialFunction )
  282. {
  283. m_initialFunction->Release();
  284. // Reset stack pointer
  285. m_regs.stackPointer = m_originalStackPointer;
  286. // Make sure the stack pointer is pointing to the original position,
  287. // otherwise something is wrong with the way it is being updated
  288. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  289. }
  290. // We trust the application not to pass anything else but a asCScriptFunction
  291. m_initialFunction = reinterpret_cast<asCScriptFunction *>(func);
  292. m_initialFunction->AddRef();
  293. m_currentFunction = m_initialFunction;
  294. // TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed
  295. m_argumentsSize = m_currentFunction->GetSpaceNeededForArguments() + (m_currentFunction->objectType ? AS_PTR_SIZE : 0);
  296. // Reserve space for the arguments and return value
  297. if( m_currentFunction->DoesReturnOnStack() )
  298. {
  299. m_returnValueSize = m_currentFunction->returnType.GetSizeInMemoryDWords();
  300. m_argumentsSize += AS_PTR_SIZE;
  301. }
  302. else
  303. m_returnValueSize = 0;
  304. // Determine the minimum stack size needed
  305. int stackSize = m_argumentsSize + m_returnValueSize + m_currentFunction->stackNeeded;
  306. // Make sure there is enough space on the stack for the arguments and return value
  307. if( !ReserveStackSpace(stackSize) )
  308. return asOUT_OF_MEMORY;
  309. }
  310. // Reset state
  311. // Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized
  312. if( m_status != asEXECUTION_FINISHED )
  313. {
  314. m_exceptionLine = -1;
  315. m_exceptionFunction = 0;
  316. m_doAbort = false;
  317. m_doSuspend = false;
  318. m_regs.doProcessSuspend = m_lineCallback;
  319. m_externalSuspendRequest = false;
  320. }
  321. m_status = asEXECUTION_PREPARED;
  322. m_regs.programPointer = 0;
  323. // Reserve space for the arguments and return value
  324. m_regs.stackFramePointer = m_regs.stackPointer - m_argumentsSize - m_returnValueSize;
  325. m_originalStackPointer = m_regs.stackPointer;
  326. m_regs.stackPointer = m_regs.stackFramePointer;
  327. // Set arguments to 0
  328. memset(m_regs.stackPointer, 0, 4*m_argumentsSize);
  329. if( m_returnValueSize )
  330. {
  331. // Set the address of the location where the return value should be put
  332. asDWORD *ptr = m_regs.stackFramePointer;
  333. if( m_currentFunction->objectType )
  334. ptr += AS_PTR_SIZE;
  335. *(void**)ptr = (void*)(m_regs.stackFramePointer + m_argumentsSize);
  336. }
  337. return asSUCCESS;
  338. }
  339. // Free all resources
  340. int asCContext::Unprepare()
  341. {
  342. if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
  343. return asCONTEXT_ACTIVE;
  344. // Only clean the stack if the context was prepared but not executed until the end
  345. if( m_status != asEXECUTION_UNINITIALIZED &&
  346. m_status != asEXECUTION_FINISHED )
  347. CleanStack();
  348. asASSERT( m_needToCleanupArgs == false );
  349. // Release the returned object (if any)
  350. CleanReturnObject();
  351. // Release the initial function
  352. if( m_initialFunction )
  353. {
  354. m_initialFunction->Release();
  355. // Reset stack pointer
  356. m_regs.stackPointer = m_originalStackPointer;
  357. // Make sure the stack pointer is pointing to the original position,
  358. // otherwise something is wrong with the way it is being updated
  359. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  360. }
  361. // Clear function pointers
  362. m_initialFunction = 0;
  363. m_currentFunction = 0;
  364. m_exceptionFunction = 0;
  365. m_regs.programPointer = 0;
  366. // Reset status
  367. m_status = asEXECUTION_UNINITIALIZED;
  368. m_regs.stackFramePointer = 0;
  369. return 0;
  370. }
  371. asBYTE asCContext::GetReturnByte()
  372. {
  373. if( m_status != asEXECUTION_FINISHED ) return 0;
  374. asCDataType *dt = &m_initialFunction->returnType;
  375. if( dt->IsObject() || dt->IsReference() ) return 0;
  376. return *(asBYTE*)&m_regs.valueRegister;
  377. }
  378. asWORD asCContext::GetReturnWord()
  379. {
  380. if( m_status != asEXECUTION_FINISHED ) return 0;
  381. asCDataType *dt = &m_initialFunction->returnType;
  382. if( dt->IsObject() || dt->IsReference() ) return 0;
  383. return *(asWORD*)&m_regs.valueRegister;
  384. }
  385. asDWORD asCContext::GetReturnDWord()
  386. {
  387. if( m_status != asEXECUTION_FINISHED ) return 0;
  388. asCDataType *dt = &m_initialFunction->returnType;
  389. if( dt->IsObject() || dt->IsReference() ) return 0;
  390. return *(asDWORD*)&m_regs.valueRegister;
  391. }
  392. asQWORD asCContext::GetReturnQWord()
  393. {
  394. if( m_status != asEXECUTION_FINISHED ) return 0;
  395. asCDataType *dt = &m_initialFunction->returnType;
  396. if( dt->IsObject() || dt->IsReference() ) return 0;
  397. return m_regs.valueRegister;
  398. }
  399. float asCContext::GetReturnFloat()
  400. {
  401. if( m_status != asEXECUTION_FINISHED ) return 0;
  402. asCDataType *dt = &m_initialFunction->returnType;
  403. if( dt->IsObject() || dt->IsReference() ) return 0;
  404. return *(float*)&m_regs.valueRegister;
  405. }
  406. double asCContext::GetReturnDouble()
  407. {
  408. if( m_status != asEXECUTION_FINISHED ) return 0;
  409. asCDataType *dt = &m_initialFunction->returnType;
  410. if( dt->IsObject() || dt->IsReference() ) return 0;
  411. return *(double*)&m_regs.valueRegister;
  412. }
  413. void *asCContext::GetReturnAddress()
  414. {
  415. if( m_status != asEXECUTION_FINISHED ) return 0;
  416. asCDataType *dt = &m_initialFunction->returnType;
  417. if( dt->IsReference() )
  418. return *(void**)&m_regs.valueRegister;
  419. else if( dt->IsObject() )
  420. {
  421. if( m_initialFunction->DoesReturnOnStack() )
  422. {
  423. // The address of the return value was passed as the first argument, after the object pointer
  424. int offset = 0;
  425. if( m_initialFunction->objectType )
  426. offset += AS_PTR_SIZE;
  427. return *(void**)(&m_regs.stackFramePointer[offset]);
  428. }
  429. return m_regs.objectRegister;
  430. }
  431. return 0;
  432. }
  433. void *asCContext::GetReturnObject()
  434. {
  435. if( m_status != asEXECUTION_FINISHED ) return 0;
  436. asCDataType *dt = &m_initialFunction->returnType;
  437. if( !dt->IsObject() ) return 0;
  438. if( dt->IsReference() )
  439. return *(void**)(asPWORD)m_regs.valueRegister;
  440. else
  441. {
  442. if( m_initialFunction->DoesReturnOnStack() )
  443. {
  444. // The address of the return value was passed as the first argument, after the object pointer
  445. int offset = 0;
  446. if( m_initialFunction->objectType )
  447. offset += AS_PTR_SIZE;
  448. return *(void**)(&m_regs.stackFramePointer[offset]);
  449. }
  450. return m_regs.objectRegister;
  451. }
  452. }
  453. void *asCContext::GetAddressOfReturnValue()
  454. {
  455. if( m_status != asEXECUTION_FINISHED ) return 0;
  456. asCDataType *dt = &m_initialFunction->returnType;
  457. // An object is stored in the objectRegister
  458. if( !dt->IsReference() && dt->IsObject() )
  459. {
  460. // Need to dereference objects
  461. if( !dt->IsObjectHandle() )
  462. {
  463. if( m_initialFunction->DoesReturnOnStack() )
  464. {
  465. // The address of the return value was passed as the first argument, after the object pointer
  466. int offset = 0;
  467. if( m_initialFunction->objectType )
  468. offset += AS_PTR_SIZE;
  469. return *(void**)(&m_regs.stackFramePointer[offset]);
  470. }
  471. return *(void**)&m_regs.objectRegister;
  472. }
  473. return &m_regs.objectRegister;
  474. }
  475. // Primitives and references are stored in valueRegister
  476. return &m_regs.valueRegister;
  477. }
  478. int asCContext::SetObject(void *obj)
  479. {
  480. if( m_status != asEXECUTION_PREPARED )
  481. return asCONTEXT_NOT_PREPARED;
  482. if( !m_initialFunction->objectType )
  483. {
  484. m_status = asEXECUTION_ERROR;
  485. return asERROR;
  486. }
  487. *(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj;
  488. return 0;
  489. }
  490. int asCContext::SetArgByte(asUINT arg, asBYTE value)
  491. {
  492. if( m_status != asEXECUTION_PREPARED )
  493. return asCONTEXT_NOT_PREPARED;
  494. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  495. {
  496. m_status = asEXECUTION_ERROR;
  497. return asINVALID_ARG;
  498. }
  499. // Verify the type of the argument
  500. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  501. if( dt->IsObject() || dt->IsReference() )
  502. {
  503. m_status = asEXECUTION_ERROR;
  504. return asINVALID_TYPE;
  505. }
  506. if( dt->GetSizeInMemoryBytes() != 1 )
  507. {
  508. m_status = asEXECUTION_ERROR;
  509. return asINVALID_TYPE;
  510. }
  511. // Determine the position of the argument
  512. int offset = 0;
  513. if( m_initialFunction->objectType )
  514. offset += AS_PTR_SIZE;
  515. // If function returns object by value an extra pointer is pushed on the stack
  516. if( m_returnValueSize )
  517. offset += AS_PTR_SIZE;
  518. for( asUINT n = 0; n < arg; n++ )
  519. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  520. // Set the value
  521. *(asBYTE*)&m_regs.stackFramePointer[offset] = value;
  522. return 0;
  523. }
  524. int asCContext::SetArgWord(asUINT arg, asWORD value)
  525. {
  526. if( m_status != asEXECUTION_PREPARED )
  527. return asCONTEXT_NOT_PREPARED;
  528. if( arg >= m_initialFunction->parameterTypes.GetLength() )
  529. {
  530. m_status = asEXECUTION_ERROR;
  531. return asINVALID_ARG;
  532. }
  533. // Verify the type of the argument
  534. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  535. if( dt->IsObject() || dt->IsReference() )
  536. {
  537. m_status = asEXECUTION_ERROR;
  538. return asINVALID_TYPE;
  539. }
  540. if( dt->GetSizeInMemoryBytes() != 2 )
  541. {
  542. m_status = asEXECUTION_ERROR;
  543. return asINVALID_TYPE;
  544. }
  545. // Determine the position of the argument
  546. int offset = 0;
  547. if( m_initialFunction->objectType )
  548. offset += AS_PTR_SIZE;
  549. // If function returns object by value an extra pointer is pushed on the stack
  550. if( m_returnValueSize )
  551. offset += AS_PTR_SIZE;
  552. for( asUINT n = 0; n < arg; n++ )
  553. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  554. // Set the value
  555. *(asWORD*)&m_regs.stackFramePointer[offset] = value;
  556. return 0;
  557. }
  558. int asCContext::SetArgDWord(asUINT arg, asDWORD value)
  559. {
  560. if( m_status != asEXECUTION_PREPARED )
  561. return asCONTEXT_NOT_PREPARED;
  562. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  563. {
  564. m_status = asEXECUTION_ERROR;
  565. return asINVALID_ARG;
  566. }
  567. // Verify the type of the argument
  568. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  569. if( dt->IsObject() || dt->IsReference() )
  570. {
  571. m_status = asEXECUTION_ERROR;
  572. return asINVALID_TYPE;
  573. }
  574. if( dt->GetSizeInMemoryBytes() != 4 )
  575. {
  576. m_status = asEXECUTION_ERROR;
  577. return asINVALID_TYPE;
  578. }
  579. // Determine the position of the argument
  580. int offset = 0;
  581. if( m_initialFunction->objectType )
  582. offset += AS_PTR_SIZE;
  583. // If function returns object by value an extra pointer is pushed on the stack
  584. if( m_returnValueSize )
  585. offset += AS_PTR_SIZE;
  586. for( asUINT n = 0; n < arg; n++ )
  587. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  588. // Set the value
  589. *(asDWORD*)&m_regs.stackFramePointer[offset] = value;
  590. return 0;
  591. }
  592. int asCContext::SetArgQWord(asUINT arg, asQWORD value)
  593. {
  594. if( m_status != asEXECUTION_PREPARED )
  595. return asCONTEXT_NOT_PREPARED;
  596. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  597. {
  598. m_status = asEXECUTION_ERROR;
  599. return asINVALID_ARG;
  600. }
  601. // Verify the type of the argument
  602. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  603. if( dt->IsObject() || dt->IsReference() )
  604. {
  605. m_status = asEXECUTION_ERROR;
  606. return asINVALID_TYPE;
  607. }
  608. if( dt->GetSizeOnStackDWords() != 2 )
  609. {
  610. m_status = asEXECUTION_ERROR;
  611. return asINVALID_TYPE;
  612. }
  613. // Determine the position of the argument
  614. int offset = 0;
  615. if( m_initialFunction->objectType )
  616. offset += AS_PTR_SIZE;
  617. // If function returns object by value an extra pointer is pushed on the stack
  618. if( m_returnValueSize )
  619. offset += AS_PTR_SIZE;
  620. for( asUINT n = 0; n < arg; n++ )
  621. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  622. // Set the value
  623. *(asQWORD*)(&m_regs.stackFramePointer[offset]) = value;
  624. return 0;
  625. }
  626. int asCContext::SetArgFloat(asUINT arg, float value)
  627. {
  628. if( m_status != asEXECUTION_PREPARED )
  629. return asCONTEXT_NOT_PREPARED;
  630. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  631. {
  632. m_status = asEXECUTION_ERROR;
  633. return asINVALID_ARG;
  634. }
  635. // Verify the type of the argument
  636. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  637. if( dt->IsObject() || dt->IsReference() )
  638. {
  639. m_status = asEXECUTION_ERROR;
  640. return asINVALID_TYPE;
  641. }
  642. if( dt->GetSizeOnStackDWords() != 1 )
  643. {
  644. m_status = asEXECUTION_ERROR;
  645. return asINVALID_TYPE;
  646. }
  647. // Determine the position of the argument
  648. int offset = 0;
  649. if( m_initialFunction->objectType )
  650. offset += AS_PTR_SIZE;
  651. // If function returns object by value an extra pointer is pushed on the stack
  652. if( m_returnValueSize )
  653. offset += AS_PTR_SIZE;
  654. for( asUINT n = 0; n < arg; n++ )
  655. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  656. // Set the value
  657. *(float*)(&m_regs.stackFramePointer[offset]) = value;
  658. return 0;
  659. }
  660. int asCContext::SetArgDouble(asUINT arg, double value)
  661. {
  662. if( m_status != asEXECUTION_PREPARED )
  663. return asCONTEXT_NOT_PREPARED;
  664. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  665. {
  666. m_status = asEXECUTION_ERROR;
  667. return asINVALID_ARG;
  668. }
  669. // Verify the type of the argument
  670. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  671. if( dt->IsObject() || dt->IsReference() )
  672. {
  673. m_status = asEXECUTION_ERROR;
  674. return asINVALID_TYPE;
  675. }
  676. if( dt->GetSizeOnStackDWords() != 2 )
  677. {
  678. m_status = asEXECUTION_ERROR;
  679. return asINVALID_TYPE;
  680. }
  681. // Determine the position of the argument
  682. int offset = 0;
  683. if( m_initialFunction->objectType )
  684. offset += AS_PTR_SIZE;
  685. // If function returns object by value an extra pointer is pushed on the stack
  686. if( m_returnValueSize )
  687. offset += AS_PTR_SIZE;
  688. for( asUINT n = 0; n < arg; n++ )
  689. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  690. // Set the value
  691. *(double*)(&m_regs.stackFramePointer[offset]) = value;
  692. return 0;
  693. }
  694. int asCContext::SetArgAddress(asUINT arg, void *value)
  695. {
  696. if( m_status != asEXECUTION_PREPARED )
  697. return asCONTEXT_NOT_PREPARED;
  698. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  699. {
  700. m_status = asEXECUTION_ERROR;
  701. return asINVALID_ARG;
  702. }
  703. // Verify the type of the argument
  704. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  705. if( !dt->IsReference() && !dt->IsObjectHandle() )
  706. {
  707. m_status = asEXECUTION_ERROR;
  708. return asINVALID_TYPE;
  709. }
  710. // Determine the position of the argument
  711. int offset = 0;
  712. if( m_initialFunction->objectType )
  713. offset += AS_PTR_SIZE;
  714. // If function returns object by value an extra pointer is pushed on the stack
  715. if( m_returnValueSize )
  716. offset += AS_PTR_SIZE;
  717. for( asUINT n = 0; n < arg; n++ )
  718. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  719. // Set the value
  720. *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)value;
  721. return 0;
  722. }
  723. int asCContext::SetArgObject(asUINT arg, void *obj)
  724. {
  725. if( m_status != asEXECUTION_PREPARED )
  726. return asCONTEXT_NOT_PREPARED;
  727. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  728. {
  729. m_status = asEXECUTION_ERROR;
  730. return asINVALID_ARG;
  731. }
  732. // Verify the type of the argument
  733. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  734. if( !dt->IsObject() )
  735. {
  736. m_status = asEXECUTION_ERROR;
  737. return asINVALID_TYPE;
  738. }
  739. // If the object should be sent by value we must make a copy of it
  740. if( !dt->IsReference() )
  741. {
  742. if( dt->IsObjectHandle() )
  743. {
  744. // Increase the reference counter
  745. asSTypeBehaviour *beh = &dt->GetObjectType()->beh;
  746. if( obj && beh->addref )
  747. m_engine->CallObjectMethod(obj, beh->addref);
  748. }
  749. else
  750. {
  751. obj = m_engine->CreateScriptObjectCopy(obj, dt->GetObjectType());
  752. }
  753. }
  754. // Determine the position of the argument
  755. int offset = 0;
  756. if( m_initialFunction->objectType )
  757. offset += AS_PTR_SIZE;
  758. // If function returns object by value an extra pointer is pushed on the stack
  759. if( m_returnValueSize )
  760. offset += AS_PTR_SIZE;
  761. for( asUINT n = 0; n < arg; n++ )
  762. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  763. // Set the value
  764. *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)obj;
  765. return 0;
  766. }
  767. // TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
  768. // interface
  769. void *asCContext::GetAddressOfArg(asUINT arg)
  770. {
  771. if( m_status != asEXECUTION_PREPARED )
  772. return 0;
  773. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  774. return 0;
  775. // Determine the position of the argument
  776. int offset = 0;
  777. if( m_initialFunction->objectType )
  778. offset += AS_PTR_SIZE;
  779. // If function returns object by value an extra pointer is pushed on the stack
  780. if( m_returnValueSize )
  781. offset += AS_PTR_SIZE;
  782. for( asUINT n = 0; n < arg; n++ )
  783. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  784. // We should return the address of the location where the argument value will be placed
  785. // All registered types are always sent by reference, even if
  786. // the function is declared to receive the argument by value.
  787. return &m_regs.stackFramePointer[offset];
  788. }
  789. int asCContext::Abort()
  790. {
  791. if( m_engine == 0 ) return asERROR;
  792. // TODO: multithread: Make thread safe. There is a chance that the status
  793. // changes to something else after being set to ABORTED here.
  794. if( m_status == asEXECUTION_SUSPENDED )
  795. m_status = asEXECUTION_ABORTED;
  796. m_doSuspend = true;
  797. m_regs.doProcessSuspend = true;
  798. m_externalSuspendRequest = true;
  799. m_doAbort = true;
  800. return 0;
  801. }
  802. // interface
  803. int asCContext::Suspend()
  804. {
  805. // This function just sets some internal flags and is safe
  806. // to call from a secondary thread, even if the library has
  807. // been built without multi-thread support.
  808. if( m_engine == 0 ) return asERROR;
  809. m_doSuspend = true;
  810. m_externalSuspendRequest = true;
  811. m_regs.doProcessSuspend = true;
  812. return 0;
  813. }
  814. // interface
  815. int asCContext::Execute()
  816. {
  817. asASSERT( m_engine != 0 );
  818. if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED )
  819. {
  820. asCString str;
  821. str.Format(TXT_FAILED_IN_FUNC_s_d, "Execute", asCONTEXT_NOT_PREPARED);
  822. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  823. return asCONTEXT_NOT_PREPARED;
  824. }
  825. m_status = asEXECUTION_ACTIVE;
  826. asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this);
  827. if( m_regs.programPointer == 0 )
  828. {
  829. if( m_currentFunction->funcType == asFUNC_DELEGATE )
  830. {
  831. // Push the object pointer onto the stack
  832. asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
  833. m_regs.stackPointer -= AS_PTR_SIZE;
  834. m_regs.stackFramePointer -= AS_PTR_SIZE;
  835. *(asPWORD*)m_regs.stackPointer = asPWORD(m_currentFunction->objForDelegate);
  836. // Make the call to the delegated object method
  837. m_currentFunction = m_currentFunction->funcForDelegate;
  838. }
  839. if( m_currentFunction->funcType == asFUNC_VIRTUAL ||
  840. m_currentFunction->funcType == asFUNC_INTERFACE )
  841. {
  842. // The currentFunction is a virtual method
  843. // Determine the true function from the object
  844. asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackFramePointer;
  845. if( obj == 0 )
  846. {
  847. SetInternalException(TXT_NULL_POINTER_ACCESS);
  848. }
  849. else
  850. {
  851. asCObjectType *objType = obj->objType;
  852. asCScriptFunction *realFunc = 0;
  853. if( m_currentFunction->funcType == asFUNC_VIRTUAL )
  854. {
  855. if( objType->virtualFunctionTable.GetLength() > (asUINT)m_currentFunction->vfTableIdx )
  856. {
  857. realFunc = objType->virtualFunctionTable[m_currentFunction->vfTableIdx];
  858. }
  859. }
  860. else
  861. {
  862. // Search the object type for a function that matches the interface function
  863. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  864. {
  865. asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]];
  866. if( f2->signatureId == m_currentFunction->signatureId )
  867. {
  868. if( f2->funcType == asFUNC_VIRTUAL )
  869. realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
  870. else
  871. realFunc = f2;
  872. break;
  873. }
  874. }
  875. }
  876. if( realFunc )
  877. {
  878. if( realFunc->signatureId != m_currentFunction->signatureId )
  879. SetInternalException(TXT_NULL_POINTER_ACCESS);
  880. else
  881. m_currentFunction = realFunc;
  882. }
  883. }
  884. }
  885. if( m_currentFunction->funcType == asFUNC_SCRIPT )
  886. {
  887. m_regs.programPointer = m_currentFunction->byteCode.AddressOf();
  888. // Set up the internal registers for executing the script function
  889. PrepareScriptFunction();
  890. }
  891. else if( m_currentFunction->funcType == asFUNC_SYSTEM )
  892. {
  893. // The current function is an application registered function
  894. // Call the function directly
  895. CallSystemFunction(m_currentFunction->id, this, 0);
  896. // Was the call successful?
  897. if( m_status == asEXECUTION_ACTIVE )
  898. {
  899. m_status = asEXECUTION_FINISHED;
  900. }
  901. }
  902. else
  903. {
  904. // This shouldn't happen
  905. asASSERT(false);
  906. }
  907. }
  908. asUINT gcPreObjects = 0;
  909. if( m_engine->ep.autoGarbageCollect )
  910. m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0);
  911. while( m_status == asEXECUTION_ACTIVE )
  912. ExecuteNext();
  913. if( m_lineCallback )
  914. {
  915. // Call the line callback one last time before leaving
  916. // so anyone listening can catch the state change
  917. CallLineCallback();
  918. m_regs.doProcessSuspend = true;
  919. }
  920. else
  921. m_regs.doProcessSuspend = false;
  922. m_doSuspend = false;
  923. if( m_engine->ep.autoGarbageCollect )
  924. {
  925. asUINT gcPosObjects = 0;
  926. m_engine->gc.GetStatistics(&gcPosObjects, 0, 0, 0, 0);
  927. if( gcPosObjects > gcPreObjects )
  928. {
  929. // Execute as many steps as there were new objects created
  930. while( gcPosObjects-- > gcPreObjects )
  931. m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE);
  932. }
  933. else if( gcPosObjects > 0 )
  934. {
  935. // Execute at least one step, even if no new objects were created
  936. m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE);
  937. }
  938. }
  939. // Pop the active context
  940. asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == this);
  941. tld->activeContexts.PopLast();
  942. if( m_status == asEXECUTION_FINISHED )
  943. {
  944. m_regs.objectType = m_initialFunction->returnType.GetObjectType();
  945. return asEXECUTION_FINISHED;
  946. }
  947. if( m_doAbort )
  948. {
  949. m_doAbort = false;
  950. m_status = asEXECUTION_ABORTED;
  951. return asEXECUTION_ABORTED;
  952. }
  953. if( m_status == asEXECUTION_SUSPENDED )
  954. return asEXECUTION_SUSPENDED;
  955. if( m_status == asEXECUTION_EXCEPTION )
  956. return asEXECUTION_EXCEPTION;
  957. return asERROR;
  958. }
  959. int asCContext::PushState()
  960. {
  961. // Only allow the state to be pushed when active
  962. // TODO: Can we support a suspended state too? So the reuse of
  963. // the context can be done outside the Execute() call?
  964. if( m_status != asEXECUTION_ACTIVE )
  965. {
  966. // TODO: Write message. Wrong usage
  967. return asERROR;
  968. }
  969. // Push the current script function that is calling the system function
  970. PushCallState();
  971. // Push the system function too, which will serve both as a marker and
  972. // informing which system function that created the nested call
  973. if( m_callStack.GetLength() == m_callStack.GetCapacity() )
  974. {
  975. // Allocate space for 10 call states at a time to save time
  976. m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
  977. }
  978. m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
  979. // Need to push m_initialFunction as it must be restored later
  980. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  981. tmp[0] = 0;
  982. tmp[1] = (asPWORD)m_callingSystemFunction;
  983. tmp[2] = (asPWORD)m_initialFunction;
  984. tmp[3] = (asPWORD)m_originalStackPointer;
  985. tmp[4] = (asPWORD)m_argumentsSize;
  986. // Need to push the value of registers so they can be restored
  987. tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister);
  988. tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32);
  989. tmp[7] = (asPWORD)m_regs.objectRegister;
  990. tmp[8] = (asPWORD)m_regs.objectType;
  991. // Decrease stackpointer to prevent the top value from being overwritten
  992. m_regs.stackPointer -= 2;
  993. // Clear the initial function so that Prepare() knows it must do all validations
  994. m_initialFunction = 0;
  995. // After this the state should appear as if uninitialized
  996. m_callingSystemFunction = 0;
  997. m_regs.objectRegister = 0;
  998. m_regs.objectType = 0;
  999. // Set the status to uninitialized as application
  1000. // should call Prepare() after this to reuse the context
  1001. m_status = asEXECUTION_UNINITIALIZED;
  1002. return asSUCCESS;
  1003. }
  1004. int asCContext::PopState()
  1005. {
  1006. if( !IsNested() )
  1007. return asERROR;
  1008. // Clean up the current execution
  1009. Unprepare();
  1010. // The topmost state must be a marker for nested call
  1011. asASSERT( m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 );
  1012. // Restore the previous state
  1013. asPWORD *tmp = &m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE];
  1014. m_callingSystemFunction = reinterpret_cast<asCScriptFunction*>(tmp[1]);
  1015. m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
  1016. // Restore the previous initial function and the associated values
  1017. m_initialFunction = reinterpret_cast<asCScriptFunction*>(tmp[2]);
  1018. m_originalStackPointer = (asDWORD*)tmp[3];
  1019. m_argumentsSize = (int)tmp[4];
  1020. m_regs.valueRegister = asQWORD(asDWORD(tmp[5]));
  1021. m_regs.valueRegister |= asQWORD(tmp[6])<<32;
  1022. m_regs.objectRegister = (void*)tmp[7];
  1023. m_regs.objectType = (asIObjectType*)tmp[8];
  1024. // Calculate the returnValueSize
  1025. if( m_initialFunction->DoesReturnOnStack() )
  1026. m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords();
  1027. else
  1028. m_returnValueSize = 0;
  1029. // Pop the current script function. This will also restore the previous stack pointer
  1030. PopCallState();
  1031. m_status = asEXECUTION_ACTIVE;
  1032. return asSUCCESS;
  1033. }
  1034. void asCContext::PushCallState()
  1035. {
  1036. if( m_callStack.GetLength() == m_callStack.GetCapacity() )
  1037. {
  1038. // Allocate space for 10 call states at a time to save time
  1039. m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
  1040. }
  1041. m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
  1042. // Separating the loads and stores limits data cache trash, and with a smart compiler
  1043. // could turn into SIMD style loading/storing if available.
  1044. // The compiler can't do this itself due to potential pointer aliasing between the pointers,
  1045. // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example
  1046. // for all the compiler knows. So introducing the local variable s, which is never referred to by
  1047. // its address we avoid this issue.
  1048. asPWORD s[5];
  1049. s[0] = (asPWORD)m_regs.stackFramePointer;
  1050. s[1] = (asPWORD)m_currentFunction;
  1051. s[2] = (asPWORD)m_regs.programPointer;
  1052. s[3] = (asPWORD)m_regs.stackPointer;
  1053. s[4] = m_stackIndex;
  1054. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  1055. tmp[0] = s[0];
  1056. tmp[1] = s[1];
  1057. tmp[2] = s[2];
  1058. tmp[3] = s[3];
  1059. tmp[4] = s[4];
  1060. }
  1061. void asCContext::PopCallState()
  1062. {
  1063. // See comments in PushCallState about pointer aliasing and data cache trashing
  1064. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  1065. asPWORD s[5];
  1066. s[0] = tmp[0];
  1067. s[1] = tmp[1];
  1068. s[2] = tmp[2];
  1069. s[3] = tmp[3];
  1070. s[4] = tmp[4];
  1071. m_regs.stackFramePointer = (asDWORD*)s[0];
  1072. m_currentFunction = (asCScriptFunction*)s[1];
  1073. m_regs.programPointer = (asDWORD*)s[2];
  1074. m_regs.stackPointer = (asDWORD*)s[3];
  1075. m_stackIndex = (int)s[4];
  1076. m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
  1077. }
  1078. // interface
  1079. asUINT asCContext::GetCallstackSize() const
  1080. {
  1081. if( m_currentFunction == 0 ) return 0;
  1082. // The current function is accessed at stackLevel 0
  1083. return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE);
  1084. }
  1085. // interface
  1086. asIScriptFunction *asCContext::GetFunction(asUINT stackLevel)
  1087. {
  1088. if( stackLevel >= GetCallstackSize() ) return 0;
  1089. if( stackLevel == 0 ) return m_currentFunction;
  1090. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE;
  1091. asCScriptFunction *func = (asCScriptFunction*)s[1];
  1092. return func;
  1093. }
  1094. // interface
  1095. int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **sectionName)
  1096. {
  1097. if( stackLevel >= GetCallstackSize() ) return asINVALID_ARG;
  1098. asCScriptFunction *func;
  1099. asDWORD *bytePos;
  1100. if( stackLevel == 0 )
  1101. {
  1102. func = m_currentFunction;
  1103. bytePos = m_regs.programPointer;
  1104. }
  1105. else
  1106. {
  1107. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  1108. func = (asCScriptFunction*)s[1];
  1109. bytePos = (asDWORD*)s[2];
  1110. // Subract 1 from the bytePos, because we want the line where
  1111. // the call was made, and not the instruction after the call
  1112. bytePos -= 1;
  1113. }
  1114. // For nested calls it is possible that func is null
  1115. if( func == 0 )
  1116. {
  1117. if( column ) *column = 0;
  1118. if( sectionName ) *sectionName = 0;
  1119. return 0;
  1120. }
  1121. int sectionIdx;
  1122. asDWORD line = func->GetLineNumber(int(bytePos - func->byteCode.AddressOf()), &sectionIdx);
  1123. if( column ) *column = (line >> 20);
  1124. if( sectionName )
  1125. {
  1126. asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) );
  1127. if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() )
  1128. *sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf();
  1129. else
  1130. *sectionName = 0;
  1131. }
  1132. return (line & 0xFFFFF);
  1133. }
  1134. // internal
  1135. bool asCContext::ReserveStackSpace(asUINT size)
  1136. {
  1137. // Make sure the first stack block is allocated
  1138. if( m_stackBlocks.GetLength() == 0 )
  1139. {
  1140. m_stackBlockSize = m_engine->initialContextStackSize;
  1141. asASSERT( m_stackBlockSize > 0 );
  1142. asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize);
  1143. if( stack == 0 )
  1144. {
  1145. // Out of memory
  1146. return false;
  1147. }
  1148. m_stackBlocks.PushLast(stack);
  1149. m_stackIndex = 0;
  1150. m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize;
  1151. }
  1152. // Check if there is enough space on the current stack block, otherwise move
  1153. // to the next one. New and larger blocks will be allocated as necessary
  1154. while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] )
  1155. {
  1156. // Make sure we don't allocate more space than allowed
  1157. if( m_engine->ep.maximumContextStackSize )
  1158. {
  1159. // This test will only stop growth once it has already crossed the limit
  1160. if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) > m_engine->ep.maximumContextStackSize )
  1161. {
  1162. m_isStackMemoryNotAllocated = true;
  1163. // Set the stackFramePointer, even though the stackPointer wasn't updated
  1164. m_regs.stackFramePointer = m_regs.stackPointer;
  1165. SetInternalException(TXT_STACK_OVERFLOW);
  1166. return false;
  1167. }
  1168. }
  1169. m_stackIndex++;
  1170. if( m_stackBlocks.GetLength() == m_stackIndex )
  1171. {
  1172. // Allocate the new stack block, with twice the size of the previous
  1173. asDWORD *stack = asNEWARRAY(asDWORD,(m_stackBlockSize << m_stackIndex));
  1174. if( stack == 0 )
  1175. {
  1176. // Out of memory
  1177. m_isStackMemoryNotAllocated = true;
  1178. // Set the stackFramePointer, even though the stackPointer wasn't updated
  1179. m_regs.stackFramePointer = m_regs.stackPointer;
  1180. SetInternalException(TXT_STACK_OVERFLOW);
  1181. return false;
  1182. }
  1183. m_stackBlocks.PushLast(stack);
  1184. }
  1185. // Update the stack pointer to point to the new block.
  1186. // Leave enough room above the stackpointer to copy the arguments from the previous stackblock
  1187. m_regs.stackPointer = m_stackBlocks[m_stackIndex] +
  1188. (m_stackBlockSize<<m_stackIndex) -
  1189. m_currentFunction->GetSpaceNeededForArguments() -
  1190. (m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
  1191. (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
  1192. }
  1193. return true;
  1194. }
  1195. // internal
  1196. void asCContext::CallScriptFunction(asCScriptFunction *func)
  1197. {
  1198. // Push the framepointer, function id and programCounter on the stack
  1199. PushCallState();
  1200. // Update the current function and program position before increasing the stack
  1201. // so the exception handler will know what to do if there is a stack overflow
  1202. m_currentFunction = func;
  1203. m_regs.programPointer = m_currentFunction->byteCode.AddressOf();
  1204. // Make sure there is space on the stack to execute the function
  1205. asDWORD *oldStackPointer = m_regs.stackPointer;
  1206. if( !ReserveStackSpace(func->stackNeeded) )
  1207. return;
  1208. // If a new stack block was allocated then we'll need to move
  1209. // over the function arguments to the new block
  1210. if( m_regs.stackPointer != oldStackPointer )
  1211. {
  1212. int numDwords = func->GetSpaceNeededForArguments() + (func->objectType ? AS_PTR_SIZE : 0) + (func->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
  1213. memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
  1214. }
  1215. PrepareScriptFunction();
  1216. }
  1217. void asCContext::PrepareScriptFunction()
  1218. {
  1219. // Update framepointer
  1220. m_regs.stackFramePointer = m_regs.stackPointer;
  1221. // Set all object variables to 0 to guarantee that they are null before they are used
  1222. // Only variables on the heap should be cleared. The rest will be cleared by calling the constructor
  1223. asUINT n = m_currentFunction->objVariablesOnHeap;
  1224. while( n-- > 0 )
  1225. {
  1226. int pos = m_currentFunction->objVariablePos[n];
  1227. *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
  1228. }
  1229. // Initialize the stack pointer with the space needed for local variables
  1230. m_regs.stackPointer -= m_currentFunction->variableSpace;
  1231. // Call the line callback for each script function, to guarantee that infinitely recursive scripts can
  1232. // be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES
  1233. if( m_regs.doProcessSuspend )
  1234. {
  1235. if( m_lineCallback )
  1236. CallLineCallback();
  1237. if( m_doSuspend )
  1238. m_status = asEXECUTION_SUSPENDED;
  1239. }
  1240. }
  1241. void asCContext::CallInterfaceMethod(asCScriptFunction *func)
  1242. {
  1243. // Resolve the interface method using the current script type
  1244. asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer;
  1245. if( obj == 0 )
  1246. {
  1247. // Tell the exception handler to clean up the arguments to this method
  1248. m_needToCleanupArgs = true;
  1249. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1250. return;
  1251. }
  1252. asCObjectType *objType = obj->objType;
  1253. // TODO: runtime optimize: The object type should have a list of only those methods that
  1254. // implement interface methods. This list should be ordered by
  1255. // the signatureId so that a binary search can be made, instead
  1256. // of a linear search.
  1257. //
  1258. // When this is done, we must also make sure the signatureId of a
  1259. // function never changes, e.g. when if the signature functions are
  1260. // released.
  1261. // Search the object type for a function that matches the interface function
  1262. asCScriptFunction *realFunc = 0;
  1263. if( func->funcType == asFUNC_INTERFACE )
  1264. {
  1265. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  1266. {
  1267. asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]];
  1268. if( f2->signatureId == func->signatureId )
  1269. {
  1270. if( f2->funcType == asFUNC_VIRTUAL )
  1271. realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
  1272. else
  1273. realFunc = f2;
  1274. break;
  1275. }
  1276. }
  1277. if( realFunc == 0 )
  1278. {
  1279. // Tell the exception handler to clean up the arguments to this method
  1280. m_needToCleanupArgs = true;
  1281. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1282. return;
  1283. }
  1284. }
  1285. else // if( func->funcType == asFUNC_VIRTUAL )
  1286. {
  1287. realFunc = objType->virtualFunctionTable[func->vfTableIdx];
  1288. }
  1289. // Then call the true script function
  1290. CallScriptFunction(realFunc);
  1291. }
  1292. void asCContext::ExecuteNext()
  1293. {
  1294. asDWORD *l_bc = m_regs.programPointer;
  1295. asDWORD *l_sp = m_regs.stackPointer;
  1296. asDWORD *l_fp = m_regs.stackFramePointer;
  1297. for(;;)
  1298. {
  1299. #ifdef AS_DEBUG
  1300. // Gather statistics on executed bytecode
  1301. stats.Instr(*(asBYTE*)l_bc);
  1302. // Used to verify that the size of the instructions are correct
  1303. asDWORD *old = l_bc;
  1304. #endif
  1305. // Remember to keep the cases in order and without
  1306. // gaps, because that will make the switch faster.
  1307. // It will be faster since only one lookup will be
  1308. // made to find the correct jump destination. If not
  1309. // in order, the switch will make two lookups.
  1310. switch( *(asBYTE*)l_bc )
  1311. {
  1312. //--------------
  1313. // memory access functions
  1314. case asBC_PopPtr:
  1315. // Pop a pointer from the stack
  1316. l_sp += AS_PTR_SIZE;
  1317. l_bc++;
  1318. break;
  1319. case asBC_PshGPtr:
  1320. // Replaces PGA + RDSPtr
  1321. l_sp -= AS_PTR_SIZE;
  1322. *(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc);
  1323. l_bc += 1 + AS_PTR_SIZE;
  1324. break;
  1325. // Push a dword value on the stack
  1326. case asBC_PshC4:
  1327. --l_sp;
  1328. *l_sp = asBC_DWORDARG(l_bc);
  1329. l_bc += 2;
  1330. break;
  1331. // Push the dword value of a variable on the stack
  1332. case asBC_PshV4:
  1333. --l_sp;
  1334. *l_sp = *(l_fp - asBC_SWORDARG0(l_bc));
  1335. l_bc++;
  1336. break;
  1337. // Push the address of a variable on the stack
  1338. case asBC_PSF:
  1339. l_sp -= AS_PTR_SIZE;
  1340. *(asPWORD*)l_sp = asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  1341. l_bc++;
  1342. break;
  1343. // Swap the top 2 pointers on the stack
  1344. case asBC_SwapPtr:
  1345. {
  1346. asPWORD p = (asPWORD)*l_sp;
  1347. *(asPWORD*)l_sp = *(asPWORD*)(l_sp+AS_PTR_SIZE);
  1348. *(asPWORD*)(l_sp+AS_PTR_SIZE) = p;
  1349. l_bc++;
  1350. }
  1351. break;
  1352. // Do a boolean not operation, modifying the value of the variable
  1353. case asBC_NOT:
  1354. #if AS_SIZEOF_BOOL == 1
  1355. {
  1356. // Set the value to true if it is equal to 0
  1357. // We need to use volatile here to tell the compiler it cannot
  1358. // change the order of read and write operations on the pointer.
  1359. volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  1360. asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1361. ptr[0] = val; // The result is stored in the lower byte
  1362. ptr[1] = 0; // Make sure the rest of the DWORD is 0
  1363. ptr[2] = 0;
  1364. ptr[3] = 0;
  1365. }
  1366. #else
  1367. *(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1368. #endif
  1369. l_bc++;
  1370. break;
  1371. // Push the dword value of a global variable on the stack
  1372. case asBC_PshG4:
  1373. --l_sp;
  1374. *l_sp = *(asDWORD*)asBC_PTRARG(l_bc);
  1375. l_bc += 1 + AS_PTR_SIZE;
  1376. break;
  1377. // Load the address of a global variable in the register, then
  1378. // copy the value of the global variable into a local variable
  1379. case asBC_LdGRdR4:
  1380. *(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc);
  1381. *(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
  1382. l_bc += 1+AS_PTR_SIZE;
  1383. break;
  1384. //----------------
  1385. // path control instructions
  1386. // Begin execution of a script function
  1387. case asBC_CALL:
  1388. {
  1389. int i = asBC_INTARG(l_bc);
  1390. l_bc += 2;
  1391. asASSERT( i >= 0 );
  1392. asASSERT( (i & FUNC_IMPORTED) == 0 );
  1393. // Need to move the values back to the context
  1394. m_regs.programPointer = l_bc;
  1395. m_regs.stackPointer = l_sp;
  1396. m_regs.stackFramePointer = l_fp;
  1397. CallScriptFunction(m_engine->scriptFunctions[i]);
  1398. // Extract the values from the context again
  1399. l_bc = m_regs.programPointer;
  1400. l_sp = m_regs.stackPointer;
  1401. l_fp = m_regs.stackFramePointer;
  1402. // If status isn't active anymore then we must stop
  1403. if( m_status != asEXECUTION_ACTIVE )
  1404. return;
  1405. }
  1406. break;
  1407. // Return to the caller, and remove the arguments from the stack
  1408. case asBC_RET:
  1409. {
  1410. // Return if this was the first function, or a nested execution
  1411. if( m_callStack.GetLength() == 0 ||
  1412. m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 )
  1413. {
  1414. m_status = asEXECUTION_FINISHED;
  1415. return;
  1416. }
  1417. asWORD w = asBC_WORDARG0(l_bc);
  1418. // Read the old framepointer, functionid, and programCounter from the call stack
  1419. PopCallState();
  1420. // Extract the values from the context again
  1421. l_bc = m_regs.programPointer;
  1422. l_sp = m_regs.stackPointer;
  1423. l_fp = m_regs.stackFramePointer;
  1424. // Pop arguments from stack
  1425. l_sp += w;
  1426. }
  1427. break;
  1428. // Jump to a relative position
  1429. case asBC_JMP:
  1430. l_bc += 2 + asBC_INTARG(l_bc);
  1431. break;
  1432. //----------------
  1433. // Conditional jumps
  1434. // Jump to a relative position if the value in the register is 0
  1435. case asBC_JZ:
  1436. if( *(int*)&m_regs.valueRegister == 0 )
  1437. l_bc += asBC_INTARG(l_bc) + 2;
  1438. else
  1439. l_bc += 2;
  1440. break;
  1441. // Jump to a relative position if the value in the register is not 0
  1442. case asBC_JNZ:
  1443. if( *(int*)&m_regs.valueRegister != 0 )
  1444. l_bc += asBC_INTARG(l_bc) + 2;
  1445. else
  1446. l_bc += 2;
  1447. break;
  1448. // Jump to a relative position if the value in the register is negative
  1449. case asBC_JS:
  1450. if( *(int*)&m_regs.valueRegister < 0 )
  1451. l_bc += asBC_INTARG(l_bc) + 2;
  1452. else
  1453. l_bc += 2;
  1454. break;
  1455. // Jump to a relative position if the value in the register it not negative
  1456. case asBC_JNS:
  1457. if( *(int*)&m_regs.valueRegister >= 0 )
  1458. l_bc += asBC_INTARG(l_bc) + 2;
  1459. else
  1460. l_bc += 2;
  1461. break;
  1462. // Jump to a relative position if the value in the register is greater than 0
  1463. case asBC_JP:
  1464. if( *(int*)&m_regs.valueRegister > 0 )
  1465. l_bc += asBC_INTARG(l_bc) + 2;
  1466. else
  1467. l_bc += 2;
  1468. break;
  1469. // Jump to a relative position if the value in the register is not greater than 0
  1470. case asBC_JNP:
  1471. if( *(int*)&m_regs.valueRegister <= 0 )
  1472. l_bc += asBC_INTARG(l_bc) + 2;
  1473. else
  1474. l_bc += 2;
  1475. break;
  1476. //--------------------
  1477. // test instructions
  1478. // If the value in the register is 0, then set the register to 1, else to 0
  1479. case asBC_TZ:
  1480. #if AS_SIZEOF_BOOL == 1
  1481. {
  1482. // Set the value to true if it is equal to 0
  1483. // We need to use volatile here to tell the compiler it cannot
  1484. // change the order of read and write operations on valueRegister.
  1485. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1486. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1487. asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1488. regBptr[0] = val; // The result is stored in the lower byte
  1489. regBptr[1] = 0; // Make sure the rest of the register is 0
  1490. regBptr[2] = 0;
  1491. regBptr[3] = 0;
  1492. regBptr[4] = 0;
  1493. regBptr[5] = 0;
  1494. regBptr[6] = 0;
  1495. regBptr[7] = 0;
  1496. }
  1497. #else
  1498. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1499. #endif
  1500. l_bc++;
  1501. break;
  1502. // If the value in the register is not 0, then set the register to 1, else to 0
  1503. case asBC_TNZ:
  1504. #if AS_SIZEOF_BOOL == 1
  1505. {
  1506. // Set the value to true if it is not equal to 0
  1507. // We need to use volatile here to tell the compiler it cannot
  1508. // change the order of read and write operations on valueRegister.
  1509. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1510. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1511. asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE;
  1512. regBptr[0] = val; // The result is stored in the lower byte
  1513. regBptr[1] = 0; // Make sure the rest of the register is 0
  1514. regBptr[2] = 0;
  1515. regBptr[3] = 0;
  1516. regBptr[4] = 0;
  1517. regBptr[5] = 0;
  1518. regBptr[6] = 0;
  1519. regBptr[7] = 0;
  1520. }
  1521. #else
  1522. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1523. #endif
  1524. l_bc++;
  1525. break;
  1526. // If the value in the register is negative, then set the register to 1, else to 0
  1527. case asBC_TS:
  1528. #if AS_SIZEOF_BOOL == 1
  1529. {
  1530. // Set the value to true if it is less than 0
  1531. // We need to use volatile here to tell the compiler it cannot
  1532. // change the order of read and write operations on valueRegister.
  1533. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1534. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1535. asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1536. regBptr[0] = val; // The result is stored in the lower byte
  1537. regBptr[1] = 0; // Make sure the rest of the register is 0
  1538. regBptr[2] = 0;
  1539. regBptr[3] = 0;
  1540. regBptr[4] = 0;
  1541. regBptr[5] = 0;
  1542. regBptr[6] = 0;
  1543. regBptr[7] = 0;
  1544. }
  1545. #else
  1546. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1547. #endif
  1548. l_bc++;
  1549. break;
  1550. // If the value in the register is not negative, then set the register to 1, else to 0
  1551. case asBC_TNS:
  1552. #if AS_SIZEOF_BOOL == 1
  1553. {
  1554. // Set the value to true if it is not less than 0
  1555. // We need to use volatile here to tell the compiler it cannot
  1556. // change the order of read and write operations on valueRegister.
  1557. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1558. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1559. asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1560. regBptr[0] = val; // The result is stored in the lower byte
  1561. regBptr[1] = 0; // Make sure the rest of the register is 0
  1562. regBptr[2] = 0;
  1563. regBptr[3] = 0;
  1564. regBptr[4] = 0;
  1565. regBptr[5] = 0;
  1566. regBptr[6] = 0;
  1567. regBptr[7] = 0;
  1568. }
  1569. #else
  1570. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1571. #endif
  1572. l_bc++;
  1573. break;
  1574. // If the value in the register is greater than 0, then set the register to 1, else to 0
  1575. case asBC_TP:
  1576. #if AS_SIZEOF_BOOL == 1
  1577. {
  1578. // Set the value to true if it is greater than 0
  1579. // We need to use volatile here to tell the compiler it cannot
  1580. // change the order of read and write operations on valueRegister.
  1581. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1582. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1583. asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1584. regBptr[0] = val; // The result is stored in the lower byte
  1585. regBptr[1] = 0; // Make sure the rest of the register is 0
  1586. regBptr[2] = 0;
  1587. regBptr[3] = 0;
  1588. regBptr[4] = 0;
  1589. regBptr[5] = 0;
  1590. regBptr[6] = 0;
  1591. regBptr[7] = 0;
  1592. }
  1593. #else
  1594. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1595. #endif
  1596. l_bc++;
  1597. break;
  1598. // If the value in the register is not greater than 0, then set the register to 1, else to 0
  1599. case asBC_TNP:
  1600. #if AS_SIZEOF_BOOL == 1
  1601. {
  1602. // Set the value to true if it is not greater than 0
  1603. // We need to use volatile here to tell the compiler it cannot
  1604. // change the order of read and write operations on valueRegister.
  1605. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1606. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1607. asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1608. regBptr[0] = val; // The result is stored in the lower byte
  1609. regBptr[1] = 0; // Make sure the rest of the register is 0
  1610. regBptr[2] = 0;
  1611. regBptr[3] = 0;
  1612. regBptr[4] = 0;
  1613. regBptr[5] = 0;
  1614. regBptr[6] = 0;
  1615. regBptr[7] = 0;
  1616. }
  1617. #else
  1618. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1619. #endif
  1620. l_bc++;
  1621. break;
  1622. //--------------------
  1623. // negate value
  1624. // Negate the integer value in the variable
  1625. case asBC_NEGi:
  1626. *(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc))));
  1627. l_bc++;
  1628. break;
  1629. // Negate the float value in the variable
  1630. case asBC_NEGf:
  1631. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc));
  1632. l_bc++;
  1633. break;
  1634. // Negate the double value in the variable
  1635. case asBC_NEGd:
  1636. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc));
  1637. l_bc++;
  1638. break;
  1639. //-------------------------
  1640. // Increment value pointed to by address in register
  1641. // Increment the short value pointed to by the register
  1642. case asBC_INCi16:
  1643. (**(short**)&m_regs.valueRegister)++;
  1644. l_bc++;
  1645. break;
  1646. // Increment the byte value pointed to by the register
  1647. case asBC_INCi8:
  1648. (**(char**)&m_regs.valueRegister)++;
  1649. l_bc++;
  1650. break;
  1651. // Decrement the short value pointed to by the register
  1652. case asBC_DECi16:
  1653. (**(short**)&m_regs.valueRegister)--;
  1654. l_bc++;
  1655. break;
  1656. // Decrement the byte value pointed to by the register
  1657. case asBC_DECi8:
  1658. (**(char**)&m_regs.valueRegister)--;
  1659. l_bc++;
  1660. break;
  1661. // Increment the integer value pointed to by the register
  1662. case asBC_INCi:
  1663. ++(**(int**)&m_regs.valueRegister);
  1664. l_bc++;
  1665. break;
  1666. // Decrement the integer value pointed to by the register
  1667. case asBC_DECi:
  1668. --(**(int**)&m_regs.valueRegister);
  1669. l_bc++;
  1670. break;
  1671. // Increment the float value pointed to by the register
  1672. case asBC_INCf:
  1673. ++(**(float**)&m_regs.valueRegister);
  1674. l_bc++;
  1675. break;
  1676. // Decrement the float value pointed to by the register
  1677. case asBC_DECf:
  1678. --(**(float**)&m_regs.valueRegister);
  1679. l_bc++;
  1680. break;
  1681. // Increment the double value pointed to by the register
  1682. case asBC_INCd:
  1683. ++(**(double**)&m_regs.valueRegister);
  1684. l_bc++;
  1685. break;
  1686. // Decrement the double value pointed to by the register
  1687. case asBC_DECd:
  1688. --(**(double**)&m_regs.valueRegister);
  1689. l_bc++;
  1690. break;
  1691. // Increment the local integer variable
  1692. case asBC_IncVi:
  1693. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++;
  1694. l_bc++;
  1695. break;
  1696. // Decrement the local integer variable
  1697. case asBC_DecVi:
  1698. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--;
  1699. l_bc++;
  1700. break;
  1701. //--------------------
  1702. // bits instructions
  1703. // Do a bitwise not on the value in the variable
  1704. case asBC_BNOT:
  1705. *(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc));
  1706. l_bc++;
  1707. break;
  1708. // Do a bitwise and of two variables and store the result in a third variable
  1709. case asBC_BAND:
  1710. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc));
  1711. l_bc += 2;
  1712. break;
  1713. // Do a bitwise or of two variables and store the result in a third variable
  1714. case asBC_BOR:
  1715. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc));
  1716. l_bc += 2;
  1717. break;
  1718. // Do a bitwise xor of two variables and store the result in a third variable
  1719. case asBC_BXOR:
  1720. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc));
  1721. l_bc += 2;
  1722. break;
  1723. // Do a logical shift left of two variables and store the result in a third variable
  1724. case asBC_BSLL:
  1725. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  1726. l_bc += 2;
  1727. break;
  1728. // Do a logical shift right of two variables and store the result in a third variable
  1729. case asBC_BSRL:
  1730. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1731. l_bc += 2;
  1732. break;
  1733. // Do an arithmetic shift right of two variables and store the result in a third variable
  1734. case asBC_BSRA:
  1735. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1736. l_bc += 2;
  1737. break;
  1738. case asBC_COPY:
  1739. {
  1740. void *d = (void*)*(asPWORD*)l_sp; l_sp += AS_PTR_SIZE;
  1741. void *s = (void*)*(asPWORD*)l_sp;
  1742. if( s == 0 || d == 0 )
  1743. {
  1744. // Need to move the values back to the context
  1745. m_regs.programPointer = l_bc;
  1746. m_regs.stackPointer = l_sp;
  1747. m_regs.stackFramePointer = l_fp;
  1748. // Raise exception
  1749. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1750. return;
  1751. }
  1752. memcpy(d, s, asBC_WORDARG0(l_bc)*4);
  1753. // replace the pointer on the stack with the lvalue
  1754. *(asPWORD**)l_sp = (asPWORD*)d;
  1755. }
  1756. l_bc += 2;
  1757. break;
  1758. case asBC_PshC8:
  1759. l_sp -= 2;
  1760. *(asQWORD*)l_sp = asBC_QWORDARG(l_bc);
  1761. l_bc += 3;
  1762. break;
  1763. case asBC_PshVPtr:
  1764. l_sp -= AS_PTR_SIZE;
  1765. *(asPWORD*)l_sp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1766. l_bc++;
  1767. break;
  1768. case asBC_RDSPtr:
  1769. {
  1770. // The pointer must not be null
  1771. asPWORD a = *(asPWORD*)l_sp;
  1772. if( a == 0 )
  1773. {
  1774. m_regs.programPointer = l_bc;
  1775. m_regs.stackPointer = l_sp;
  1776. m_regs.stackFramePointer = l_fp;
  1777. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1778. return;
  1779. }
  1780. // Pop an address from the stack, read a pointer from that address and push it on the stack
  1781. *(asPWORD*)l_sp = *(asPWORD*)a;
  1782. }
  1783. l_bc++;
  1784. break;
  1785. //----------------------------
  1786. // Comparisons
  1787. case asBC_CMPd:
  1788. {
  1789. // Do a comparison of the values, rather than a subtraction
  1790. // in order to get proper behaviour for infinity values.
  1791. double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc));
  1792. double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc));
  1793. if( dbl1 == dbl2 ) *(int*)&m_regs.valueRegister = 0;
  1794. else if( dbl1 < dbl2 ) *(int*)&m_regs.valueRegister = -1;
  1795. else *(int*)&m_regs.valueRegister = 1;
  1796. l_bc += 2;
  1797. }
  1798. break;
  1799. case asBC_CMPu:
  1800. {
  1801. asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1802. asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  1803. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  1804. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  1805. else *(int*)&m_regs.valueRegister = 1;
  1806. l_bc += 2;
  1807. }
  1808. break;
  1809. case asBC_CMPf:
  1810. {
  1811. // Do a comparison of the values, rather than a subtraction
  1812. // in order to get proper behaviour for infinity values.
  1813. float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
  1814. float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc));
  1815. if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0;
  1816. else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
  1817. else *(int*)&m_regs.valueRegister = 1;
  1818. l_bc += 2;
  1819. }
  1820. break;
  1821. case asBC_CMPi:
  1822. {
  1823. int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
  1824. int i2 = *(int*)(l_fp - asBC_SWORDARG1(l_bc));
  1825. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  1826. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  1827. else *(int*)&m_regs.valueRegister = 1;
  1828. l_bc += 2;
  1829. }
  1830. break;
  1831. //----------------------------
  1832. // Comparisons with constant value
  1833. case asBC_CMPIi:
  1834. {
  1835. int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
  1836. int i2 = asBC_INTARG(l_bc);
  1837. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  1838. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  1839. else *(int*)&m_regs.valueRegister = 1;
  1840. l_bc += 2;
  1841. }
  1842. break;
  1843. case asBC_CMPIf:
  1844. {
  1845. // Do a comparison of the values, rather than a subtraction
  1846. // in order to get proper behaviour for infinity values.
  1847. float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
  1848. float f2 = asBC_FLOATARG(l_bc);
  1849. if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0;
  1850. else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
  1851. else *(int*)&m_regs.valueRegister = 1;
  1852. l_bc += 2;
  1853. }
  1854. break;
  1855. case asBC_CMPIu:
  1856. {
  1857. asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1858. asDWORD d2 = asBC_DWORDARG(l_bc);
  1859. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  1860. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  1861. else *(int*)&m_regs.valueRegister = 1;
  1862. l_bc += 2;
  1863. }
  1864. break;
  1865. case asBC_JMPP:
  1866. l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2;
  1867. break;
  1868. case asBC_PopRPtr:
  1869. *(asPWORD*)&m_regs.valueRegister = *(asPWORD*)l_sp;
  1870. l_sp += AS_PTR_SIZE;
  1871. l_bc++;
  1872. break;
  1873. case asBC_PshRPtr:
  1874. l_sp -= AS_PTR_SIZE;
  1875. *(asPWORD*)l_sp = *(asPWORD*)&m_regs.valueRegister;
  1876. l_bc++;
  1877. break;
  1878. case asBC_STR:
  1879. {
  1880. // Get the string id from the argument
  1881. asWORD w = asBC_WORDARG0(l_bc);
  1882. // Push the string pointer on the stack
  1883. const asCString &b = m_engine->GetConstantString(w);
  1884. l_sp -= AS_PTR_SIZE;
  1885. *(asPWORD*)l_sp = (asPWORD)b.AddressOf();
  1886. // Push the string length on the stack
  1887. --l_sp;
  1888. *l_sp = (asDWORD)b.GetLength();
  1889. l_bc++;
  1890. }
  1891. break;
  1892. case asBC_CALLSYS:
  1893. {
  1894. // Get function ID from the argument
  1895. int i = asBC_INTARG(l_bc);
  1896. // Need to move the values back to the context as the called functions
  1897. // may use the debug interface to inspect the registers
  1898. m_regs.programPointer = l_bc;
  1899. m_regs.stackPointer = l_sp;
  1900. m_regs.stackFramePointer = l_fp;
  1901. l_sp += CallSystemFunction(i, this, 0);
  1902. // Update the program position after the call so that line number is correct
  1903. l_bc += 2;
  1904. if( m_regs.doProcessSuspend )
  1905. {
  1906. // Should the execution be suspended?
  1907. if( m_doSuspend )
  1908. {
  1909. m_regs.programPointer = l_bc;
  1910. m_regs.stackPointer = l_sp;
  1911. m_regs.stackFramePointer = l_fp;
  1912. m_status = asEXECUTION_SUSPENDED;
  1913. return;
  1914. }
  1915. // An exception might have been raised
  1916. if( m_status != asEXECUTION_ACTIVE )
  1917. {
  1918. m_regs.programPointer = l_bc;
  1919. m_regs.stackPointer = l_sp;
  1920. m_regs.stackFramePointer = l_fp;
  1921. return;
  1922. }
  1923. }
  1924. }
  1925. break;
  1926. case asBC_CALLBND:
  1927. {
  1928. // Get the function ID from the stack
  1929. int i = asBC_INTARG(l_bc);
  1930. l_bc += 2;
  1931. asASSERT( i >= 0 );
  1932. asASSERT( i & FUNC_IMPORTED );
  1933. // Need to move the values back to the context
  1934. m_regs.programPointer = l_bc;
  1935. m_regs.stackPointer = l_sp;
  1936. m_regs.stackFramePointer = l_fp;
  1937. int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId;
  1938. if( funcId == -1 )
  1939. {
  1940. // Tell the exception handler to clean up the arguments to this function
  1941. m_needToCleanupArgs = true;
  1942. SetInternalException(TXT_UNBOUND_FUNCTION);
  1943. return;
  1944. }
  1945. else
  1946. {
  1947. asCScriptFunction *func = m_engine->GetScriptFunction(funcId);
  1948. CallScriptFunction(func);
  1949. }
  1950. // Extract the values from the context again
  1951. l_bc = m_regs.programPointer;
  1952. l_sp = m_regs.stackPointer;
  1953. l_fp = m_regs.stackFramePointer;
  1954. // If status isn't active anymore then we must stop
  1955. if( m_status != asEXECUTION_ACTIVE )
  1956. return;
  1957. }
  1958. break;
  1959. case asBC_SUSPEND:
  1960. if( m_regs.doProcessSuspend )
  1961. {
  1962. if( m_lineCallback )
  1963. {
  1964. m_regs.programPointer = l_bc;
  1965. m_regs.stackPointer = l_sp;
  1966. m_regs.stackFramePointer = l_fp;
  1967. CallLineCallback();
  1968. }
  1969. if( m_doSuspend )
  1970. {
  1971. l_bc++;
  1972. // Need to move the values back to the context
  1973. m_regs.programPointer = l_bc;
  1974. m_regs.stackPointer = l_sp;
  1975. m_regs.stackFramePointer = l_fp;
  1976. m_status = asEXECUTION_SUSPENDED;
  1977. return;
  1978. }
  1979. }
  1980. l_bc++;
  1981. break;
  1982. case asBC_ALLOC:
  1983. {
  1984. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  1985. int func = asBC_INTARG(l_bc+AS_PTR_SIZE);
  1986. if( objType->flags & asOBJ_SCRIPT_OBJECT )
  1987. {
  1988. // Need to move the values back to the context as the construction
  1989. // of the script object may reuse the context for nested calls.
  1990. m_regs.programPointer = l_bc;
  1991. m_regs.stackPointer = l_sp;
  1992. m_regs.stackFramePointer = l_fp;
  1993. // Pre-allocate the memory
  1994. asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
  1995. // Pre-initialize the memory by calling the constructor for asCScriptObject
  1996. ScriptObject_Construct(objType, (asCScriptObject*)mem);
  1997. // Call the constructor to initalize the memory
  1998. asCScriptFunction *f = m_engine->scriptFunctions[func];
  1999. asDWORD **a = (asDWORD**)*(asPWORD*)(m_regs.stackPointer + f->GetSpaceNeededForArguments());
  2000. if( a ) *a = mem;
  2001. // Push the object pointer on the stack
  2002. m_regs.stackPointer -= AS_PTR_SIZE;
  2003. *(asPWORD*)m_regs.stackPointer = (asPWORD)mem;
  2004. m_regs.programPointer += 2+AS_PTR_SIZE;
  2005. CallScriptFunction(f);
  2006. // Extract the values from the context again
  2007. l_bc = m_regs.programPointer;
  2008. l_sp = m_regs.stackPointer;
  2009. l_fp = m_regs.stackFramePointer;
  2010. // If status isn't active anymore then we must stop
  2011. if( m_status != asEXECUTION_ACTIVE )
  2012. return;
  2013. }
  2014. else
  2015. {
  2016. // Pre-allocate the memory
  2017. asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
  2018. if( func )
  2019. {
  2020. // Need to move the values back to the context as the called functions
  2021. // may use the debug interface to inspect the registers
  2022. m_regs.programPointer = l_bc;
  2023. m_regs.stackPointer = l_sp;
  2024. m_regs.stackFramePointer = l_fp;
  2025. l_sp += CallSystemFunction(func, this, mem);
  2026. }
  2027. // Pop the variable address from the stack
  2028. asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
  2029. l_sp += AS_PTR_SIZE;
  2030. if( a ) *a = mem;
  2031. l_bc += 2+AS_PTR_SIZE;
  2032. if( m_regs.doProcessSuspend )
  2033. {
  2034. // Should the execution be suspended?
  2035. if( m_doSuspend )
  2036. {
  2037. m_regs.programPointer = l_bc;
  2038. m_regs.stackPointer = l_sp;
  2039. m_regs.stackFramePointer = l_fp;
  2040. m_status = asEXECUTION_SUSPENDED;
  2041. return;
  2042. }
  2043. // An exception might have been raised
  2044. if( m_status != asEXECUTION_ACTIVE )
  2045. {
  2046. m_regs.programPointer = l_bc;
  2047. m_regs.stackPointer = l_sp;
  2048. m_regs.stackFramePointer = l_fp;
  2049. m_engine->CallFree(mem);
  2050. *a = 0;
  2051. return;
  2052. }
  2053. }
  2054. }
  2055. }
  2056. break;
  2057. case asBC_FREE:
  2058. {
  2059. // Get the variable that holds the object handle/reference
  2060. asPWORD *a = (asPWORD*)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  2061. if( *a )
  2062. {
  2063. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  2064. asSTypeBehaviour *beh = &objType->beh;
  2065. // Need to move the values back to the context as the called functions
  2066. // may use the debug interface to inspect the registers
  2067. m_regs.programPointer = l_bc;
  2068. m_regs.stackPointer = l_sp;
  2069. m_regs.stackFramePointer = l_fp;
  2070. if( objType->flags & asOBJ_REF )
  2071. {
  2072. asASSERT( (objType->flags & asOBJ_NOCOUNT) || beh->release );
  2073. if( beh->release )
  2074. m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->release);
  2075. }
  2076. else
  2077. {
  2078. if( beh->destruct )
  2079. m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->destruct);
  2080. m_engine->CallFree((void*)(asPWORD)*a);
  2081. }
  2082. // Clear the variable
  2083. *a = 0;
  2084. }
  2085. }
  2086. l_bc += 1+AS_PTR_SIZE;
  2087. break;
  2088. case asBC_LOADOBJ:
  2089. {
  2090. // Move the object pointer from the object variable into the object register
  2091. void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc));
  2092. m_regs.objectType = 0;
  2093. m_regs.objectRegister = *a;
  2094. *a = 0;
  2095. }
  2096. l_bc++;
  2097. break;
  2098. case asBC_STOREOBJ:
  2099. // Move the object pointer from the object register to the object variable
  2100. *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asPWORD(m_regs.objectRegister);
  2101. m_regs.objectRegister = 0;
  2102. l_bc++;
  2103. break;
  2104. case asBC_GETOBJ:
  2105. {
  2106. // Read variable index from location on stack
  2107. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2108. asDWORD offset = *(asDWORD*)a;
  2109. // Move pointer from variable to the same location on the stack
  2110. asPWORD *v = (asPWORD*)(l_fp - offset);
  2111. *a = *v;
  2112. // Clear variable
  2113. *v = 0;
  2114. }
  2115. l_bc++;
  2116. break;
  2117. case asBC_REFCPY:
  2118. {
  2119. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  2120. asSTypeBehaviour *beh = &objType->beh;
  2121. // Pop address of destination pointer from the stack
  2122. void **d = (void**)*(asPWORD*)l_sp;
  2123. l_sp += AS_PTR_SIZE;
  2124. // Read wanted pointer from the stack
  2125. void *s = (void*)*(asPWORD*)l_sp;
  2126. // Need to move the values back to the context as the called functions
  2127. // may use the debug interface to inspect the registers
  2128. m_regs.programPointer = l_bc;
  2129. m_regs.stackPointer = l_sp;
  2130. m_regs.stackFramePointer = l_fp;
  2131. if( !(objType->flags & asOBJ_NOCOUNT) )
  2132. {
  2133. // Release previous object held by destination pointer
  2134. if( *d != 0 )
  2135. m_engine->CallObjectMethod(*d, beh->release);
  2136. // Increase ref counter of wanted object
  2137. if( s != 0 )
  2138. m_engine->CallObjectMethod(s, beh->addref);
  2139. }
  2140. // Set the new object in the destination
  2141. *d = s;
  2142. }
  2143. l_bc += 1+AS_PTR_SIZE;
  2144. break;
  2145. case asBC_CHKREF:
  2146. {
  2147. // Verify if the pointer on the stack is null
  2148. // This is used when validating a pointer that an operator will work on
  2149. asPWORD a = *(asPWORD*)l_sp;
  2150. if( a == 0 )
  2151. {
  2152. m_regs.programPointer = l_bc;
  2153. m_regs.stackPointer = l_sp;
  2154. m_regs.stackFramePointer = l_fp;
  2155. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2156. return;
  2157. }
  2158. }
  2159. l_bc++;
  2160. break;
  2161. case asBC_GETOBJREF:
  2162. {
  2163. // Get the location on the stack where the reference will be placed
  2164. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2165. // Replace the variable index with the object handle held in the variable
  2166. *(asPWORD**)a = *(asPWORD**)(l_fp - *a);
  2167. }
  2168. l_bc++;
  2169. break;
  2170. case asBC_GETREF:
  2171. {
  2172. // Get the location on the stack where the reference will be placed
  2173. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2174. // Replace the variable index with the address of the variable
  2175. *(asPWORD**)a = (asPWORD*)(l_fp - (int)*a);
  2176. }
  2177. l_bc++;
  2178. break;
  2179. case asBC_PshNull:
  2180. // Push a null pointer on the stack
  2181. l_sp -= AS_PTR_SIZE;
  2182. *(asPWORD*)l_sp = 0;
  2183. l_bc++;
  2184. break;
  2185. case asBC_ClrVPtr:
  2186. // TODO: runtime optimize: Is this instruction really necessary?
  2187. // CallScriptFunction() can clear the null handles upon entry, just as is done for
  2188. // all other object variables
  2189. // Clear pointer variable
  2190. *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
  2191. l_bc++;
  2192. break;
  2193. case asBC_OBJTYPE:
  2194. // Push the object type on the stack
  2195. l_sp -= AS_PTR_SIZE;
  2196. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  2197. l_bc += 1+AS_PTR_SIZE;
  2198. break;
  2199. case asBC_TYPEID:
  2200. // Equivalent to PshC4, but kept as separate instruction for bytecode serialization
  2201. --l_sp;
  2202. *l_sp = asBC_DWORDARG(l_bc);
  2203. l_bc += 2;
  2204. break;
  2205. case asBC_SetV4:
  2206. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2207. l_bc += 2;
  2208. break;
  2209. case asBC_SetV8:
  2210. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc);
  2211. l_bc += 3;
  2212. break;
  2213. case asBC_ADDSi:
  2214. {
  2215. // The pointer must not be null
  2216. asPWORD a = *(asPWORD*)l_sp;
  2217. if( a == 0 )
  2218. {
  2219. m_regs.programPointer = l_bc;
  2220. m_regs.stackPointer = l_sp;
  2221. m_regs.stackFramePointer = l_fp;
  2222. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2223. return;
  2224. }
  2225. // Add an offset to the pointer
  2226. *(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc);
  2227. }
  2228. l_bc += 2;
  2229. break;
  2230. case asBC_CpyVtoV4:
  2231. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc));
  2232. l_bc += 2;
  2233. break;
  2234. case asBC_CpyVtoV8:
  2235. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2236. l_bc += 2;
  2237. break;
  2238. case asBC_CpyVtoR4:
  2239. *(asDWORD*)&m_regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2240. l_bc++;
  2241. break;
  2242. case asBC_CpyVtoR8:
  2243. *(asQWORD*)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2244. l_bc++;
  2245. break;
  2246. case asBC_CpyVtoG4:
  2247. *(asDWORD*)asBC_PTRARG(l_bc) = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2248. l_bc += 1 + AS_PTR_SIZE;
  2249. break;
  2250. case asBC_CpyRtoV4:
  2251. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&m_regs.valueRegister;
  2252. l_bc++;
  2253. break;
  2254. case asBC_CpyRtoV8:
  2255. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = m_regs.valueRegister;
  2256. l_bc++;
  2257. break;
  2258. case asBC_CpyGtoV4:
  2259. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)asBC_PTRARG(l_bc);
  2260. l_bc += 1 + AS_PTR_SIZE;
  2261. break;
  2262. case asBC_WRTV1:
  2263. // The pointer in the register points to a byte, and *(l_fp - offset) too
  2264. **(asBYTE**)&m_regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2265. l_bc++;
  2266. break;
  2267. case asBC_WRTV2:
  2268. // The pointer in the register points to a word, and *(l_fp - offset) too
  2269. **(asWORD**)&m_regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2270. l_bc++;
  2271. break;
  2272. case asBC_WRTV4:
  2273. **(asDWORD**)&m_regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc));
  2274. l_bc++;
  2275. break;
  2276. case asBC_WRTV8:
  2277. **(asQWORD**)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2278. l_bc++;
  2279. break;
  2280. case asBC_RDR1:
  2281. {
  2282. // The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte
  2283. asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2284. bPtr[0] = **(asBYTE**)&m_regs.valueRegister; // read the byte
  2285. bPtr[1] = 0; // 0 the rest of the DWORD
  2286. bPtr[2] = 0;
  2287. bPtr[3] = 0;
  2288. }
  2289. l_bc++;
  2290. break;
  2291. case asBC_RDR2:
  2292. {
  2293. // The pointer in the register points to a word, and *(l_fp - offset) will also point to a word
  2294. asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2295. wPtr[0] = **(asWORD**)&m_regs.valueRegister; // read the word
  2296. wPtr[1] = 0; // 0 the rest of the DWORD
  2297. }
  2298. l_bc++;
  2299. break;
  2300. case asBC_RDR4:
  2301. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
  2302. l_bc++;
  2303. break;
  2304. case asBC_RDR8:
  2305. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&m_regs.valueRegister;
  2306. l_bc++;
  2307. break;
  2308. case asBC_LDG:
  2309. *(asPWORD*)&m_regs.valueRegister = asBC_PTRARG(l_bc);
  2310. l_bc += 1+AS_PTR_SIZE;
  2311. break;
  2312. case asBC_LDV:
  2313. *(asDWORD**)&m_regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc));
  2314. l_bc++;
  2315. break;
  2316. case asBC_PGA:
  2317. l_sp -= AS_PTR_SIZE;
  2318. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  2319. l_bc += 1+AS_PTR_SIZE;
  2320. break;
  2321. case asBC_CmpPtr:
  2322. {
  2323. // TODO: runtime optimize: This instruction should really just be an equals, and return true or false.
  2324. // The instruction is only used for is and !is tests anyway.
  2325. asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2326. asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2327. if( p1 == p2 ) *(int*)&m_regs.valueRegister = 0;
  2328. else if( p1 < p2 ) *(int*)&m_regs.valueRegister = -1;
  2329. else *(int*)&m_regs.valueRegister = 1;
  2330. l_bc += 2;
  2331. }
  2332. break;
  2333. case asBC_VAR:
  2334. l_sp -= AS_PTR_SIZE;
  2335. *(asPWORD*)l_sp = (asPWORD)asBC_SWORDARG0(l_bc);
  2336. l_bc++;
  2337. break;
  2338. //----------------------------
  2339. // Type conversions
  2340. case asBC_iTOf:
  2341. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc)));
  2342. l_bc++;
  2343. break;
  2344. case asBC_fTOi:
  2345. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)));
  2346. l_bc++;
  2347. break;
  2348. case asBC_uTOf:
  2349. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc)));
  2350. l_bc++;
  2351. break;
  2352. case asBC_fTOu:
  2353. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2354. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))));
  2355. l_bc++;
  2356. break;
  2357. case asBC_sbTOi:
  2358. // *(l_fp - offset) points to a char, and will point to an int afterwards
  2359. *(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc));
  2360. l_bc++;
  2361. break;
  2362. case asBC_swTOi:
  2363. // *(l_fp - offset) points to a short, and will point to an int afterwards
  2364. *(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc));
  2365. l_bc++;
  2366. break;
  2367. case asBC_ubTOi:
  2368. // (l_fp - offset) points to a byte, and will point to an int afterwards
  2369. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2370. l_bc++;
  2371. break;
  2372. case asBC_uwTOi:
  2373. // *(l_fp - offset) points to a word, and will point to an int afterwards
  2374. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2375. l_bc++;
  2376. break;
  2377. case asBC_dTOi:
  2378. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2379. l_bc += 2;
  2380. break;
  2381. case asBC_dTOu:
  2382. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2383. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))));
  2384. l_bc += 2;
  2385. break;
  2386. case asBC_dTOf:
  2387. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2388. l_bc += 2;
  2389. break;
  2390. case asBC_iTOd:
  2391. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2392. l_bc += 2;
  2393. break;
  2394. case asBC_uTOd:
  2395. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2396. l_bc += 2;
  2397. break;
  2398. case asBC_fTOd:
  2399. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2400. l_bc += 2;
  2401. break;
  2402. //------------------------------
  2403. // Math operations
  2404. case asBC_ADDi:
  2405. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2406. l_bc += 2;
  2407. break;
  2408. case asBC_SUBi:
  2409. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2410. l_bc += 2;
  2411. break;
  2412. case asBC_MULi:
  2413. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2414. l_bc += 2;
  2415. break;
  2416. case asBC_DIVi:
  2417. {
  2418. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2419. if( divider == 0 )
  2420. {
  2421. // Need to move the values back to the context
  2422. m_regs.programPointer = l_bc;
  2423. m_regs.stackPointer = l_sp;
  2424. m_regs.stackFramePointer = l_fp;
  2425. // Raise exception
  2426. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2427. return;
  2428. }
  2429. else if( divider == -1 )
  2430. {
  2431. // Need to check if the value that is divided is 0x80000000
  2432. // as dividing it with -1 will cause an overflow exception
  2433. if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
  2434. {
  2435. // Need to move the values back to the context
  2436. m_regs.programPointer = l_bc;
  2437. m_regs.stackPointer = l_sp;
  2438. m_regs.stackFramePointer = l_fp;
  2439. // Raise exception
  2440. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2441. return;
  2442. }
  2443. }
  2444. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2445. }
  2446. l_bc += 2;
  2447. break;
  2448. case asBC_MODi:
  2449. {
  2450. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2451. if( divider == 0 )
  2452. {
  2453. // Need to move the values back to the context
  2454. m_regs.programPointer = l_bc;
  2455. m_regs.stackPointer = l_sp;
  2456. m_regs.stackFramePointer = l_fp;
  2457. // Raise exception
  2458. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2459. return;
  2460. }
  2461. else if( divider == -1 )
  2462. {
  2463. // Need to check if the value that is divided is 0x80000000
  2464. // as dividing it with -1 will cause an overflow exception
  2465. if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
  2466. {
  2467. // Need to move the values back to the context
  2468. m_regs.programPointer = l_bc;
  2469. m_regs.stackPointer = l_sp;
  2470. m_regs.stackFramePointer = l_fp;
  2471. // Raise exception
  2472. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2473. return;
  2474. }
  2475. }
  2476. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  2477. }
  2478. l_bc += 2;
  2479. break;
  2480. case asBC_ADDf:
  2481. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2482. l_bc += 2;
  2483. break;
  2484. case asBC_SUBf:
  2485. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2486. l_bc += 2;
  2487. break;
  2488. case asBC_MULf:
  2489. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2490. l_bc += 2;
  2491. break;
  2492. case asBC_DIVf:
  2493. {
  2494. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2495. if( divider == 0 )
  2496. {
  2497. // Need to move the values back to the context
  2498. m_regs.programPointer = l_bc;
  2499. m_regs.stackPointer = l_sp;
  2500. m_regs.stackFramePointer = l_fp;
  2501. // Raise exception
  2502. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2503. return;
  2504. }
  2505. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2506. }
  2507. l_bc += 2;
  2508. break;
  2509. case asBC_MODf:
  2510. {
  2511. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2512. if( divider == 0 )
  2513. {
  2514. // Need to move the values back to the context
  2515. m_regs.programPointer = l_bc;
  2516. m_regs.stackPointer = l_sp;
  2517. m_regs.stackFramePointer = l_fp;
  2518. // Raise exception
  2519. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2520. return;
  2521. }
  2522. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2523. }
  2524. l_bc += 2;
  2525. break;
  2526. case asBC_ADDd:
  2527. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2528. l_bc += 2;
  2529. break;
  2530. case asBC_SUBd:
  2531. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2532. l_bc += 2;
  2533. break;
  2534. case asBC_MULd:
  2535. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2536. l_bc += 2;
  2537. break;
  2538. case asBC_DIVd:
  2539. {
  2540. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2541. if( divider == 0 )
  2542. {
  2543. // Need to move the values back to the context
  2544. m_regs.programPointer = l_bc;
  2545. m_regs.stackPointer = l_sp;
  2546. m_regs.stackFramePointer = l_fp;
  2547. // Raise exception
  2548. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2549. return;
  2550. }
  2551. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2552. l_bc += 2;
  2553. }
  2554. break;
  2555. case asBC_MODd:
  2556. {
  2557. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2558. if( divider == 0 )
  2559. {
  2560. // Need to move the values back to the context
  2561. m_regs.programPointer = l_bc;
  2562. m_regs.stackPointer = l_sp;
  2563. m_regs.stackFramePointer = l_fp;
  2564. // Raise exception
  2565. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2566. return;
  2567. }
  2568. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2569. l_bc += 2;
  2570. }
  2571. break;
  2572. //------------------------------
  2573. // Math operations with constant value
  2574. case asBC_ADDIi:
  2575. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1);
  2576. l_bc += 3;
  2577. break;
  2578. case asBC_SUBIi:
  2579. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1);
  2580. l_bc += 3;
  2581. break;
  2582. case asBC_MULIi:
  2583. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1);
  2584. l_bc += 3;
  2585. break;
  2586. case asBC_ADDIf:
  2587. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1);
  2588. l_bc += 3;
  2589. break;
  2590. case asBC_SUBIf:
  2591. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1);
  2592. l_bc += 3;
  2593. break;
  2594. case asBC_MULIf:
  2595. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1);
  2596. l_bc += 3;
  2597. break;
  2598. //-----------------------------------
  2599. case asBC_SetG4:
  2600. *(asDWORD*)asBC_PTRARG(l_bc) = asBC_DWORDARG(l_bc+AS_PTR_SIZE);
  2601. l_bc += 2 + AS_PTR_SIZE;
  2602. break;
  2603. case asBC_ChkRefS:
  2604. {
  2605. // Verify if the pointer on the stack refers to a non-null value
  2606. // This is used to validate a reference to a handle
  2607. asPWORD *a = (asPWORD*)*(asPWORD*)l_sp;
  2608. if( *a == 0 )
  2609. {
  2610. m_regs.programPointer = l_bc;
  2611. m_regs.stackPointer = l_sp;
  2612. m_regs.stackFramePointer = l_fp;
  2613. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2614. return;
  2615. }
  2616. }
  2617. l_bc++;
  2618. break;
  2619. case asBC_ChkNullV:
  2620. {
  2621. // Verify if variable (on the stack) is not null
  2622. asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc));
  2623. if( a == 0 )
  2624. {
  2625. m_regs.programPointer = l_bc;
  2626. m_regs.stackPointer = l_sp;
  2627. m_regs.stackFramePointer = l_fp;
  2628. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2629. return;
  2630. }
  2631. }
  2632. l_bc++;
  2633. break;
  2634. case asBC_CALLINTF:
  2635. {
  2636. int i = asBC_INTARG(l_bc);
  2637. l_bc += 2;
  2638. asASSERT( i >= 0 );
  2639. asASSERT( (i & FUNC_IMPORTED) == 0 );
  2640. // Need to move the values back to the context
  2641. m_regs.programPointer = l_bc;
  2642. m_regs.stackPointer = l_sp;
  2643. m_regs.stackFramePointer = l_fp;
  2644. CallInterfaceMethod(m_engine->GetScriptFunction(i));
  2645. // Extract the values from the context again
  2646. l_bc = m_regs.programPointer;
  2647. l_sp = m_regs.stackPointer;
  2648. l_fp = m_regs.stackFramePointer;
  2649. // If status isn't active anymore then we must stop
  2650. if( m_status != asEXECUTION_ACTIVE )
  2651. return;
  2652. }
  2653. break;
  2654. case asBC_iTOb:
  2655. {
  2656. // *(l_fp - offset) points to an int, and will point to a byte afterwards
  2657. // We need to use volatile here to tell the compiler not to rearrange
  2658. // read and write operations during optimizations.
  2659. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2660. volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2661. bPtr[0] = (asBYTE)val; // write the byte
  2662. bPtr[1] = 0; // 0 the rest of the DWORD
  2663. bPtr[2] = 0;
  2664. bPtr[3] = 0;
  2665. }
  2666. l_bc++;
  2667. break;
  2668. case asBC_iTOw:
  2669. {
  2670. // *(l_fp - offset) points to an int, and will point to word afterwards
  2671. // We need to use volatile here to tell the compiler not to rearrange
  2672. // read and write operations during optimizations.
  2673. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2674. volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2675. wPtr[0] = (asWORD)val; // write the word
  2676. wPtr[1] = 0; // 0 the rest of the DWORD
  2677. }
  2678. l_bc++;
  2679. break;
  2680. case asBC_SetV1:
  2681. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2682. // when the bytecode instructions were more tightly packed. It can now
  2683. // be removed. When removing it, make sure the value is correctly converted
  2684. // on big-endian CPUs.
  2685. // The byte is already stored correctly in the argument
  2686. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2687. l_bc += 2;
  2688. break;
  2689. case asBC_SetV2:
  2690. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2691. // when the bytecode instructions were more tightly packed. It can now
  2692. // be removed. When removing it, make sure the value is correctly converted
  2693. // on big-endian CPUs.
  2694. // The word is already stored correctly in the argument
  2695. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2696. l_bc += 2;
  2697. break;
  2698. case asBC_Cast:
  2699. // Cast the handle at the top of the stack to the type in the argument
  2700. {
  2701. asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
  2702. if( a && *a )
  2703. {
  2704. asDWORD typeId = asBC_DWORDARG(l_bc);
  2705. asCScriptObject *obj = (asCScriptObject *)* a;
  2706. asCObjectType *objType = obj->objType;
  2707. asCObjectType *to = m_engine->GetObjectTypeFromTypeId(typeId);
  2708. // This instruction can only be used with script classes and interfaces
  2709. asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT );
  2710. asASSERT( to->flags & asOBJ_SCRIPT_OBJECT );
  2711. if( objType->Implements(to) || objType->DerivesFrom(to) )
  2712. {
  2713. m_regs.objectType = 0;
  2714. m_regs.objectRegister = obj;
  2715. obj->AddRef();
  2716. }
  2717. else
  2718. {
  2719. // The object register should already be null, so there
  2720. // is no need to clear it if the cast is unsuccessful
  2721. asASSERT( m_regs.objectRegister == 0 );
  2722. }
  2723. }
  2724. l_sp += AS_PTR_SIZE;
  2725. }
  2726. l_bc += 2;
  2727. break;
  2728. case asBC_i64TOi:
  2729. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  2730. l_bc += 2;
  2731. break;
  2732. case asBC_uTOi64:
  2733. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2734. l_bc += 2;
  2735. break;
  2736. case asBC_iTOi64:
  2737. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2738. l_bc += 2;
  2739. break;
  2740. case asBC_fTOi64:
  2741. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2742. l_bc += 2;
  2743. break;
  2744. case asBC_dTOi64:
  2745. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)));
  2746. l_bc++;
  2747. break;
  2748. case asBC_fTOu64:
  2749. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))));
  2750. l_bc += 2;
  2751. break;
  2752. case asBC_dTOu64:
  2753. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))));
  2754. l_bc++;
  2755. break;
  2756. case asBC_i64TOf:
  2757. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  2758. l_bc += 2;
  2759. break;
  2760. case asBC_u64TOf:
  2761. #if _MSC_VER <= 1200 // MSVC6
  2762. {
  2763. // MSVC6 doesn't permit UINT64 to double
  2764. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  2765. if( v < 0 )
  2766. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v);
  2767. else
  2768. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v);
  2769. }
  2770. #else
  2771. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)));
  2772. #endif
  2773. l_bc += 2;
  2774. break;
  2775. case asBC_i64TOd:
  2776. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)));
  2777. l_bc++;
  2778. break;
  2779. case asBC_u64TOd:
  2780. #if _MSC_VER <= 1200 // MSVC6
  2781. {
  2782. // MSVC6 doesn't permit UINT64 to double
  2783. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  2784. if( v < 0 )
  2785. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v);
  2786. else
  2787. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v);
  2788. }
  2789. #else
  2790. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)));
  2791. #endif
  2792. l_bc++;
  2793. break;
  2794. case asBC_NEGi64:
  2795. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  2796. l_bc++;
  2797. break;
  2798. case asBC_INCi64:
  2799. ++(**(asQWORD**)&m_regs.valueRegister);
  2800. l_bc++;
  2801. break;
  2802. case asBC_DECi64:
  2803. --(**(asQWORD**)&m_regs.valueRegister);
  2804. l_bc++;
  2805. break;
  2806. case asBC_BNOT64:
  2807. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2808. l_bc++;
  2809. break;
  2810. case asBC_ADDi64:
  2811. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2812. l_bc += 2;
  2813. break;
  2814. case asBC_SUBi64:
  2815. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2816. l_bc += 2;
  2817. break;
  2818. case asBC_MULi64:
  2819. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2820. l_bc += 2;
  2821. break;
  2822. case asBC_DIVi64:
  2823. {
  2824. asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
  2825. if( divider == 0 )
  2826. {
  2827. // Need to move the values back to the context
  2828. m_regs.programPointer = l_bc;
  2829. m_regs.stackPointer = l_sp;
  2830. m_regs.stackFramePointer = l_fp;
  2831. // Raise exception
  2832. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2833. return;
  2834. }
  2835. else if( divider == -1 )
  2836. {
  2837. // Need to check if the value that is divided is 1<<63
  2838. // as dividing it with -1 will cause an overflow exception
  2839. if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
  2840. {
  2841. // Need to move the values back to the context
  2842. m_regs.programPointer = l_bc;
  2843. m_regs.stackPointer = l_sp;
  2844. m_regs.stackFramePointer = l_fp;
  2845. // Raise exception
  2846. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2847. return;
  2848. }
  2849. }
  2850. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2851. }
  2852. l_bc += 2;
  2853. break;
  2854. case asBC_MODi64:
  2855. {
  2856. asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
  2857. if( divider == 0 )
  2858. {
  2859. // Need to move the values back to the context
  2860. m_regs.programPointer = l_bc;
  2861. m_regs.stackPointer = l_sp;
  2862. m_regs.stackFramePointer = l_fp;
  2863. // Raise exception
  2864. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2865. return;
  2866. }
  2867. else if( divider == -1 )
  2868. {
  2869. // Need to check if the value that is divided is 1<<63
  2870. // as dividing it with -1 will cause an overflow exception
  2871. if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
  2872. {
  2873. // Need to move the values back to the context
  2874. m_regs.programPointer = l_bc;
  2875. m_regs.stackPointer = l_sp;
  2876. m_regs.stackFramePointer = l_fp;
  2877. // Raise exception
  2878. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2879. return;
  2880. }
  2881. }
  2882. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  2883. }
  2884. l_bc += 2;
  2885. break;
  2886. case asBC_BAND64:
  2887. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2888. l_bc += 2;
  2889. break;
  2890. case asBC_BOR64:
  2891. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2892. l_bc += 2;
  2893. break;
  2894. case asBC_BXOR64:
  2895. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2896. l_bc += 2;
  2897. break;
  2898. case asBC_BSLL64:
  2899. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  2900. l_bc += 2;
  2901. break;
  2902. case asBC_BSRL64:
  2903. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  2904. l_bc += 2;
  2905. break;
  2906. case asBC_BSRA64:
  2907. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  2908. l_bc += 2;
  2909. break;
  2910. case asBC_CMPi64:
  2911. {
  2912. asINT64 i1 = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  2913. asINT64 i2 = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  2914. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  2915. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  2916. else *(int*)&m_regs.valueRegister = 1;
  2917. l_bc += 2;
  2918. }
  2919. break;
  2920. case asBC_CMPu64:
  2921. {
  2922. asQWORD d1 = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2923. asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2924. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  2925. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  2926. else *(int*)&m_regs.valueRegister = 1;
  2927. l_bc += 2;
  2928. }
  2929. break;
  2930. case asBC_ChkNullS:
  2931. {
  2932. // Verify if the pointer on the stack is null
  2933. // This is used for example when validating handles passed as function arguments
  2934. asPWORD a = *(asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2935. if( a == 0 )
  2936. {
  2937. m_regs.programPointer = l_bc;
  2938. m_regs.stackPointer = l_sp;
  2939. m_regs.stackFramePointer = l_fp;
  2940. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2941. return;
  2942. }
  2943. }
  2944. l_bc++;
  2945. break;
  2946. case asBC_ClrHi:
  2947. #if AS_SIZEOF_BOOL == 1
  2948. {
  2949. // Clear the upper bytes, so that trash data don't interfere with boolean operations
  2950. // We need to use volatile here to tell the compiler it cannot
  2951. // change the order of read and write operations on the pointer.
  2952. volatile asBYTE *ptr = (asBYTE*)&m_regs.valueRegister;
  2953. ptr[1] = 0; // The boolean value is stored in the lower byte, so we clear the rest
  2954. ptr[2] = 0;
  2955. ptr[3] = 0;
  2956. }
  2957. #else
  2958. // We don't have anything to do here
  2959. #endif
  2960. l_bc++;
  2961. break;
  2962. case asBC_JitEntry:
  2963. {
  2964. if( m_currentFunction->jitFunction )
  2965. {
  2966. asPWORD jitArg = asBC_PTRARG(l_bc);
  2967. if( jitArg )
  2968. {
  2969. // Resume JIT operation
  2970. m_regs.programPointer = l_bc;
  2971. m_regs.stackPointer = l_sp;
  2972. m_regs.stackFramePointer = l_fp;
  2973. (m_currentFunction->jitFunction)(&m_regs, jitArg);
  2974. l_bc = m_regs.programPointer;
  2975. l_sp = m_regs.stackPointer;
  2976. l_fp = m_regs.stackFramePointer;
  2977. // If status isn't active anymore then we must stop
  2978. if( m_status != asEXECUTION_ACTIVE )
  2979. return;
  2980. break;
  2981. }
  2982. }
  2983. // Not a JIT resume point, treat as nop
  2984. l_bc += 1+AS_PTR_SIZE;
  2985. }
  2986. break;
  2987. case asBC_CallPtr:
  2988. {
  2989. // Get the function pointer from the local variable
  2990. asCScriptFunction *func = *(asCScriptFunction**)(l_fp - asBC_SWORDARG0(l_bc));
  2991. // Need to move the values back to the context
  2992. m_regs.programPointer = l_bc;
  2993. m_regs.stackPointer = l_sp;
  2994. m_regs.stackFramePointer = l_fp;
  2995. if( func == 0 )
  2996. {
  2997. // Need to update the program pointer anyway for the exception handler
  2998. m_regs.programPointer++;
  2999. // Tell the exception handler to clean up the arguments to this method
  3000. m_needToCleanupArgs = true;
  3001. // TODO: funcdef: Should we have a different exception string?
  3002. SetInternalException(TXT_UNBOUND_FUNCTION);
  3003. return;
  3004. }
  3005. else
  3006. {
  3007. if( func->funcType == asFUNC_SCRIPT )
  3008. {
  3009. m_regs.programPointer++;
  3010. CallScriptFunction(func);
  3011. }
  3012. else if( func->funcType == asFUNC_DELEGATE )
  3013. {
  3014. // Push the object pointer on the stack. There is always a reserved space for this so
  3015. // we don't don't need to worry about overflowing the allocated memory buffer
  3016. asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
  3017. m_regs.stackPointer -= AS_PTR_SIZE;
  3018. *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
  3019. // Call the delegated method
  3020. if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
  3021. {
  3022. m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this, 0);
  3023. // Update program position after the call so the line number
  3024. // is correct in case the system function queries it
  3025. m_regs.programPointer++;
  3026. }
  3027. else
  3028. {
  3029. m_regs.programPointer++;
  3030. // TODO: run-time optimize: The true method could be figured out when creating the delegate
  3031. CallInterfaceMethod(func->funcForDelegate);
  3032. }
  3033. }
  3034. else
  3035. {
  3036. asASSERT( func->funcType == asFUNC_SYSTEM );
  3037. m_regs.stackPointer += CallSystemFunction(func->id, this, 0);
  3038. // Update program position after the call so the line number
  3039. // is correct in case the system function queries it
  3040. m_regs.programPointer++;
  3041. }
  3042. }
  3043. // Extract the values from the context again
  3044. l_bc = m_regs.programPointer;
  3045. l_sp = m_regs.stackPointer;
  3046. l_fp = m_regs.stackFramePointer;
  3047. // If status isn't active anymore then we must stop
  3048. if( m_status != asEXECUTION_ACTIVE )
  3049. return;
  3050. }
  3051. break;
  3052. case asBC_FuncPtr:
  3053. // Push the function pointer on the stack. The pointer is in the argument
  3054. l_sp -= AS_PTR_SIZE;
  3055. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  3056. l_bc += 1+AS_PTR_SIZE;
  3057. break;
  3058. case asBC_LoadThisR:
  3059. {
  3060. // PshVPtr 0
  3061. asPWORD tmp = *(asPWORD*)l_fp;
  3062. // Make sure the pointer is not null
  3063. if( tmp == 0 )
  3064. {
  3065. // Need to move the values back to the context
  3066. m_regs.programPointer = l_bc;
  3067. m_regs.stackPointer = l_sp;
  3068. m_regs.stackFramePointer = l_fp;
  3069. // Raise exception
  3070. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3071. return;
  3072. }
  3073. // ADDSi
  3074. tmp = tmp + asBC_SWORDARG0(l_bc);
  3075. // PopRPtr
  3076. *(asPWORD*)&m_regs.valueRegister = tmp;
  3077. l_bc += 2;
  3078. }
  3079. break;
  3080. // Push the qword value of a variable on the stack
  3081. case asBC_PshV8:
  3082. l_sp -= 2;
  3083. *(asQWORD*)l_sp = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3084. l_bc++;
  3085. break;
  3086. case asBC_DIVu:
  3087. {
  3088. asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
  3089. if( divider == 0 )
  3090. {
  3091. // Need to move the values back to the context
  3092. m_regs.programPointer = l_bc;
  3093. m_regs.stackPointer = l_sp;
  3094. m_regs.stackFramePointer = l_fp;
  3095. // Raise exception
  3096. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3097. return;
  3098. }
  3099. *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  3100. }
  3101. l_bc += 2;
  3102. break;
  3103. case asBC_MODu:
  3104. {
  3105. asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
  3106. if( divider == 0 )
  3107. {
  3108. // Need to move the values back to the context
  3109. m_regs.programPointer = l_bc;
  3110. m_regs.stackPointer = l_sp;
  3111. m_regs.stackFramePointer = l_fp;
  3112. // Raise exception
  3113. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3114. return;
  3115. }
  3116. *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  3117. }
  3118. l_bc += 2;
  3119. break;
  3120. case asBC_DIVu64:
  3121. {
  3122. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3123. if( divider == 0 )
  3124. {
  3125. // Need to move the values back to the context
  3126. m_regs.programPointer = l_bc;
  3127. m_regs.stackPointer = l_sp;
  3128. m_regs.stackFramePointer = l_fp;
  3129. // Raise exception
  3130. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3131. return;
  3132. }
  3133. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  3134. }
  3135. l_bc += 2;
  3136. break;
  3137. case asBC_MODu64:
  3138. {
  3139. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3140. if( divider == 0 )
  3141. {
  3142. // Need to move the values back to the context
  3143. m_regs.programPointer = l_bc;
  3144. m_regs.stackPointer = l_sp;
  3145. m_regs.stackFramePointer = l_fp;
  3146. // Raise exception
  3147. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3148. return;
  3149. }
  3150. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  3151. }
  3152. l_bc += 2;
  3153. break;
  3154. case asBC_LoadRObjR:
  3155. {
  3156. // PshVPtr x
  3157. asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3158. // Make sure the pointer is not null
  3159. if( tmp == 0 )
  3160. {
  3161. // Need to move the values back to the context
  3162. m_regs.programPointer = l_bc;
  3163. m_regs.stackPointer = l_sp;
  3164. m_regs.stackFramePointer = l_fp;
  3165. // Raise exception
  3166. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3167. return;
  3168. }
  3169. // ADDSi y
  3170. tmp = tmp + asBC_SWORDARG1(l_bc);
  3171. // PopRPtr
  3172. *(asPWORD*)&m_regs.valueRegister = tmp;
  3173. l_bc += 3;
  3174. }
  3175. break;
  3176. case asBC_LoadVObjR:
  3177. {
  3178. // PSF x
  3179. asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc));
  3180. // ADDSi y
  3181. tmp = tmp + asBC_SWORDARG1(l_bc);
  3182. // PopRPtr
  3183. *(asPWORD*)&m_regs.valueRegister = tmp;
  3184. l_bc += 3;
  3185. }
  3186. break;
  3187. case asBC_RefCpyV:
  3188. // Same as PSF v, REFCPY
  3189. {
  3190. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  3191. asSTypeBehaviour *beh = &objType->beh;
  3192. // Determine destination from argument
  3193. void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  3194. // Read wanted pointer from the stack
  3195. void *s = (void*)*(asPWORD*)l_sp;
  3196. // Need to move the values back to the context as the called functions
  3197. // may use the debug interface to inspect the registers
  3198. m_regs.programPointer = l_bc;
  3199. m_regs.stackPointer = l_sp;
  3200. m_regs.stackFramePointer = l_fp;
  3201. if( !(objType->flags & asOBJ_NOCOUNT) )
  3202. {
  3203. // Release previous object held by destination pointer
  3204. if( *d != 0 )
  3205. m_engine->CallObjectMethod(*d, beh->release);
  3206. // Increase ref counter of wanted object
  3207. if( s != 0 )
  3208. m_engine->CallObjectMethod(s, beh->addref);
  3209. }
  3210. // Set the new object in the destination
  3211. *d = s;
  3212. }
  3213. l_bc += 1+AS_PTR_SIZE;
  3214. break;
  3215. case asBC_JLowZ:
  3216. if( *(asBYTE*)&m_regs.valueRegister == 0 )
  3217. l_bc += asBC_INTARG(l_bc) + 2;
  3218. else
  3219. l_bc += 2;
  3220. break;
  3221. case asBC_JLowNZ:
  3222. if( *(asBYTE*)&m_regs.valueRegister != 0 )
  3223. l_bc += asBC_INTARG(l_bc) + 2;
  3224. else
  3225. l_bc += 2;
  3226. break;
  3227. // Don't let the optimizer optimize for size,
  3228. // since it requires extra conditions and jumps
  3229. case 189: l_bc = (asDWORD*)189; break;
  3230. case 190: l_bc = (asDWORD*)190; break;
  3231. case 191: l_bc = (asDWORD*)191; break;
  3232. case 192: l_bc = (asDWORD*)192; break;
  3233. case 193: l_bc = (asDWORD*)193; break;
  3234. case 194: l_bc = (asDWORD*)194; break;
  3235. case 195: l_bc = (asDWORD*)195; break;
  3236. case 196: l_bc = (asDWORD*)196; break;
  3237. case 197: l_bc = (asDWORD*)197; break;
  3238. case 198: l_bc = (asDWORD*)198; break;
  3239. case 199: l_bc = (asDWORD*)199; break;
  3240. case 200: l_bc = (asDWORD*)200; break;
  3241. case 201: l_bc = (asDWORD*)201; break;
  3242. case 202: l_bc = (asDWORD*)202; break;
  3243. case 203: l_bc = (asDWORD*)203; break;
  3244. case 204: l_bc = (asDWORD*)204; break;
  3245. case 205: l_bc = (asDWORD*)205; break;
  3246. case 206: l_bc = (asDWORD*)206; break;
  3247. case 207: l_bc = (asDWORD*)207; break;
  3248. case 208: l_bc = (asDWORD*)208; break;
  3249. case 209: l_bc = (asDWORD*)209; break;
  3250. case 210: l_bc = (asDWORD*)210; break;
  3251. case 211: l_bc = (asDWORD*)211; break;
  3252. case 212: l_bc = (asDWORD*)212; break;
  3253. case 213: l_bc = (asDWORD*)213; break;
  3254. case 214: l_bc = (asDWORD*)214; break;
  3255. case 215: l_bc = (asDWORD*)215; break;
  3256. case 216: l_bc = (asDWORD*)216; break;
  3257. case 217: l_bc = (asDWORD*)217; break;
  3258. case 218: l_bc = (asDWORD*)218; break;
  3259. case 219: l_bc = (asDWORD*)219; break;
  3260. case 220: l_bc = (asDWORD*)220; break;
  3261. case 221: l_bc = (asDWORD*)221; break;
  3262. case 222: l_bc = (asDWORD*)222; break;
  3263. case 223: l_bc = (asDWORD*)223; break;
  3264. case 224: l_bc = (asDWORD*)224; break;
  3265. case 225: l_bc = (asDWORD*)225; break;
  3266. case 226: l_bc = (asDWORD*)226; break;
  3267. case 227: l_bc = (asDWORD*)227; break;
  3268. case 228: l_bc = (asDWORD*)228; break;
  3269. case 229: l_bc = (asDWORD*)229; break;
  3270. case 230: l_bc = (asDWORD*)230; break;
  3271. case 231: l_bc = (asDWORD*)231; break;
  3272. case 232: l_bc = (asDWORD*)232; break;
  3273. case 233: l_bc = (asDWORD*)233; break;
  3274. case 234: l_bc = (asDWORD*)234; break;
  3275. case 235: l_bc = (asDWORD*)235; break;
  3276. case 236: l_bc = (asDWORD*)236; break;
  3277. case 237: l_bc = (asDWORD*)237; break;
  3278. case 238: l_bc = (asDWORD*)238; break;
  3279. case 239: l_bc = (asDWORD*)239; break;
  3280. case 240: l_bc = (asDWORD*)240; break;
  3281. case 241: l_bc = (asDWORD*)241; break;
  3282. case 242: l_bc = (asDWORD*)242; break;
  3283. case 243: l_bc = (asDWORD*)243; break;
  3284. case 244: l_bc = (asDWORD*)244; break;
  3285. case 245: l_bc = (asDWORD*)245; break;
  3286. case 246: l_bc = (asDWORD*)246; break;
  3287. case 247: l_bc = (asDWORD*)247; break;
  3288. case 248: l_bc = (asDWORD*)248; break;
  3289. case 249: l_bc = (asDWORD*)249; break;
  3290. case 250: l_bc = (asDWORD*)250; break;
  3291. case 251: l_bc = (asDWORD*)251; break;
  3292. case 252: l_bc = (asDWORD*)252; break;
  3293. case 253: l_bc = (asDWORD*)253; break;
  3294. case 254: l_bc = (asDWORD*)254; break;
  3295. case 255: l_bc = (asDWORD*)255; break;
  3296. #ifdef AS_DEBUG
  3297. default:
  3298. asASSERT(false);
  3299. SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
  3300. #endif
  3301. #if defined(_MSC_VER) && !defined(AS_DEBUG)
  3302. default:
  3303. // This Microsoft specific code allows the
  3304. // compiler to optimize the switch case as
  3305. // it will know that the code will never
  3306. // reach this point
  3307. __assume(0);
  3308. #endif
  3309. }
  3310. #ifdef AS_DEBUG
  3311. asDWORD instr = *(asBYTE*)old;
  3312. if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ &&
  3313. instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr &&
  3314. instr != asBC_JitEntry )
  3315. {
  3316. asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] );
  3317. }
  3318. #endif
  3319. }
  3320. }
  3321. int asCContext::SetException(const char *descr)
  3322. {
  3323. // Only allow this if we're executing a CALL byte code
  3324. if( m_callingSystemFunction == 0 ) return asERROR;
  3325. SetInternalException(descr);
  3326. return 0;
  3327. }
  3328. void asCContext::SetInternalException(const char *descr)
  3329. {
  3330. if( m_inExceptionHandler )
  3331. {
  3332. asASSERT(false); // Shouldn't happen
  3333. return; // but if it does, at least this will not crash the application
  3334. }
  3335. m_status = asEXECUTION_EXCEPTION;
  3336. m_regs.doProcessSuspend = true;
  3337. m_exceptionString = descr;
  3338. m_exceptionFunction = m_currentFunction->id;
  3339. m_exceptionLine = m_currentFunction->GetLineNumber(int(m_regs.programPointer - m_currentFunction->byteCode.AddressOf()), &m_exceptionSectionIdx);
  3340. m_exceptionColumn = m_exceptionLine >> 20;
  3341. m_exceptionLine &= 0xFFFFF;
  3342. if( m_exceptionCallback )
  3343. CallExceptionCallback();
  3344. }
  3345. void asCContext::CleanReturnObject()
  3346. {
  3347. if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED )
  3348. {
  3349. // If function returns on stack we need to call the destructor on the returned object
  3350. if( m_initialFunction->returnType.GetObjectType()->beh.destruct )
  3351. m_engine->CallObjectMethod(GetReturnObject(), m_initialFunction->returnType.GetObjectType()->beh.destruct);
  3352. return;
  3353. }
  3354. if( m_regs.objectRegister == 0 ) return;
  3355. asASSERT( m_regs.objectType != 0 );
  3356. if( m_regs.objectType )
  3357. {
  3358. // Call the destructor on the object
  3359. asSTypeBehaviour *beh = &((asCObjectType*)m_regs.objectType)->beh;
  3360. if( m_regs.objectType->GetFlags() & asOBJ_REF )
  3361. {
  3362. asASSERT( beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT) );
  3363. if( beh->release )
  3364. m_engine->CallObjectMethod(m_regs.objectRegister, beh->release);
  3365. m_regs.objectRegister = 0;
  3366. }
  3367. else
  3368. {
  3369. if( beh->destruct )
  3370. m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct);
  3371. // Free the memory
  3372. m_engine->CallFree(m_regs.objectRegister);
  3373. m_regs.objectRegister = 0;
  3374. }
  3375. }
  3376. }
  3377. void asCContext::CleanStack()
  3378. {
  3379. m_inExceptionHandler = true;
  3380. // Run the clean up code for each of the functions called
  3381. CleanStackFrame();
  3382. // Set the status to exception so that the stack unwind is done correctly.
  3383. // This shouldn't be done for the current function, which is why we only
  3384. // do this after the first CleanStackFrame() is done.
  3385. m_status = asEXECUTION_EXCEPTION;
  3386. while( m_callStack.GetLength() > 0 )
  3387. {
  3388. // Only clean up until the top most marker for a nested call
  3389. asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  3390. if( s[0] == 0 )
  3391. break;
  3392. PopCallState();
  3393. CleanStackFrame();
  3394. }
  3395. m_inExceptionHandler = false;
  3396. }
  3397. // Interface
  3398. bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel)
  3399. {
  3400. // Don't return anything if there is no bytecode, e.g. before calling Execute()
  3401. if( m_regs.programPointer == 0 ) return false;
  3402. if( stackLevel >= GetCallstackSize() ) return false;
  3403. asCScriptFunction *func;
  3404. asUINT pos;
  3405. if( stackLevel == 0 )
  3406. {
  3407. func = m_currentFunction;
  3408. pos = asUINT(m_regs.programPointer - func->byteCode.AddressOf());
  3409. }
  3410. else
  3411. {
  3412. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  3413. func = (asCScriptFunction*)s[1];
  3414. pos = asUINT((asDWORD*)s[2] - func->byteCode.AddressOf());
  3415. }
  3416. // First determine if the program position is after the variable declaration
  3417. if( func->variables.GetLength() <= varIndex ) return false;
  3418. if( func->variables[varIndex]->declaredAtProgramPos > pos ) return false;
  3419. asUINT declaredAt = func->variables[varIndex]->declaredAtProgramPos;
  3420. // If the program position is after the variable declaration it is necessary
  3421. // determine if the program position is still inside the statement block where
  3422. // the variable was delcared.
  3423. for( int n = 0; n < (int)func->objVariableInfo.GetLength(); n++ )
  3424. {
  3425. if( func->objVariableInfo[n].programPos >= declaredAt )
  3426. {
  3427. // If the current block ends between the declaredAt and current
  3428. // program position, then we know the variable is no longer visible
  3429. int level = 0;
  3430. for( ; n < (int)func->objVariableInfo.GetLength(); n++ )
  3431. {
  3432. if( func->objVariableInfo[n].programPos > pos )
  3433. break;
  3434. if( func->objVariableInfo[n].option == asBLOCK_BEGIN ) level++;
  3435. if( func->objVariableInfo[n].option == asBLOCK_END && --level < 0 )
  3436. return false;
  3437. }
  3438. break;
  3439. }
  3440. }
  3441. // Variable is visible
  3442. return true;
  3443. }
  3444. // Internal
  3445. void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel)
  3446. {
  3447. asASSERT( stackLevel < GetCallstackSize() );
  3448. asCScriptFunction *func;
  3449. asUINT pos;
  3450. if( stackLevel == 0 )
  3451. {
  3452. func = m_currentFunction;
  3453. pos = asUINT(m_regs.programPointer - func->byteCode.AddressOf());
  3454. if( m_status == asEXECUTION_EXCEPTION )
  3455. {
  3456. // Don't consider the last instruction as executed, as it failed with an exception
  3457. // It's not actually necessary to decrease the exact size of the instruction. Just
  3458. // before the current position is enough to disconsider it.
  3459. pos--;
  3460. }
  3461. }
  3462. else
  3463. {
  3464. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  3465. func = (asCScriptFunction*)s[1];
  3466. pos = asUINT((asDWORD*)s[2] - func->byteCode.AddressOf());
  3467. // Don't consider the last instruction as executed, as the function that was called by it
  3468. // is still being executed. If we consider it as executed already, then a value object
  3469. // returned by value would be considered alive, which it is not.
  3470. pos--;
  3471. }
  3472. // Determine which object variables that are really live ones
  3473. liveObjects.SetLength(func->objVariablePos.GetLength());
  3474. memset(liveObjects.AddressOf(), 0, sizeof(int)*liveObjects.GetLength());
  3475. for( int n = 0; n < (int)func->objVariableInfo.GetLength(); n++ )
  3476. {
  3477. // Find the first variable info with a larger position than the current
  3478. // As the variable info are always placed on the instruction right after the
  3479. // one that initialized or freed the object, the current position needs to be
  3480. // considered as valid.
  3481. if( func->objVariableInfo[n].programPos > pos )
  3482. {
  3483. // We've determined how far the execution ran, now determine which variables are alive
  3484. for( --n; n >= 0; n-- )
  3485. {
  3486. switch( func->objVariableInfo[n].option )
  3487. {
  3488. case asOBJ_UNINIT: // Object was destroyed
  3489. {
  3490. // TODO: optimize: This should have been done by the compiler already
  3491. // Which variable is this?
  3492. asUINT var = 0;
  3493. for( asUINT v = 0; v < func->objVariablePos.GetLength(); v++ )
  3494. if( func->objVariablePos[v] == func->objVariableInfo[n].variableOffset )
  3495. {
  3496. var = v;
  3497. break;
  3498. }
  3499. liveObjects[var] -= 1;
  3500. }
  3501. break;
  3502. case asOBJ_INIT: // Object was created
  3503. {
  3504. // Which variable is this?
  3505. asUINT var = 0;
  3506. for( asUINT v = 0; v < func->objVariablePos.GetLength(); v++ )
  3507. if( func->objVariablePos[v] == func->objVariableInfo[n].variableOffset )
  3508. {
  3509. var = v;
  3510. break;
  3511. }
  3512. liveObjects[var] += 1;
  3513. }
  3514. break;
  3515. case asBLOCK_BEGIN: // Start block
  3516. // We should ignore start blocks, since it just means the
  3517. // program was within the block when the exception ocurred
  3518. break;
  3519. case asBLOCK_END: // End block
  3520. // We need to skip the entire block, as the objects created
  3521. // and destroyed inside this block are already out of scope
  3522. {
  3523. int nested = 1;
  3524. while( nested > 0 )
  3525. {
  3526. int option = func->objVariableInfo[--n].option;
  3527. if( option == 3 )
  3528. nested++;
  3529. if( option == 2 )
  3530. nested--;
  3531. }
  3532. }
  3533. break;
  3534. }
  3535. }
  3536. // We're done with the investigation
  3537. break;
  3538. }
  3539. }
  3540. }
  3541. void asCContext::CleanArgsOnStack()
  3542. {
  3543. if( !m_needToCleanupArgs )
  3544. return;
  3545. // Find the instruction just before the current program pointer
  3546. asDWORD *instr = m_currentFunction->byteCode.AddressOf();
  3547. asDWORD *prevInstr = 0;
  3548. while( instr < m_regs.programPointer )
  3549. {
  3550. prevInstr = instr;
  3551. instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type];
  3552. }
  3553. // Determine what function was being called
  3554. asCScriptFunction *func = 0;
  3555. asBYTE bc = *(asBYTE*)prevInstr;
  3556. if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF )
  3557. {
  3558. int funcId = asBC_INTARG(prevInstr);
  3559. func = m_engine->scriptFunctions[funcId];
  3560. }
  3561. else if( bc == asBC_CALLBND )
  3562. {
  3563. int funcId = asBC_INTARG(prevInstr);
  3564. func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
  3565. }
  3566. else if( bc == asBC_CallPtr )
  3567. {
  3568. asUINT v;
  3569. int var = asBC_SWORDARG0(prevInstr);
  3570. // Find the funcdef from the local variable
  3571. for( v = 0; v < m_currentFunction->objVariablePos.GetLength(); v++ )
  3572. if( m_currentFunction->objVariablePos[v] == var )
  3573. {
  3574. func = m_currentFunction->funcVariableTypes[v];
  3575. break;
  3576. }
  3577. if( func == 0 )
  3578. {
  3579. // Look in parameters
  3580. int paramPos = 0;
  3581. if( m_currentFunction->objectType )
  3582. paramPos -= AS_PTR_SIZE;
  3583. if( m_currentFunction->DoesReturnOnStack() )
  3584. paramPos -= AS_PTR_SIZE;
  3585. for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ )
  3586. {
  3587. if( var == paramPos )
  3588. {
  3589. func = m_currentFunction->parameterTypes[v].GetFuncDef();
  3590. break;
  3591. }
  3592. paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords();
  3593. }
  3594. }
  3595. }
  3596. else
  3597. asASSERT( false );
  3598. asASSERT( func );
  3599. // Clean parameters
  3600. int offset = 0;
  3601. if( func->objectType )
  3602. offset += AS_PTR_SIZE;
  3603. if( func->DoesReturnOnStack() )
  3604. offset += AS_PTR_SIZE;
  3605. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  3606. {
  3607. if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsReference() )
  3608. {
  3609. if( *(asPWORD*)&m_regs.stackPointer[offset] )
  3610. {
  3611. // Call the object's destructor
  3612. asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour();
  3613. if( func->parameterTypes[n].GetObjectType()->flags & asOBJ_REF )
  3614. {
  3615. asASSERT( (func->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
  3616. if( beh->release )
  3617. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release);
  3618. *(asPWORD*)&m_regs.stackPointer[offset] = 0;
  3619. }
  3620. else
  3621. {
  3622. if( beh->destruct )
  3623. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct);
  3624. // Free the memory
  3625. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]);
  3626. *(asPWORD*)&m_regs.stackPointer[offset] = 0;
  3627. }
  3628. }
  3629. }
  3630. offset += func->parameterTypes[n].GetSizeOnStackDWords();
  3631. }
  3632. m_needToCleanupArgs = false;
  3633. }
  3634. void asCContext::CleanStackFrame()
  3635. {
  3636. // Clean object variables on the stack
  3637. // If the stack memory is not allocated or the program pointer
  3638. // is not set, then there is nothing to clean up on the stack frame
  3639. if( !m_isStackMemoryNotAllocated && m_regs.programPointer )
  3640. {
  3641. // If the exception occurred while calling a function it is necessary
  3642. // to clean up the arguments that were put on the stack.
  3643. CleanArgsOnStack();
  3644. // Restore the stack pointer
  3645. m_regs.stackPointer += m_currentFunction->variableSpace;
  3646. // Determine which object variables that are really live ones
  3647. asCArray<int> liveObjects;
  3648. DetermineLiveObjects(liveObjects, 0);
  3649. for( asUINT n = 0; n < m_currentFunction->objVariablePos.GetLength(); n++ )
  3650. {
  3651. int pos = m_currentFunction->objVariablePos[n];
  3652. if( n < m_currentFunction->objVariablesOnHeap )
  3653. {
  3654. // Check if the pointer is initialized
  3655. if( *(asPWORD*)&m_regs.stackFramePointer[-pos] )
  3656. {
  3657. // Call the object's destructor
  3658. asSTypeBehaviour *beh = &m_currentFunction->objVariableTypes[n]->beh;
  3659. if( m_currentFunction->objVariableTypes[n]->flags & asOBJ_REF )
  3660. {
  3661. asASSERT( (m_currentFunction->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release );
  3662. if( beh->release )
  3663. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release);
  3664. *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
  3665. }
  3666. else
  3667. {
  3668. if( beh->destruct )
  3669. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
  3670. // Free the memory
  3671. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]);
  3672. *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
  3673. }
  3674. }
  3675. }
  3676. else
  3677. {
  3678. asASSERT( m_currentFunction->objVariableTypes[n]->GetFlags() & asOBJ_VALUE );
  3679. // Only destroy the object if it is truly alive
  3680. if( liveObjects[n] > 0 )
  3681. {
  3682. asSTypeBehaviour *beh = &m_currentFunction->objVariableTypes[n]->beh;
  3683. if( beh->destruct )
  3684. m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
  3685. }
  3686. }
  3687. }
  3688. // If the object is a script declared object, then we must release it
  3689. // as the compiler adds a reference at the entry of the function. Make sure
  3690. // the function has actually been entered
  3691. if( m_currentFunction->objectType && m_regs.programPointer != m_currentFunction->byteCode.AddressOf() )
  3692. {
  3693. // Methods returning a reference or constructors don't add a reference
  3694. if( !m_currentFunction->returnType.IsReference() && m_currentFunction->name != m_currentFunction->objectType->name )
  3695. {
  3696. asSTypeBehaviour *beh = &m_currentFunction->objectType->beh;
  3697. if( beh->release && *(asPWORD*)&m_regs.stackFramePointer[0] != 0 )
  3698. {
  3699. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[0], beh->release);
  3700. *(asPWORD*)&m_regs.stackFramePointer[0] = 0;
  3701. }
  3702. }
  3703. }
  3704. }
  3705. else
  3706. m_isStackMemoryNotAllocated = false;
  3707. // Functions that do not own the object and parameters shouldn't do any clean up
  3708. if( m_currentFunction->dontCleanUpOnException )
  3709. return;
  3710. // Clean object and parameters
  3711. int offset = 0;
  3712. if( m_currentFunction->objectType )
  3713. offset += AS_PTR_SIZE;
  3714. if( m_currentFunction->DoesReturnOnStack() )
  3715. offset += AS_PTR_SIZE;
  3716. for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ )
  3717. {
  3718. if( m_currentFunction->parameterTypes[n].IsObject() && !m_currentFunction->parameterTypes[n].IsReference() )
  3719. {
  3720. if( *(asPWORD*)&m_regs.stackFramePointer[offset] )
  3721. {
  3722. // Call the object's destructor
  3723. asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour();
  3724. if( m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF )
  3725. {
  3726. asASSERT( (m_currentFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
  3727. if( beh->release )
  3728. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release);
  3729. *(asPWORD*)&m_regs.stackFramePointer[offset] = 0;
  3730. }
  3731. else
  3732. {
  3733. if( beh->destruct )
  3734. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->destruct);
  3735. // Free the memory
  3736. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]);
  3737. *(asPWORD*)&m_regs.stackFramePointer[offset] = 0;
  3738. }
  3739. }
  3740. }
  3741. offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords();
  3742. }
  3743. }
  3744. // interface
  3745. int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
  3746. {
  3747. if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
  3748. if( column ) *column = m_exceptionColumn;
  3749. if( sectionName )
  3750. {
  3751. // The section index can be -1 if the exception was raised in a generated function, e.g. factstub for templates
  3752. if( m_exceptionSectionIdx >= 0 )
  3753. *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf();
  3754. else
  3755. *sectionName = 0;
  3756. }
  3757. return m_exceptionLine;
  3758. }
  3759. // interface
  3760. asIScriptFunction *asCContext::GetExceptionFunction()
  3761. {
  3762. if( GetState() != asEXECUTION_EXCEPTION ) return 0;
  3763. return m_engine->scriptFunctions[m_exceptionFunction];
  3764. }
  3765. // interface
  3766. const char *asCContext::GetExceptionString()
  3767. {
  3768. if( GetState() != asEXECUTION_EXCEPTION ) return 0;
  3769. return m_exceptionString.AddressOf();
  3770. }
  3771. // interface
  3772. asEContextState asCContext::GetState() const
  3773. {
  3774. return m_status;
  3775. }
  3776. // interface
  3777. int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
  3778. {
  3779. m_lineCallback = true;
  3780. m_regs.doProcessSuspend = true;
  3781. m_lineCallbackObj = obj;
  3782. bool isObj = false;
  3783. if( (unsigned)callConv == asCALL_GENERIC )
  3784. {
  3785. m_lineCallback = false;
  3786. m_regs.doProcessSuspend = m_doSuspend;
  3787. return asNOT_SUPPORTED;
  3788. }
  3789. if( (unsigned)callConv >= asCALL_THISCALL )
  3790. {
  3791. isObj = true;
  3792. if( obj == 0 )
  3793. {
  3794. m_lineCallback = false;
  3795. m_regs.doProcessSuspend = m_doSuspend;
  3796. return asINVALID_ARG;
  3797. }
  3798. }
  3799. int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc);
  3800. if( r < 0 ) m_lineCallback = false;
  3801. m_regs.doProcessSuspend = m_doSuspend || m_lineCallback;
  3802. return r;
  3803. }
  3804. void asCContext::CallLineCallback()
  3805. {
  3806. if( m_lineCallbackFunc.callConv < ICC_THISCALL )
  3807. m_engine->CallGlobalFunction(this, m_lineCallbackObj, &m_lineCallbackFunc, 0);
  3808. else
  3809. m_engine->CallObjectMethod(m_lineCallbackObj, this, &m_lineCallbackFunc, 0);
  3810. }
  3811. // interface
  3812. int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv)
  3813. {
  3814. m_exceptionCallback = true;
  3815. m_exceptionCallbackObj = obj;
  3816. bool isObj = false;
  3817. if( (unsigned)callConv == asCALL_GENERIC )
  3818. return asNOT_SUPPORTED;
  3819. if( (unsigned)callConv >= asCALL_THISCALL )
  3820. {
  3821. isObj = true;
  3822. if( obj == 0 )
  3823. {
  3824. m_exceptionCallback = false;
  3825. return asINVALID_ARG;
  3826. }
  3827. }
  3828. int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_exceptionCallbackFunc);
  3829. if( r < 0 ) m_exceptionCallback = false;
  3830. return r;
  3831. }
  3832. void asCContext::CallExceptionCallback()
  3833. {
  3834. if( m_exceptionCallbackFunc.callConv < ICC_THISCALL )
  3835. m_engine->CallGlobalFunction(this, m_exceptionCallbackObj, &m_exceptionCallbackFunc, 0);
  3836. else
  3837. m_engine->CallObjectMethod(m_exceptionCallbackObj, this, &m_exceptionCallbackFunc, 0);
  3838. }
  3839. // interface
  3840. void asCContext::ClearLineCallback()
  3841. {
  3842. m_lineCallback = false;
  3843. m_regs.doProcessSuspend = m_doSuspend;
  3844. }
  3845. // interface
  3846. void asCContext::ClearExceptionCallback()
  3847. {
  3848. m_exceptionCallback = false;
  3849. }
  3850. int asCContext::CallGeneric(int id, void *objectPointer)
  3851. {
  3852. asCScriptFunction *sysFunction = m_engine->scriptFunctions[id];
  3853. asSSystemFunctionInterface *sysFunc = sysFunction->sysFuncIntf;
  3854. void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func;
  3855. int popSize = sysFunc->paramSize;
  3856. asDWORD *args = m_regs.stackPointer;
  3857. // Verify the object pointer if it is a class method
  3858. void *currentObject = 0;
  3859. if( sysFunc->callConv == ICC_GENERIC_METHOD )
  3860. {
  3861. if( objectPointer )
  3862. {
  3863. currentObject = objectPointer;
  3864. // Don't increase the reference of this pointer
  3865. // since it will not have been constructed yet
  3866. }
  3867. else
  3868. {
  3869. // The object pointer should be popped from the context stack
  3870. popSize += AS_PTR_SIZE;
  3871. // Check for null pointer
  3872. currentObject = (void*)*(asPWORD*)(args);
  3873. if( currentObject == 0 )
  3874. {
  3875. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3876. return 0;
  3877. }
  3878. // Add the base offset for multiple inheritance
  3879. currentObject = (void*)(asPWORD(currentObject) + sysFunc->baseOffset);
  3880. // Skip object pointer
  3881. args += AS_PTR_SIZE;
  3882. }
  3883. }
  3884. if( sysFunction->DoesReturnOnStack() )
  3885. {
  3886. // Skip the address where the return value will be stored
  3887. args += AS_PTR_SIZE;
  3888. popSize += AS_PTR_SIZE;
  3889. }
  3890. asCGeneric gen(m_engine, sysFunction, currentObject, args);
  3891. m_callingSystemFunction = sysFunction;
  3892. func(&gen);
  3893. m_callingSystemFunction = 0;
  3894. m_regs.valueRegister = gen.returnVal;
  3895. m_regs.objectRegister = gen.objectRegister;
  3896. m_regs.objectType = sysFunction->returnType.GetObjectType();
  3897. // Clean up function parameters
  3898. int offset = 0;
  3899. for( asUINT n = 0; n < sysFunction->parameterTypes.GetLength(); n++ )
  3900. {
  3901. if( sysFunction->parameterTypes[n].IsObject() && !sysFunction->parameterTypes[n].IsReference() )
  3902. {
  3903. void *obj = *(void**)&args[offset];
  3904. if( obj )
  3905. {
  3906. // Release the object
  3907. asSTypeBehaviour *beh = &sysFunction->parameterTypes[n].GetObjectType()->beh;
  3908. if( sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF )
  3909. {
  3910. asASSERT( (sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
  3911. if( beh->release )
  3912. m_engine->CallObjectMethod(obj, beh->release);
  3913. }
  3914. else
  3915. {
  3916. // Call the destructor then free the memory
  3917. if( beh->destruct )
  3918. m_engine->CallObjectMethod(obj, beh->destruct);
  3919. m_engine->CallFree(obj);
  3920. }
  3921. }
  3922. }
  3923. offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
  3924. }
  3925. // Return how much should be popped from the stack
  3926. return popSize;
  3927. }
  3928. // interface
  3929. int asCContext::GetVarCount(asUINT stackLevel)
  3930. {
  3931. asIScriptFunction *func = GetFunction(stackLevel);
  3932. if( func == 0 ) return asINVALID_ARG;
  3933. return func->GetVarCount();
  3934. }
  3935. // interface
  3936. const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel)
  3937. {
  3938. asIScriptFunction *func = GetFunction(stackLevel);
  3939. if( func == 0 ) return 0;
  3940. const char *name = 0;
  3941. int r = func->GetVar(varIndex, &name);
  3942. return r >= 0 ? name : 0;
  3943. }
  3944. // interface
  3945. const char *asCContext::GetVarDeclaration(asUINT varIndex, asUINT stackLevel)
  3946. {
  3947. asIScriptFunction *func = GetFunction(stackLevel);
  3948. if( func == 0 ) return 0;
  3949. return func->GetVarDecl(varIndex);
  3950. }
  3951. // interface
  3952. int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel)
  3953. {
  3954. asIScriptFunction *func = GetFunction(stackLevel);
  3955. if( func == 0 ) return asINVALID_ARG;
  3956. int typeId;
  3957. int r = func->GetVar(varIndex, 0, &typeId);
  3958. return r < 0 ? r : typeId;
  3959. }
  3960. // interface
  3961. void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel)
  3962. {
  3963. // Don't return anything if there is no bytecode, e.g. before calling Execute()
  3964. if( m_regs.programPointer == 0 ) return 0;
  3965. if( stackLevel >= GetCallstackSize() ) return 0;
  3966. asCScriptFunction *func;
  3967. asDWORD *sf;
  3968. if( stackLevel == 0 )
  3969. {
  3970. func = m_currentFunction;
  3971. sf = m_regs.stackFramePointer;
  3972. }
  3973. else
  3974. {
  3975. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  3976. func = (asCScriptFunction*)s[1];
  3977. sf = (asDWORD*)s[0];
  3978. }
  3979. if( func == 0 )
  3980. return 0;
  3981. if( varIndex >= func->variables.GetLength() )
  3982. return 0;
  3983. // For object variables it's necessary to dereference the pointer to get the address of the value
  3984. // Reference parameters must also be dereferenced to give the address of the value
  3985. int pos = func->variables[varIndex]->stackOffset;
  3986. if( (func->variables[varIndex]->type.IsObject() && !func->variables[varIndex]->type.IsObjectHandle()) || (pos <= 0) )
  3987. {
  3988. // Determine if the object is really on the heap
  3989. bool onHeap = false;
  3990. if( func->variables[varIndex]->type.IsObject() &&
  3991. !func->variables[varIndex]->type.IsObjectHandle() )
  3992. {
  3993. onHeap = true;
  3994. if( func->variables[varIndex]->type.GetObjectType()->GetFlags() & asOBJ_VALUE )
  3995. {
  3996. for( asUINT n = 0; n < func->objVariablePos.GetLength(); n++ )
  3997. {
  3998. if( func->objVariablePos[n] == pos )
  3999. {
  4000. onHeap = n < func->objVariablesOnHeap;
  4001. if( !onHeap )
  4002. {
  4003. // If the object on the stack is not initialized return a null pointer instead
  4004. asCArray<int> liveObjects;
  4005. DetermineLiveObjects(liveObjects, stackLevel);
  4006. if( liveObjects[n] <= 0 )
  4007. return 0;
  4008. }
  4009. break;
  4010. }
  4011. }
  4012. }
  4013. }
  4014. // If it wasn't an object on the heap, then check if it is a reference parameter
  4015. if( !onHeap && pos <= 0 )
  4016. {
  4017. // Determine what function argument this position matches
  4018. int stackPos = 0;
  4019. if( func->objectType )
  4020. stackPos -= AS_PTR_SIZE;
  4021. if( func->DoesReturnOnStack() )
  4022. stackPos -= AS_PTR_SIZE;
  4023. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  4024. {
  4025. if( stackPos == pos )
  4026. {
  4027. // The right argument was found. Is this a reference parameter?
  4028. if( func->inOutFlags[n] != asTM_NONE )
  4029. onHeap = true;
  4030. break;
  4031. }
  4032. stackPos -= func->parameterTypes[n].GetSizeOnStackDWords();
  4033. }
  4034. }
  4035. if( onHeap )
  4036. return *(void**)(sf - func->variables[varIndex]->stackOffset);
  4037. }
  4038. return sf - func->variables[varIndex]->stackOffset;
  4039. }
  4040. // interface
  4041. // returns the typeId of the 'this' object at the given call stack level (-1 for current)
  4042. // returns 0 if the function call at the given stack level is not a method
  4043. int asCContext::GetThisTypeId(asUINT stackLevel)
  4044. {
  4045. asIScriptFunction *func = GetFunction(stackLevel);
  4046. if( func == 0 ) return asINVALID_ARG;
  4047. if( func->GetObjectType() == 0 )
  4048. return 0; // not in a method
  4049. // create a datatype
  4050. asCDataType dt = asCDataType::CreateObject((asCObjectType*)func->GetObjectType(), false);
  4051. // return a typeId from the data type
  4052. return m_engine->GetTypeIdFromDataType(dt);
  4053. }
  4054. // interface
  4055. // returns the 'this' object pointer at the given call stack level (-1 for current)
  4056. // returns 0 if the function call at the given stack level is not a method
  4057. void *asCContext::GetThisPointer(asUINT stackLevel)
  4058. {
  4059. if( stackLevel >= GetCallstackSize() )
  4060. return 0;
  4061. asCScriptFunction *func;
  4062. asDWORD *sf;
  4063. if( stackLevel == 0 )
  4064. {
  4065. func = m_currentFunction;
  4066. sf = m_regs.stackFramePointer;
  4067. }
  4068. else
  4069. {
  4070. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  4071. func = (asCScriptFunction*)s[1];
  4072. sf = (asDWORD*)s[0];
  4073. }
  4074. if( func == 0 )
  4075. return 0;
  4076. if( func->objectType == 0 )
  4077. return 0; // not in a method
  4078. void *thisPointer = (void*)*(asPWORD*)(sf);
  4079. if( thisPointer == 0 )
  4080. {
  4081. return 0;
  4082. }
  4083. // NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return
  4084. // a pointer to a pointer. I can't imagine someone would want to change the 'this'
  4085. return thisPointer;
  4086. }
  4087. END_AS_NAMESPACE