as_context.cpp 115 KB

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