as_context.cpp 164 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2021 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_context.cpp
  25. //
  26. // This class handles the execution of the byte code
  27. //
  28. #include <math.h> // fmodf() pow()
  29. #include "as_config.h"
  30. #include "as_context.h"
  31. #include "as_scriptengine.h"
  32. #include "as_tokendef.h"
  33. #include "as_texts.h"
  34. #include "as_callfunc.h"
  35. #include "as_generic.h"
  36. #include "as_debug.h" // mkdir()
  37. #include "as_bytecode.h"
  38. #include "as_scriptobject.h"
  39. #ifdef _MSC_VER
  40. #pragma warning(disable:4702) // unreachable code
  41. #endif
  42. BEGIN_AS_NAMESPACE
  43. // We need at least 2 PTRs reserved for exception handling
  44. // We need at least 1 PTR reserved for calling system functions
  45. const int RESERVE_STACK = 2*AS_PTR_SIZE;
  46. // For each script function call we push 9 PTRs on the call stack
  47. const int CALLSTACK_FRAME_SIZE = 9;
  48. #if defined(AS_DEBUG)
  49. class asCDebugStats
  50. {
  51. public:
  52. asCDebugStats()
  53. {
  54. memset(instrCount, 0, sizeof(instrCount));
  55. memset(instrCount2, 0, sizeof(instrCount2));
  56. lastBC = 255;
  57. }
  58. ~asCDebugStats()
  59. {
  60. // This code writes out some statistics for the VM.
  61. // It's useful for determining what needs to be optimized.
  62. #ifndef __MINGW32__
  63. // _mkdir is broken on mingw
  64. _mkdir("AS_DEBUG");
  65. #endif
  66. #if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
  67. FILE *f;
  68. fopen_s(&f, "AS_DEBUG/stats.txt", "wt");
  69. #else
  70. FILE *f = fopen("AS_DEBUG/stats.txt", "wt");
  71. #endif
  72. if( f )
  73. {
  74. // Output instruction statistics
  75. fprintf(f, "\nTotal count\n");
  76. int n;
  77. for( n = 0; n < asBC_MAXBYTECODE; n++ )
  78. {
  79. if( asBCInfo[n].name && instrCount[n] > 0 )
  80. fprintf(f, "%-10.10s : %.0f\n", asBCInfo[n].name, instrCount[n]);
  81. }
  82. fprintf(f, "\nNever executed\n");
  83. for( n = 0; n < asBC_MAXBYTECODE; n++ )
  84. {
  85. if( asBCInfo[n].name && instrCount[n] == 0 )
  86. fprintf(f, "%-10.10s\n", asBCInfo[n].name);
  87. }
  88. fprintf(f, "\nSequences\n");
  89. for( n = 0; n < 256; n++ )
  90. {
  91. if( asBCInfo[n].name )
  92. {
  93. for( int m = 0; m < 256; m++ )
  94. {
  95. if( instrCount2[n][m] )
  96. fprintf(f, "%-10.10s, %-10.10s : %.0f\n", asBCInfo[n].name, asBCInfo[m].name, instrCount2[n][m]);
  97. }
  98. }
  99. }
  100. fclose(f);
  101. }
  102. }
  103. void Instr(asBYTE bc)
  104. {
  105. ++instrCount[bc];
  106. ++instrCount2[lastBC][bc];
  107. lastBC = bc;
  108. }
  109. // Instruction statistics
  110. double instrCount[256];
  111. double instrCount2[256][256];
  112. int lastBC;
  113. } stats;
  114. #endif
  115. // interface
  116. AS_API asIScriptContext *asGetActiveContext()
  117. {
  118. asCThreadLocalData *tld = asCThreadManager::GetLocalData();
  119. // tld can be 0 if asGetActiveContext is called before any engine has been created.
  120. // Observe! I've seen a case where an application linked with the library twice
  121. // and thus ended up with two separate instances of the code and global variables.
  122. // The application somehow mixed the two instances so that a function called from
  123. // a script ended up calling asGetActiveContext from the other instance that had
  124. // never been initialized.
  125. if( tld == 0 || tld->activeContexts.GetLength() == 0 )
  126. return 0;
  127. return tld->activeContexts[tld->activeContexts.GetLength()-1];
  128. }
  129. // internal
  130. asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx)
  131. {
  132. asCThreadLocalData *tld = asCThreadManager::GetLocalData();
  133. asASSERT( tld );
  134. if( tld == 0 )
  135. return 0;
  136. tld->activeContexts.PushLast(ctx);
  137. return tld;
  138. }
  139. // internal
  140. void asPopActiveContext(asCThreadLocalData *tld, asIScriptContext *ctx)
  141. {
  142. UNUSED_VAR(ctx);
  143. asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx);
  144. if (tld)
  145. tld->activeContexts.PopLast();
  146. }
  147. asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
  148. {
  149. m_refCount.set(1);
  150. m_holdEngineRef = holdRef;
  151. if( holdRef )
  152. engine->AddRef();
  153. m_engine = engine;
  154. m_status = asEXECUTION_UNINITIALIZED;
  155. m_stackBlockSize = 0;
  156. m_originalStackPointer = 0;
  157. m_inExceptionHandler = false;
  158. m_isStackMemoryNotAllocated = false;
  159. m_needToCleanupArgs = false;
  160. m_currentFunction = 0;
  161. m_callingSystemFunction = 0;
  162. m_regs.objectRegister = 0;
  163. m_initialFunction = 0;
  164. m_lineCallback = false;
  165. m_exceptionCallback = false;
  166. m_regs.doProcessSuspend = false;
  167. m_doSuspend = false;
  168. m_userData = 0;
  169. m_regs.ctx = this;
  170. m_exceptionWillBeCaught = false;
  171. }
  172. asCContext::~asCContext()
  173. {
  174. DetachEngine();
  175. }
  176. // interface
  177. bool asCContext::IsNested(asUINT *nestCount) const
  178. {
  179. if( nestCount )
  180. *nestCount = 0;
  181. asUINT c = GetCallstackSize();
  182. if( c == 0 )
  183. return false;
  184. // Search for a marker on the call stack
  185. // This loop starts at 2 because the 0th entry is not stored in m_callStack,
  186. // and then we need to subtract one more to get the base of each frame
  187. for( asUINT n = 2; n <= c; n++ )
  188. {
  189. const asPWORD *s = m_callStack.AddressOf() + (c - n)*CALLSTACK_FRAME_SIZE;
  190. if( s && s[0] == 0 )
  191. {
  192. if( nestCount )
  193. (*nestCount)++;
  194. else
  195. return true;
  196. }
  197. }
  198. if( nestCount && *nestCount > 0 )
  199. return true;
  200. return false;
  201. }
  202. // interface
  203. int asCContext::AddRef() const
  204. {
  205. return m_refCount.atomicInc();
  206. }
  207. // interface
  208. int asCContext::Release() const
  209. {
  210. int r = m_refCount.atomicDec();
  211. if( r == 0 )
  212. {
  213. asDELETE(const_cast<asCContext*>(this),asCContext);
  214. return 0;
  215. }
  216. return r;
  217. }
  218. // internal
  219. void asCContext::DetachEngine()
  220. {
  221. if( m_engine == 0 ) return;
  222. // Clean up all calls, included nested ones
  223. do
  224. {
  225. // Abort any execution
  226. Abort();
  227. // Free all resources
  228. Unprepare();
  229. }
  230. while( IsNested() );
  231. // Free the stack blocks
  232. for( asUINT n = 0; n < m_stackBlocks.GetLength(); n++ )
  233. {
  234. if( m_stackBlocks[n] )
  235. {
  236. #ifndef WIP_16BYTE_ALIGN
  237. asDELETEARRAY(m_stackBlocks[n]);
  238. #else
  239. asDELETEARRAYALIGNED(m_stackBlocks[n]);
  240. #endif
  241. }
  242. }
  243. m_stackBlocks.SetLength(0);
  244. m_stackBlockSize = 0;
  245. // Clean the user data
  246. for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
  247. {
  248. if( m_userData[n+1] )
  249. {
  250. for( asUINT c = 0; c < m_engine->cleanContextFuncs.GetLength(); c++ )
  251. if( m_engine->cleanContextFuncs[c].type == m_userData[n] )
  252. m_engine->cleanContextFuncs[c].cleanFunc(this);
  253. }
  254. }
  255. m_userData.SetLength(0);
  256. // Clear engine pointer
  257. if( m_holdEngineRef )
  258. m_engine->Release();
  259. m_engine = 0;
  260. }
  261. // interface
  262. asIScriptEngine *asCContext::GetEngine() const
  263. {
  264. return m_engine;
  265. }
  266. // interface
  267. void *asCContext::SetUserData(void *data, asPWORD type)
  268. {
  269. // As a thread might add a new new user data at the same time as another
  270. // it is necessary to protect both read and write access to the userData member
  271. ACQUIREEXCLUSIVE(m_engine->engineRWLock);
  272. // It is not intended to store a lot of different types of userdata,
  273. // so a more complex structure like a associative map would just have
  274. // more overhead than a simple array.
  275. for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
  276. {
  277. if( m_userData[n] == type )
  278. {
  279. void *oldData = reinterpret_cast<void*>(m_userData[n+1]);
  280. m_userData[n+1] = reinterpret_cast<asPWORD>(data);
  281. RELEASEEXCLUSIVE(m_engine->engineRWLock);
  282. return oldData;
  283. }
  284. }
  285. m_userData.PushLast(type);
  286. m_userData.PushLast(reinterpret_cast<asPWORD>(data));
  287. RELEASEEXCLUSIVE(m_engine->engineRWLock);
  288. return 0;
  289. }
  290. // interface
  291. void *asCContext::GetUserData(asPWORD type) const
  292. {
  293. // There may be multiple threads reading, but when
  294. // setting the user data nobody must be reading.
  295. ACQUIRESHARED(m_engine->engineRWLock);
  296. for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
  297. {
  298. if( m_userData[n] == type )
  299. {
  300. RELEASESHARED(m_engine->engineRWLock);
  301. return reinterpret_cast<void*>(m_userData[n+1]);
  302. }
  303. }
  304. RELEASESHARED(m_engine->engineRWLock);
  305. return 0;
  306. }
  307. // interface
  308. asIScriptFunction *asCContext::GetSystemFunction()
  309. {
  310. return m_callingSystemFunction;
  311. }
  312. // interface
  313. int asCContext::Prepare(asIScriptFunction *func)
  314. {
  315. if( func == 0 )
  316. {
  317. asCString str;
  318. str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", "null", errorNames[-asNO_FUNCTION], asNO_FUNCTION);
  319. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  320. return asNO_FUNCTION;
  321. }
  322. if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
  323. {
  324. asCString str;
  325. str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asCONTEXT_ACTIVE], asCONTEXT_ACTIVE);
  326. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  327. return asCONTEXT_ACTIVE;
  328. }
  329. // Clean the stack if not done before
  330. if( m_status != asEXECUTION_FINISHED && m_status != asEXECUTION_UNINITIALIZED )
  331. CleanStack();
  332. // Release the returned object (if any)
  333. CleanReturnObject();
  334. // Release the object if it is a script object
  335. if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
  336. {
  337. asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
  338. if( obj )
  339. obj->Release();
  340. *(asPWORD*)&m_regs.stackFramePointer[0] = 0;
  341. }
  342. if( m_initialFunction && m_initialFunction == func )
  343. {
  344. // If the same function is executed again, we can skip a lot of the setup
  345. m_currentFunction = m_initialFunction;
  346. // Reset stack pointer
  347. m_regs.stackPointer = m_originalStackPointer;
  348. // Make sure the stack pointer is pointing to the original position,
  349. // otherwise something is wrong with the way it is being updated
  350. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  351. }
  352. else
  353. {
  354. asASSERT( m_engine );
  355. // Make sure the function is from the same engine as the context to avoid mixups
  356. if( m_engine != func->GetEngine() )
  357. {
  358. asCString str;
  359. str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asINVALID_ARG], asINVALID_ARG);
  360. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  361. return asINVALID_ARG;
  362. }
  363. if( m_initialFunction )
  364. {
  365. m_initialFunction->Release();
  366. // Reset stack pointer
  367. m_regs.stackPointer = m_originalStackPointer;
  368. // Make sure the stack pointer is pointing to the original position,
  369. // otherwise something is wrong with the way it is being updated
  370. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  371. }
  372. // We trust the application not to pass anything else but a asCScriptFunction
  373. m_initialFunction = reinterpret_cast<asCScriptFunction *>(func);
  374. m_initialFunction->AddRef();
  375. m_currentFunction = m_initialFunction;
  376. // TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed
  377. m_argumentsSize = m_currentFunction->GetSpaceNeededForArguments() + (m_currentFunction->objectType ? AS_PTR_SIZE : 0);
  378. // Reserve space for the arguments and return value
  379. if( m_currentFunction->DoesReturnOnStack() )
  380. {
  381. m_returnValueSize = m_currentFunction->returnType.GetSizeInMemoryDWords();
  382. m_argumentsSize += AS_PTR_SIZE;
  383. }
  384. else
  385. m_returnValueSize = 0;
  386. // Determine the minimum stack size needed
  387. int stackSize = m_argumentsSize + m_returnValueSize;
  388. if( m_currentFunction->scriptData )
  389. stackSize += m_currentFunction->scriptData->stackNeeded;
  390. // Make sure there is enough space on the stack for the arguments and return value
  391. if( !ReserveStackSpace(stackSize) )
  392. return asOUT_OF_MEMORY;
  393. // Set up the call stack too
  394. if (m_callStack.GetCapacity() < m_engine->ep.initCallStackSize)
  395. m_callStack.AllocateNoConstruct(m_engine->ep.initCallStackSize * CALLSTACK_FRAME_SIZE, true);
  396. }
  397. // Reset state
  398. // Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized
  399. if( m_status != asEXECUTION_FINISHED )
  400. {
  401. m_exceptionLine = -1;
  402. m_exceptionFunction = 0;
  403. m_doAbort = false;
  404. m_doSuspend = false;
  405. m_regs.doProcessSuspend = m_lineCallback;
  406. m_externalSuspendRequest = false;
  407. }
  408. m_status = asEXECUTION_PREPARED;
  409. m_regs.programPointer = 0;
  410. // Reserve space for the arguments and return value
  411. m_regs.stackFramePointer = m_regs.stackPointer - m_argumentsSize - m_returnValueSize;
  412. m_originalStackPointer = m_regs.stackPointer;
  413. m_regs.stackPointer = m_regs.stackFramePointer;
  414. // Set arguments to 0
  415. memset(m_regs.stackPointer, 0, 4*m_argumentsSize);
  416. if( m_returnValueSize )
  417. {
  418. // Set the address of the location where the return value should be put
  419. asDWORD *ptr = m_regs.stackFramePointer;
  420. if( m_currentFunction->objectType )
  421. ptr += AS_PTR_SIZE;
  422. *(void**)ptr = (void*)(m_regs.stackFramePointer + m_argumentsSize);
  423. }
  424. return asSUCCESS;
  425. }
  426. // Free all resources
  427. int asCContext::Unprepare()
  428. {
  429. if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
  430. return asCONTEXT_ACTIVE;
  431. // Set the context as active so that any clean up code can use access it if desired
  432. asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this);
  433. asDWORD count = m_refCount.get();
  434. UNUSED_VAR(count);
  435. // Only clean the stack if the context was prepared but not executed until the end
  436. if( m_status != asEXECUTION_UNINITIALIZED &&
  437. m_status != asEXECUTION_FINISHED )
  438. CleanStack();
  439. asASSERT( m_needToCleanupArgs == false );
  440. // Release the returned object (if any)
  441. CleanReturnObject();
  442. // TODO: Unprepare is called during destruction, so nobody
  443. // must be allowed to keep an extra reference
  444. asASSERT(m_refCount.get() == count);
  445. asPopActiveContext(tld, this);
  446. // Release the object if it is a script object
  447. if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
  448. {
  449. asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
  450. if( obj )
  451. obj->Release();
  452. }
  453. // Release the initial function
  454. if( m_initialFunction )
  455. {
  456. m_initialFunction->Release();
  457. // Reset stack pointer
  458. m_regs.stackPointer = m_originalStackPointer;
  459. // Make sure the stack pointer is pointing to the original position,
  460. // otherwise something is wrong with the way it is being updated
  461. asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
  462. }
  463. // Clear function pointers
  464. m_initialFunction = 0;
  465. m_currentFunction = 0;
  466. m_exceptionFunction = 0;
  467. m_regs.programPointer = 0;
  468. // Reset status
  469. m_status = asEXECUTION_UNINITIALIZED;
  470. m_regs.stackFramePointer = 0;
  471. return 0;
  472. }
  473. asBYTE asCContext::GetReturnByte()
  474. {
  475. if( m_status != asEXECUTION_FINISHED ) return 0;
  476. asCDataType *dt = &m_initialFunction->returnType;
  477. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  478. return *(asBYTE*)&m_regs.valueRegister;
  479. }
  480. asWORD asCContext::GetReturnWord()
  481. {
  482. if( m_status != asEXECUTION_FINISHED ) return 0;
  483. asCDataType *dt = &m_initialFunction->returnType;
  484. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  485. return *(asWORD*)&m_regs.valueRegister;
  486. }
  487. asDWORD asCContext::GetReturnDWord()
  488. {
  489. if( m_status != asEXECUTION_FINISHED ) return 0;
  490. asCDataType *dt = &m_initialFunction->returnType;
  491. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  492. return *(asDWORD*)&m_regs.valueRegister;
  493. }
  494. asQWORD asCContext::GetReturnQWord()
  495. {
  496. if( m_status != asEXECUTION_FINISHED ) return 0;
  497. asCDataType *dt = &m_initialFunction->returnType;
  498. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  499. return m_regs.valueRegister;
  500. }
  501. float asCContext::GetReturnFloat()
  502. {
  503. if( m_status != asEXECUTION_FINISHED ) return 0;
  504. asCDataType *dt = &m_initialFunction->returnType;
  505. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  506. return *(float*)&m_regs.valueRegister;
  507. }
  508. double asCContext::GetReturnDouble()
  509. {
  510. if( m_status != asEXECUTION_FINISHED ) return 0;
  511. asCDataType *dt = &m_initialFunction->returnType;
  512. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
  513. return *(double*)&m_regs.valueRegister;
  514. }
  515. void *asCContext::GetReturnAddress()
  516. {
  517. if( m_status != asEXECUTION_FINISHED ) return 0;
  518. asCDataType *dt = &m_initialFunction->returnType;
  519. if( dt->IsReference() )
  520. return *(void**)&m_regs.valueRegister;
  521. else if( dt->IsObject() || dt->IsFuncdef() )
  522. {
  523. if( m_initialFunction->DoesReturnOnStack() )
  524. {
  525. // The address of the return value was passed as the first argument, after the object pointer
  526. int offset = 0;
  527. if( m_initialFunction->objectType )
  528. offset += AS_PTR_SIZE;
  529. return *(void**)(&m_regs.stackFramePointer[offset]);
  530. }
  531. return m_regs.objectRegister;
  532. }
  533. return 0;
  534. }
  535. void *asCContext::GetReturnObject()
  536. {
  537. if( m_status != asEXECUTION_FINISHED ) return 0;
  538. asCDataType *dt = &m_initialFunction->returnType;
  539. if( !dt->IsObject() && !dt->IsFuncdef() ) return 0;
  540. if( dt->IsReference() )
  541. return *(void**)(asPWORD)m_regs.valueRegister;
  542. else
  543. {
  544. if( m_initialFunction->DoesReturnOnStack() )
  545. {
  546. // The address of the return value was passed as the first argument, after the object pointer
  547. int offset = 0;
  548. if( m_initialFunction->objectType )
  549. offset += AS_PTR_SIZE;
  550. return *(void**)(&m_regs.stackFramePointer[offset]);
  551. }
  552. return m_regs.objectRegister;
  553. }
  554. }
  555. void *asCContext::GetAddressOfReturnValue()
  556. {
  557. if( m_status != asEXECUTION_FINISHED ) return 0;
  558. asCDataType *dt = &m_initialFunction->returnType;
  559. // An object is stored in the objectRegister
  560. if( !dt->IsReference() && (dt->IsObject() || dt->IsFuncdef()) )
  561. {
  562. // Need to dereference objects
  563. if( !dt->IsObjectHandle() )
  564. {
  565. if( m_initialFunction->DoesReturnOnStack() )
  566. {
  567. // The address of the return value was passed as the first argument, after the object pointer
  568. int offset = 0;
  569. if( m_initialFunction->objectType )
  570. offset += AS_PTR_SIZE;
  571. return *(void**)(&m_regs.stackFramePointer[offset]);
  572. }
  573. return *(void**)&m_regs.objectRegister;
  574. }
  575. return &m_regs.objectRegister;
  576. }
  577. // Primitives and references are stored in valueRegister
  578. return &m_regs.valueRegister;
  579. }
  580. int asCContext::SetObject(void *obj)
  581. {
  582. if( m_status != asEXECUTION_PREPARED )
  583. return asCONTEXT_NOT_PREPARED;
  584. if( !m_initialFunction->objectType )
  585. {
  586. m_status = asEXECUTION_ERROR;
  587. return asERROR;
  588. }
  589. asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 );
  590. *(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj;
  591. // TODO: This should be optional by having a flag where the application can chose whether it should be done or not
  592. // The flag could be named something like takeOwnership and have default value of true
  593. if( obj && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
  594. reinterpret_cast<asCScriptObject*>(obj)->AddRef();
  595. return 0;
  596. }
  597. int asCContext::SetArgByte(asUINT arg, asBYTE value)
  598. {
  599. if( m_status != asEXECUTION_PREPARED )
  600. return asCONTEXT_NOT_PREPARED;
  601. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  602. {
  603. m_status = asEXECUTION_ERROR;
  604. return asINVALID_ARG;
  605. }
  606. // Verify the type of the argument
  607. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  608. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  609. {
  610. m_status = asEXECUTION_ERROR;
  611. return asINVALID_TYPE;
  612. }
  613. if( dt->GetSizeInMemoryBytes() != 1 )
  614. {
  615. m_status = asEXECUTION_ERROR;
  616. return asINVALID_TYPE;
  617. }
  618. // Determine the position of the argument
  619. int offset = 0;
  620. if( m_initialFunction->objectType )
  621. offset += AS_PTR_SIZE;
  622. // If function returns object by value an extra pointer is pushed on the stack
  623. if( m_returnValueSize )
  624. offset += AS_PTR_SIZE;
  625. for( asUINT n = 0; n < arg; n++ )
  626. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  627. // Set the value
  628. *(asBYTE*)&m_regs.stackFramePointer[offset] = value;
  629. return 0;
  630. }
  631. int asCContext::SetArgWord(asUINT arg, asWORD value)
  632. {
  633. if( m_status != asEXECUTION_PREPARED )
  634. return asCONTEXT_NOT_PREPARED;
  635. if( arg >= m_initialFunction->parameterTypes.GetLength() )
  636. {
  637. m_status = asEXECUTION_ERROR;
  638. return asINVALID_ARG;
  639. }
  640. // Verify the type of the argument
  641. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  642. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  643. {
  644. m_status = asEXECUTION_ERROR;
  645. return asINVALID_TYPE;
  646. }
  647. if( dt->GetSizeInMemoryBytes() != 2 )
  648. {
  649. m_status = asEXECUTION_ERROR;
  650. return asINVALID_TYPE;
  651. }
  652. // Determine the position of the argument
  653. int offset = 0;
  654. if( m_initialFunction->objectType )
  655. offset += AS_PTR_SIZE;
  656. // If function returns object by value an extra pointer is pushed on the stack
  657. if( m_returnValueSize )
  658. offset += AS_PTR_SIZE;
  659. for( asUINT n = 0; n < arg; n++ )
  660. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  661. // Set the value
  662. *(asWORD*)&m_regs.stackFramePointer[offset] = value;
  663. return 0;
  664. }
  665. int asCContext::SetArgDWord(asUINT arg, asDWORD value)
  666. {
  667. if( m_status != asEXECUTION_PREPARED )
  668. return asCONTEXT_NOT_PREPARED;
  669. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  670. {
  671. m_status = asEXECUTION_ERROR;
  672. return asINVALID_ARG;
  673. }
  674. // Verify the type of the argument
  675. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  676. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  677. {
  678. m_status = asEXECUTION_ERROR;
  679. return asINVALID_TYPE;
  680. }
  681. if( dt->GetSizeInMemoryBytes() != 4 )
  682. {
  683. m_status = asEXECUTION_ERROR;
  684. return asINVALID_TYPE;
  685. }
  686. // Determine the position of the argument
  687. int offset = 0;
  688. if( m_initialFunction->objectType )
  689. offset += AS_PTR_SIZE;
  690. // If function returns object by value an extra pointer is pushed on the stack
  691. if( m_returnValueSize )
  692. offset += AS_PTR_SIZE;
  693. for( asUINT n = 0; n < arg; n++ )
  694. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  695. // Set the value
  696. *(asDWORD*)&m_regs.stackFramePointer[offset] = value;
  697. return 0;
  698. }
  699. int asCContext::SetArgQWord(asUINT arg, asQWORD value)
  700. {
  701. if( m_status != asEXECUTION_PREPARED )
  702. return asCONTEXT_NOT_PREPARED;
  703. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  704. {
  705. m_status = asEXECUTION_ERROR;
  706. return asINVALID_ARG;
  707. }
  708. // Verify the type of the argument
  709. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  710. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  711. {
  712. m_status = asEXECUTION_ERROR;
  713. return asINVALID_TYPE;
  714. }
  715. if( dt->GetSizeOnStackDWords() != 2 )
  716. {
  717. m_status = asEXECUTION_ERROR;
  718. return asINVALID_TYPE;
  719. }
  720. // Determine the position of the argument
  721. int offset = 0;
  722. if( m_initialFunction->objectType )
  723. offset += AS_PTR_SIZE;
  724. // If function returns object by value an extra pointer is pushed on the stack
  725. if( m_returnValueSize )
  726. offset += AS_PTR_SIZE;
  727. for( asUINT n = 0; n < arg; n++ )
  728. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  729. // Set the value
  730. *(asQWORD*)(&m_regs.stackFramePointer[offset]) = value;
  731. return 0;
  732. }
  733. int asCContext::SetArgFloat(asUINT arg, float value)
  734. {
  735. if( m_status != asEXECUTION_PREPARED )
  736. return asCONTEXT_NOT_PREPARED;
  737. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  738. {
  739. m_status = asEXECUTION_ERROR;
  740. return asINVALID_ARG;
  741. }
  742. // Verify the type of the argument
  743. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  744. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  745. {
  746. m_status = asEXECUTION_ERROR;
  747. return asINVALID_TYPE;
  748. }
  749. if( dt->GetSizeOnStackDWords() != 1 )
  750. {
  751. m_status = asEXECUTION_ERROR;
  752. return asINVALID_TYPE;
  753. }
  754. // Determine the position of the argument
  755. int offset = 0;
  756. if( m_initialFunction->objectType )
  757. offset += AS_PTR_SIZE;
  758. // If function returns object by value an extra pointer is pushed on the stack
  759. if( m_returnValueSize )
  760. offset += AS_PTR_SIZE;
  761. for( asUINT n = 0; n < arg; n++ )
  762. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  763. // Set the value
  764. *(float*)(&m_regs.stackFramePointer[offset]) = value;
  765. return 0;
  766. }
  767. int asCContext::SetArgDouble(asUINT arg, double value)
  768. {
  769. if( m_status != asEXECUTION_PREPARED )
  770. return asCONTEXT_NOT_PREPARED;
  771. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  772. {
  773. m_status = asEXECUTION_ERROR;
  774. return asINVALID_ARG;
  775. }
  776. // Verify the type of the argument
  777. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  778. if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
  779. {
  780. m_status = asEXECUTION_ERROR;
  781. return asINVALID_TYPE;
  782. }
  783. if( dt->GetSizeOnStackDWords() != 2 )
  784. {
  785. m_status = asEXECUTION_ERROR;
  786. return asINVALID_TYPE;
  787. }
  788. // Determine the position of the argument
  789. int offset = 0;
  790. if( m_initialFunction->objectType )
  791. offset += AS_PTR_SIZE;
  792. // If function returns object by value an extra pointer is pushed on the stack
  793. if( m_returnValueSize )
  794. offset += AS_PTR_SIZE;
  795. for( asUINT n = 0; n < arg; n++ )
  796. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  797. // Set the value
  798. *(double*)(&m_regs.stackFramePointer[offset]) = value;
  799. return 0;
  800. }
  801. int asCContext::SetArgAddress(asUINT arg, void *value)
  802. {
  803. if( m_status != asEXECUTION_PREPARED )
  804. return asCONTEXT_NOT_PREPARED;
  805. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  806. {
  807. m_status = asEXECUTION_ERROR;
  808. return asINVALID_ARG;
  809. }
  810. // Verify the type of the argument
  811. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  812. if( !dt->IsReference() && !dt->IsObjectHandle() )
  813. {
  814. m_status = asEXECUTION_ERROR;
  815. return asINVALID_TYPE;
  816. }
  817. // Determine the position of the argument
  818. int offset = 0;
  819. if( m_initialFunction->objectType )
  820. offset += AS_PTR_SIZE;
  821. // If function returns object by value an extra pointer is pushed on the stack
  822. if( m_returnValueSize )
  823. offset += AS_PTR_SIZE;
  824. for( asUINT n = 0; n < arg; n++ )
  825. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  826. // Set the value
  827. *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)value;
  828. return 0;
  829. }
  830. int asCContext::SetArgObject(asUINT arg, void *obj)
  831. {
  832. if( m_status != asEXECUTION_PREPARED )
  833. return asCONTEXT_NOT_PREPARED;
  834. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  835. {
  836. m_status = asEXECUTION_ERROR;
  837. return asINVALID_ARG;
  838. }
  839. // Verify the type of the argument
  840. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  841. if( !dt->IsObject() && !dt->IsFuncdef() )
  842. {
  843. m_status = asEXECUTION_ERROR;
  844. return asINVALID_TYPE;
  845. }
  846. // If the object should be sent by value we must make a copy of it
  847. if( !dt->IsReference() )
  848. {
  849. if( dt->IsObjectHandle() )
  850. {
  851. // Increase the reference counter
  852. if (obj && dt->IsFuncdef())
  853. ((asIScriptFunction*)obj)->AddRef();
  854. else
  855. {
  856. asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh;
  857. if (obj && beh->addref)
  858. m_engine->CallObjectMethod(obj, beh->addref);
  859. }
  860. }
  861. else
  862. {
  863. obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo());
  864. }
  865. }
  866. // Determine the position of the argument
  867. int offset = 0;
  868. if( m_initialFunction->objectType )
  869. offset += AS_PTR_SIZE;
  870. // If function returns object by value an extra pointer is pushed on the stack
  871. if( m_returnValueSize )
  872. offset += AS_PTR_SIZE;
  873. for( asUINT n = 0; n < arg; n++ )
  874. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  875. // Set the value
  876. *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)obj;
  877. return 0;
  878. }
  879. int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId)
  880. {
  881. if( m_status != asEXECUTION_PREPARED )
  882. return asCONTEXT_NOT_PREPARED;
  883. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  884. {
  885. m_status = asEXECUTION_ERROR;
  886. return asINVALID_ARG;
  887. }
  888. // Verify the type of the argument
  889. asCDataType *dt = &m_initialFunction->parameterTypes[arg];
  890. if( dt->GetTokenType() != ttQuestion )
  891. {
  892. m_status = asEXECUTION_ERROR;
  893. return asINVALID_TYPE;
  894. }
  895. // Determine the position of the argument
  896. int offset = 0;
  897. if( m_initialFunction->objectType )
  898. offset += AS_PTR_SIZE;
  899. // If function returns object by value an extra pointer is pushed on the stack
  900. if( m_returnValueSize )
  901. offset += AS_PTR_SIZE;
  902. for( asUINT n = 0; n < arg; n++ )
  903. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  904. // Set the typeId and pointer
  905. *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr;
  906. offset += AS_PTR_SIZE;
  907. *(int*)(&m_regs.stackFramePointer[offset]) = typeId;
  908. return 0;
  909. }
  910. // TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
  911. // interface
  912. void *asCContext::GetAddressOfArg(asUINT arg)
  913. {
  914. if( m_status != asEXECUTION_PREPARED )
  915. return 0;
  916. if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
  917. return 0;
  918. // Determine the position of the argument
  919. int offset = 0;
  920. if( m_initialFunction->objectType )
  921. offset += AS_PTR_SIZE;
  922. // If function returns object by value an extra pointer is pushed on the stack
  923. if( m_returnValueSize )
  924. offset += AS_PTR_SIZE;
  925. for( asUINT n = 0; n < arg; n++ )
  926. offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  927. // We should return the address of the location where the argument value will be placed
  928. // All registered types are always sent by reference, even if
  929. // the function is declared to receive the argument by value.
  930. return &m_regs.stackFramePointer[offset];
  931. }
  932. int asCContext::Abort()
  933. {
  934. if( m_engine == 0 ) return asERROR;
  935. // TODO: multithread: Make thread safe. There is a chance that the status
  936. // changes to something else after being set to ABORTED here.
  937. if( m_status == asEXECUTION_SUSPENDED )
  938. m_status = asEXECUTION_ABORTED;
  939. m_doSuspend = true;
  940. m_regs.doProcessSuspend = true;
  941. m_externalSuspendRequest = true;
  942. m_doAbort = true;
  943. return 0;
  944. }
  945. // interface
  946. int asCContext::Suspend()
  947. {
  948. // This function just sets some internal flags and is safe
  949. // to call from a secondary thread, even if the library has
  950. // been built without multi-thread support.
  951. if( m_engine == 0 ) return asERROR;
  952. m_doSuspend = true;
  953. m_externalSuspendRequest = true;
  954. m_regs.doProcessSuspend = true;
  955. return 0;
  956. }
  957. // interface
  958. int asCContext::Execute()
  959. {
  960. asASSERT( m_engine != 0 );
  961. if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED )
  962. {
  963. asCString str;
  964. str.Format(TXT_FAILED_IN_FUNC_s_s_d, "Execute", errorNames[-asCONTEXT_NOT_PREPARED], asCONTEXT_NOT_PREPARED);
  965. m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  966. return asCONTEXT_NOT_PREPARED;
  967. }
  968. m_status = asEXECUTION_ACTIVE;
  969. asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this);
  970. // Make sure there are not too many nested calls, as it could crash the application
  971. // by filling up the thread call stack
  972. if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls)
  973. SetInternalException(TXT_TOO_MANY_NESTED_CALLS);
  974. else if( m_regs.programPointer == 0 )
  975. {
  976. if( m_currentFunction->funcType == asFUNC_DELEGATE )
  977. {
  978. // Push the object pointer onto the stack
  979. asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
  980. m_regs.stackPointer -= AS_PTR_SIZE;
  981. m_regs.stackFramePointer -= AS_PTR_SIZE;
  982. *(asPWORD*)m_regs.stackPointer = asPWORD(m_currentFunction->objForDelegate);
  983. // Make the call to the delegated object method
  984. m_currentFunction = m_currentFunction->funcForDelegate;
  985. }
  986. if( m_currentFunction->funcType == asFUNC_VIRTUAL ||
  987. m_currentFunction->funcType == asFUNC_INTERFACE )
  988. {
  989. // The currentFunction is a virtual method
  990. // Determine the true function from the object
  991. asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackFramePointer;
  992. if( obj == 0 )
  993. {
  994. SetInternalException(TXT_NULL_POINTER_ACCESS);
  995. }
  996. else
  997. {
  998. asCObjectType *objType = obj->objType;
  999. asCScriptFunction *realFunc = 0;
  1000. if( m_currentFunction->funcType == asFUNC_VIRTUAL )
  1001. {
  1002. if( objType->virtualFunctionTable.GetLength() > (asUINT)m_currentFunction->vfTableIdx )
  1003. {
  1004. realFunc = objType->virtualFunctionTable[m_currentFunction->vfTableIdx];
  1005. }
  1006. }
  1007. else
  1008. {
  1009. // Search the object type for a function that matches the interface function
  1010. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  1011. {
  1012. asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]];
  1013. if( f2->signatureId == m_currentFunction->signatureId )
  1014. {
  1015. if( f2->funcType == asFUNC_VIRTUAL )
  1016. realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
  1017. else
  1018. realFunc = f2;
  1019. break;
  1020. }
  1021. }
  1022. }
  1023. if( realFunc && realFunc->signatureId == m_currentFunction->signatureId )
  1024. m_currentFunction = realFunc;
  1025. else
  1026. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1027. }
  1028. }
  1029. else if( m_currentFunction->funcType == asFUNC_IMPORTED )
  1030. {
  1031. int funcId = m_engine->importedFunctions[m_currentFunction->id & ~FUNC_IMPORTED]->boundFunctionId;
  1032. if( funcId > 0 )
  1033. m_currentFunction = m_engine->scriptFunctions[funcId];
  1034. else
  1035. SetInternalException(TXT_UNBOUND_FUNCTION);
  1036. }
  1037. if( m_currentFunction->funcType == asFUNC_SCRIPT )
  1038. {
  1039. m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf();
  1040. // Set up the internal registers for executing the script function
  1041. PrepareScriptFunction();
  1042. }
  1043. else if( m_currentFunction->funcType == asFUNC_SYSTEM )
  1044. {
  1045. // The current function is an application registered function
  1046. // Call the function directly
  1047. CallSystemFunction(m_currentFunction->id, this);
  1048. // Was the call successful?
  1049. if( m_status == asEXECUTION_ACTIVE )
  1050. {
  1051. m_status = asEXECUTION_FINISHED;
  1052. }
  1053. }
  1054. else
  1055. {
  1056. // This shouldn't happen unless there was an error in which
  1057. // case an exception should have been raised already
  1058. asASSERT( m_status == asEXECUTION_EXCEPTION );
  1059. }
  1060. }
  1061. asUINT gcPreObjects = 0;
  1062. if( m_engine->ep.autoGarbageCollect )
  1063. m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0);
  1064. while (m_status == asEXECUTION_ACTIVE)
  1065. {
  1066. ExecuteNext();
  1067. // If an exception was raised that will be caught, then unwind the stack
  1068. // and move the program pointer to the catch block before proceeding
  1069. if (m_status == asEXECUTION_EXCEPTION && m_exceptionWillBeCaught)
  1070. CleanStack(true);
  1071. }
  1072. if( m_lineCallback )
  1073. {
  1074. // Call the line callback one last time before leaving
  1075. // so anyone listening can catch the state change
  1076. CallLineCallback();
  1077. m_regs.doProcessSuspend = true;
  1078. }
  1079. else
  1080. m_regs.doProcessSuspend = false;
  1081. m_doSuspend = false;
  1082. if( m_engine->ep.autoGarbageCollect )
  1083. {
  1084. asUINT gcPosObjects = 0;
  1085. m_engine->gc.GetStatistics(&gcPosObjects, 0, 0, 0, 0);
  1086. if( gcPosObjects > gcPreObjects )
  1087. {
  1088. // Execute as many steps as there were new objects created
  1089. m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, gcPosObjects - gcPreObjects);
  1090. }
  1091. else if( gcPosObjects > 0 )
  1092. {
  1093. // Execute at least one step, even if no new objects were created
  1094. m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, 1);
  1095. }
  1096. }
  1097. // Pop the active context
  1098. asPopActiveContext(tld, this);
  1099. if( m_status == asEXECUTION_FINISHED )
  1100. {
  1101. m_regs.objectType = m_initialFunction->returnType.GetTypeInfo();
  1102. return asEXECUTION_FINISHED;
  1103. }
  1104. if( m_doAbort )
  1105. {
  1106. m_doAbort = false;
  1107. m_status = asEXECUTION_ABORTED;
  1108. return asEXECUTION_ABORTED;
  1109. }
  1110. if( m_status == asEXECUTION_SUSPENDED )
  1111. return asEXECUTION_SUSPENDED;
  1112. if( m_status == asEXECUTION_EXCEPTION )
  1113. return asEXECUTION_EXCEPTION;
  1114. return asERROR;
  1115. }
  1116. int asCContext::PushState()
  1117. {
  1118. // Only allow the state to be pushed when active
  1119. // TODO: Can we support a suspended state too? So the reuse of
  1120. // the context can be done outside the Execute() call?
  1121. if( m_status != asEXECUTION_ACTIVE )
  1122. {
  1123. // TODO: Write message. Wrong usage
  1124. return asERROR;
  1125. }
  1126. // Allocate space on the callstack for at least two states
  1127. if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE)
  1128. {
  1129. if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE)
  1130. {
  1131. // The call stack is too big to grow further
  1132. // If an error occurs, no change to the context should be done
  1133. return asOUT_OF_MEMORY;
  1134. }
  1135. // Allocate space for 10 call states at a time to save time
  1136. m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true);
  1137. }
  1138. // Push the current script function that is calling the system function
  1139. // This cannot fail, since the memory was already allocated above
  1140. PushCallState();
  1141. // Push the system function too, which will serve both as a marker and
  1142. // informing which system function that created the nested call
  1143. m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
  1144. // Need to push m_initialFunction as it must be restored later
  1145. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  1146. tmp[0] = 0;
  1147. tmp[1] = (asPWORD)m_callingSystemFunction;
  1148. tmp[2] = (asPWORD)m_initialFunction;
  1149. tmp[3] = (asPWORD)m_originalStackPointer;
  1150. tmp[4] = (asPWORD)m_argumentsSize;
  1151. // Need to push the value of registers so they can be restored
  1152. tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister);
  1153. tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32);
  1154. tmp[7] = (asPWORD)m_regs.objectRegister;
  1155. tmp[8] = (asPWORD)m_regs.objectType;
  1156. // Decrease stackpointer to prevent the top value from being overwritten
  1157. m_regs.stackPointer -= 2;
  1158. // Clear the initial function so that Prepare() knows it must do all validations
  1159. m_initialFunction = 0;
  1160. // After this the state should appear as if uninitialized
  1161. m_callingSystemFunction = 0;
  1162. m_regs.objectRegister = 0;
  1163. m_regs.objectType = 0;
  1164. // Set the status to uninitialized as application
  1165. // should call Prepare() after this to reuse the context
  1166. m_status = asEXECUTION_UNINITIALIZED;
  1167. return asSUCCESS;
  1168. }
  1169. int asCContext::PopState()
  1170. {
  1171. if( !IsNested() )
  1172. return asERROR;
  1173. // Clean up the current execution
  1174. Unprepare();
  1175. // The topmost state must be a marker for nested call
  1176. asASSERT( m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 );
  1177. // Restore the previous state
  1178. asPWORD *tmp = &m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE];
  1179. m_callingSystemFunction = reinterpret_cast<asCScriptFunction*>(tmp[1]);
  1180. m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
  1181. // Restore the previous initial function and the associated values
  1182. m_initialFunction = reinterpret_cast<asCScriptFunction*>(tmp[2]);
  1183. m_originalStackPointer = (asDWORD*)tmp[3];
  1184. m_argumentsSize = (int)tmp[4];
  1185. m_regs.valueRegister = asQWORD(asDWORD(tmp[5]));
  1186. m_regs.valueRegister |= asQWORD(tmp[6])<<32;
  1187. m_regs.objectRegister = (void*)tmp[7];
  1188. m_regs.objectType = (asITypeInfo*)tmp[8];
  1189. // Calculate the returnValueSize
  1190. if( m_initialFunction->DoesReturnOnStack() )
  1191. m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords();
  1192. else
  1193. m_returnValueSize = 0;
  1194. // Pop the current script function. This will also restore the previous stack pointer
  1195. PopCallState();
  1196. m_status = asEXECUTION_ACTIVE;
  1197. return asSUCCESS;
  1198. }
  1199. int asCContext::PushCallState()
  1200. {
  1201. if( m_callStack.GetLength() == m_callStack.GetCapacity() )
  1202. {
  1203. if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE)
  1204. {
  1205. // The call stack is too big to grow further
  1206. SetInternalException(TXT_STACK_OVERFLOW);
  1207. return asERROR;
  1208. }
  1209. // Allocate space for 10 call states at a time to save time
  1210. m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
  1211. }
  1212. m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
  1213. // Separating the loads and stores limits data cache trash, and with a smart compiler
  1214. // could turn into SIMD style loading/storing if available.
  1215. // The compiler can't do this itself due to potential pointer aliasing between the pointers,
  1216. // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example
  1217. // for all the compiler knows. So introducing the local variable s, which is never referred to by
  1218. // its address we avoid this issue.
  1219. asPWORD s[5];
  1220. s[0] = (asPWORD)m_regs.stackFramePointer;
  1221. s[1] = (asPWORD)m_currentFunction;
  1222. s[2] = (asPWORD)m_regs.programPointer;
  1223. s[3] = (asPWORD)m_regs.stackPointer;
  1224. s[4] = m_stackIndex;
  1225. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  1226. tmp[0] = s[0];
  1227. tmp[1] = s[1];
  1228. tmp[2] = s[2];
  1229. tmp[3] = s[3];
  1230. tmp[4] = s[4];
  1231. return asSUCCESS;
  1232. }
  1233. void asCContext::PopCallState()
  1234. {
  1235. // See comments in PushCallState about pointer aliasing and data cache trashing
  1236. asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  1237. asPWORD s[5];
  1238. s[0] = tmp[0];
  1239. s[1] = tmp[1];
  1240. s[2] = tmp[2];
  1241. s[3] = tmp[3];
  1242. s[4] = tmp[4];
  1243. m_regs.stackFramePointer = (asDWORD*)s[0];
  1244. m_currentFunction = (asCScriptFunction*)s[1];
  1245. m_regs.programPointer = (asDWORD*)s[2];
  1246. m_regs.stackPointer = (asDWORD*)s[3];
  1247. m_stackIndex = (int)s[4];
  1248. m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
  1249. }
  1250. // interface
  1251. asUINT asCContext::GetCallstackSize() const
  1252. {
  1253. if( m_currentFunction == 0 ) return 0;
  1254. // The current function is accessed at stackLevel 0
  1255. return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE);
  1256. }
  1257. // interface
  1258. asIScriptFunction *asCContext::GetFunction(asUINT stackLevel)
  1259. {
  1260. if( stackLevel >= GetCallstackSize() ) return 0;
  1261. if( stackLevel == 0 ) return m_currentFunction;
  1262. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE;
  1263. asCScriptFunction *func = (asCScriptFunction*)s[1];
  1264. return func;
  1265. }
  1266. // interface
  1267. int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **sectionName)
  1268. {
  1269. if( stackLevel >= GetCallstackSize() ) return asINVALID_ARG;
  1270. asCScriptFunction *func;
  1271. asDWORD *bytePos;
  1272. if( stackLevel == 0 )
  1273. {
  1274. func = m_currentFunction;
  1275. if( func->scriptData == 0 ) return 0;
  1276. bytePos = m_regs.programPointer;
  1277. }
  1278. else
  1279. {
  1280. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  1281. func = (asCScriptFunction*)s[1];
  1282. if( func->scriptData == 0 ) return 0;
  1283. bytePos = (asDWORD*)s[2];
  1284. // Subract 1 from the bytePos, because we want the line where
  1285. // the call was made, and not the instruction after the call
  1286. bytePos -= 1;
  1287. }
  1288. // For nested calls it is possible that func is null
  1289. if( func == 0 )
  1290. {
  1291. if( column ) *column = 0;
  1292. if( sectionName ) *sectionName = 0;
  1293. return 0;
  1294. }
  1295. int sectionIdx;
  1296. asDWORD line = func->GetLineNumber(int(bytePos - func->scriptData->byteCode.AddressOf()), &sectionIdx);
  1297. if( column ) *column = (line >> 20);
  1298. if( sectionName )
  1299. {
  1300. asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) );
  1301. if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() )
  1302. *sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf();
  1303. else
  1304. *sectionName = 0;
  1305. }
  1306. return (line & 0xFFFFF);
  1307. }
  1308. // internal
  1309. bool asCContext::ReserveStackSpace(asUINT size)
  1310. {
  1311. #ifdef WIP_16BYTE_ALIGN
  1312. // Pad size to a multiple of MAX_TYPE_ALIGNMENT.
  1313. const asUINT remainder = size % MAX_TYPE_ALIGNMENT;
  1314. if(remainder != 0)
  1315. {
  1316. size = size + (MAX_TYPE_ALIGNMENT - (size % MAX_TYPE_ALIGNMENT));
  1317. }
  1318. #endif
  1319. // Make sure the first stack block is allocated
  1320. if( m_stackBlocks.GetLength() == 0 )
  1321. {
  1322. m_stackBlockSize = m_engine->ep.initContextStackSize;
  1323. asASSERT( m_stackBlockSize > 0 );
  1324. #ifndef WIP_16BYTE_ALIGN
  1325. asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize);
  1326. #else
  1327. asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT);
  1328. #endif
  1329. if( stack == 0 )
  1330. {
  1331. // Out of memory
  1332. return false;
  1333. }
  1334. #ifdef WIP_16BYTE_ALIGN
  1335. asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
  1336. #endif
  1337. m_stackBlocks.PushLast(stack);
  1338. m_stackIndex = 0;
  1339. m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize;
  1340. #ifdef WIP_16BYTE_ALIGN
  1341. // Align the stack pointer. This is necessary as the m_stackBlockSize is not necessarily evenly divisable with the max alignment
  1342. ((asPWORD&)m_regs.stackPointer) &= ~(MAX_TYPE_ALIGNMENT-1);
  1343. asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
  1344. #endif
  1345. }
  1346. // Check if there is enough space on the current stack block, otherwise move
  1347. // to the next one. New and larger blocks will be allocated as necessary
  1348. while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] )
  1349. {
  1350. // Make sure we don't allocate more space than allowed
  1351. if( m_engine->ep.maximumContextStackSize )
  1352. {
  1353. // This test will only stop growth once it is on or already crossed the limit
  1354. if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) >= m_engine->ep.maximumContextStackSize )
  1355. {
  1356. m_isStackMemoryNotAllocated = true;
  1357. // Set the stackFramePointer, even though the stackPointer wasn't updated
  1358. m_regs.stackFramePointer = m_regs.stackPointer;
  1359. SetInternalException(TXT_STACK_OVERFLOW);
  1360. return false;
  1361. }
  1362. }
  1363. m_stackIndex++;
  1364. if( m_stackBlocks.GetLength() == m_stackIndex )
  1365. {
  1366. // Allocate the new stack block, with twice the size of the previous
  1367. #ifndef WIP_16BYTE_ALIGN
  1368. asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex));
  1369. #else
  1370. asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT);
  1371. #endif
  1372. if( stack == 0 )
  1373. {
  1374. // Out of memory
  1375. m_isStackMemoryNotAllocated = true;
  1376. // Set the stackFramePointer, even though the stackPointer wasn't updated
  1377. m_regs.stackFramePointer = m_regs.stackPointer;
  1378. SetInternalException(TXT_STACK_OVERFLOW);
  1379. return false;
  1380. }
  1381. #ifdef WIP_16BYTE_ALIGN
  1382. asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
  1383. #endif
  1384. m_stackBlocks.PushLast(stack);
  1385. }
  1386. // Update the stack pointer to point to the new block.
  1387. // Leave enough room above the stackpointer to copy the arguments from the previous stackblock
  1388. m_regs.stackPointer = m_stackBlocks[m_stackIndex] +
  1389. (m_stackBlockSize<<m_stackIndex) -
  1390. m_currentFunction->GetSpaceNeededForArguments() -
  1391. (m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
  1392. (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
  1393. #ifdef WIP_16BYTE_ALIGN
  1394. // Align the stack pointer
  1395. (asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1);
  1396. asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
  1397. #endif
  1398. }
  1399. return true;
  1400. }
  1401. // internal
  1402. void asCContext::CallScriptFunction(asCScriptFunction *func)
  1403. {
  1404. asASSERT( func->scriptData );
  1405. // Push the framepointer, function id and programCounter on the stack
  1406. if (PushCallState() < 0)
  1407. return;
  1408. // Update the current function and program position before increasing the stack
  1409. // so the exception handler will know what to do if there is a stack overflow
  1410. m_currentFunction = func;
  1411. m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf();
  1412. PrepareScriptFunction();
  1413. }
  1414. void asCContext::PrepareScriptFunction()
  1415. {
  1416. asASSERT( m_currentFunction->scriptData );
  1417. // Make sure there is space on the stack to execute the function
  1418. asDWORD *oldStackPointer = m_regs.stackPointer;
  1419. if( !ReserveStackSpace(m_currentFunction->scriptData->stackNeeded) )
  1420. return;
  1421. // If a new stack block was allocated then we'll need to move
  1422. // over the function arguments to the new block.
  1423. if( m_regs.stackPointer != oldStackPointer )
  1424. {
  1425. int numDwords = m_currentFunction->GetSpaceNeededForArguments() +
  1426. (m_currentFunction->objectType ? AS_PTR_SIZE : 0) +
  1427. (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
  1428. memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
  1429. }
  1430. // Update framepointer
  1431. m_regs.stackFramePointer = m_regs.stackPointer;
  1432. // Set all object variables to 0 to guarantee that they are null before they are used
  1433. // Only variables on the heap should be cleared. The rest will be cleared by calling the constructor
  1434. asUINT n = m_currentFunction->scriptData->objVariablesOnHeap;
  1435. while( n-- > 0 )
  1436. {
  1437. int pos = m_currentFunction->scriptData->objVariablePos[n];
  1438. *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
  1439. }
  1440. // Initialize the stack pointer with the space needed for local variables
  1441. m_regs.stackPointer -= m_currentFunction->scriptData->variableSpace;
  1442. // Call the line callback for each script function, to guarantee that infinitely recursive scripts can
  1443. // be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES
  1444. if( m_regs.doProcessSuspend )
  1445. {
  1446. if( m_lineCallback )
  1447. CallLineCallback();
  1448. if( m_doSuspend )
  1449. m_status = asEXECUTION_SUSPENDED;
  1450. }
  1451. }
  1452. void asCContext::CallInterfaceMethod(asCScriptFunction *func)
  1453. {
  1454. // Resolve the interface method using the current script type
  1455. asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer;
  1456. if( obj == 0 )
  1457. {
  1458. // Tell the exception handler to clean up the arguments to this method
  1459. m_needToCleanupArgs = true;
  1460. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1461. return;
  1462. }
  1463. asCObjectType *objType = obj->objType;
  1464. // Search the object type for a function that matches the interface function
  1465. asCScriptFunction *realFunc = 0;
  1466. if( func->funcType == asFUNC_INTERFACE )
  1467. {
  1468. // Find the offset for the interface's virtual function table chunk
  1469. asUINT offset = 0;
  1470. bool found = false;
  1471. asCObjectType *findInterface = func->objectType;
  1472. // TODO: runtime optimize: The list of interfaces should be ordered by the address
  1473. // Then a binary search pattern can be used.
  1474. asUINT intfCount = asUINT(objType->interfaces.GetLength());
  1475. for( asUINT n = 0; n < intfCount; n++ )
  1476. {
  1477. if( objType->interfaces[n] == findInterface )
  1478. {
  1479. offset = objType->interfaceVFTOffsets[n];
  1480. found = true;
  1481. break;
  1482. }
  1483. }
  1484. if( !found )
  1485. {
  1486. // Tell the exception handler to clean up the arguments to this method
  1487. m_needToCleanupArgs = true;
  1488. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1489. return;
  1490. }
  1491. // Find the real function in the virtual table chunk with the found offset
  1492. realFunc = objType->virtualFunctionTable[func->vfTableIdx + offset];
  1493. // Since the interface was implemented by the class, it shouldn't
  1494. // be possible that the real function isn't found
  1495. asASSERT( realFunc );
  1496. asASSERT( realFunc->signatureId == func->signatureId );
  1497. }
  1498. else // if( func->funcType == asFUNC_VIRTUAL )
  1499. {
  1500. realFunc = objType->virtualFunctionTable[func->vfTableIdx];
  1501. }
  1502. // Then call the true script function
  1503. CallScriptFunction(realFunc);
  1504. }
  1505. void asCContext::ExecuteNext()
  1506. {
  1507. asDWORD *l_bc = m_regs.programPointer;
  1508. asDWORD *l_sp = m_regs.stackPointer;
  1509. asDWORD *l_fp = m_regs.stackFramePointer;
  1510. for(;;)
  1511. {
  1512. #ifdef AS_DEBUG
  1513. // Gather statistics on executed bytecode
  1514. stats.Instr(*(asBYTE*)l_bc);
  1515. // Used to verify that the size of the instructions are correct
  1516. asDWORD *old = l_bc;
  1517. #endif
  1518. // Remember to keep the cases in order and without
  1519. // gaps, because that will make the switch faster.
  1520. // It will be faster since only one lookup will be
  1521. // made to find the correct jump destination. If not
  1522. // in order, the switch will make two lookups.
  1523. switch( *(asBYTE*)l_bc )
  1524. {
  1525. //--------------
  1526. // memory access functions
  1527. case asBC_PopPtr:
  1528. // Pop a pointer from the stack
  1529. l_sp += AS_PTR_SIZE;
  1530. l_bc++;
  1531. break;
  1532. case asBC_PshGPtr:
  1533. // Replaces PGA + RDSPtr
  1534. l_sp -= AS_PTR_SIZE;
  1535. *(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc);
  1536. l_bc += 1 + AS_PTR_SIZE;
  1537. break;
  1538. // Push a dword value on the stack
  1539. case asBC_PshC4:
  1540. --l_sp;
  1541. *l_sp = asBC_DWORDARG(l_bc);
  1542. l_bc += 2;
  1543. break;
  1544. // Push the dword value of a variable on the stack
  1545. case asBC_PshV4:
  1546. --l_sp;
  1547. *l_sp = *(l_fp - asBC_SWORDARG0(l_bc));
  1548. l_bc++;
  1549. break;
  1550. // Push the address of a variable on the stack
  1551. case asBC_PSF:
  1552. l_sp -= AS_PTR_SIZE;
  1553. *(asPWORD*)l_sp = asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  1554. l_bc++;
  1555. break;
  1556. // Swap the top 2 pointers on the stack
  1557. case asBC_SwapPtr:
  1558. {
  1559. asPWORD p = *(asPWORD*)l_sp;
  1560. *(asPWORD*)l_sp = *(asPWORD*)(l_sp+AS_PTR_SIZE);
  1561. *(asPWORD*)(l_sp+AS_PTR_SIZE) = p;
  1562. l_bc++;
  1563. }
  1564. break;
  1565. // Do a boolean not operation, modifying the value of the variable
  1566. case asBC_NOT:
  1567. #if AS_SIZEOF_BOOL == 1
  1568. {
  1569. // Set the value to true if it is equal to 0
  1570. // We need to use volatile here to tell the compiler it cannot
  1571. // change the order of read and write operations on the pointer.
  1572. volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  1573. asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1574. ptr[0] = val; // The result is stored in the lower byte
  1575. ptr[1] = 0; // Make sure the rest of the DWORD is 0
  1576. ptr[2] = 0;
  1577. ptr[3] = 0;
  1578. }
  1579. #else
  1580. *(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1581. #endif
  1582. l_bc++;
  1583. break;
  1584. // Push the dword value of a global variable on the stack
  1585. case asBC_PshG4:
  1586. --l_sp;
  1587. *l_sp = *(asDWORD*)asBC_PTRARG(l_bc);
  1588. l_bc += 1 + AS_PTR_SIZE;
  1589. break;
  1590. // Load the address of a global variable in the register, then
  1591. // copy the value of the global variable into a local variable
  1592. case asBC_LdGRdR4:
  1593. *(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc);
  1594. *(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
  1595. l_bc += 1+AS_PTR_SIZE;
  1596. break;
  1597. //----------------
  1598. // path control instructions
  1599. // Begin execution of a script function
  1600. case asBC_CALL:
  1601. {
  1602. int i = asBC_INTARG(l_bc);
  1603. l_bc += 2;
  1604. asASSERT( i >= 0 );
  1605. asASSERT( (i & FUNC_IMPORTED) == 0 );
  1606. // Need to move the values back to the context
  1607. m_regs.programPointer = l_bc;
  1608. m_regs.stackPointer = l_sp;
  1609. m_regs.stackFramePointer = l_fp;
  1610. CallScriptFunction(m_engine->scriptFunctions[i]);
  1611. // Extract the values from the context again
  1612. l_bc = m_regs.programPointer;
  1613. l_sp = m_regs.stackPointer;
  1614. l_fp = m_regs.stackFramePointer;
  1615. // If status isn't active anymore then we must stop
  1616. if( m_status != asEXECUTION_ACTIVE )
  1617. return;
  1618. }
  1619. break;
  1620. // Return to the caller, and remove the arguments from the stack
  1621. case asBC_RET:
  1622. {
  1623. // Return if this was the first function, or a nested execution
  1624. if( m_callStack.GetLength() == 0 ||
  1625. m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 )
  1626. {
  1627. m_status = asEXECUTION_FINISHED;
  1628. return;
  1629. }
  1630. asWORD w = asBC_WORDARG0(l_bc);
  1631. // Read the old framepointer, functionid, and programCounter from the call stack
  1632. PopCallState();
  1633. // Extract the values from the context again
  1634. l_bc = m_regs.programPointer;
  1635. l_sp = m_regs.stackPointer;
  1636. l_fp = m_regs.stackFramePointer;
  1637. // Pop arguments from stack
  1638. l_sp += w;
  1639. }
  1640. break;
  1641. // Jump to a relative position
  1642. case asBC_JMP:
  1643. l_bc += 2 + asBC_INTARG(l_bc);
  1644. break;
  1645. //----------------
  1646. // Conditional jumps
  1647. // Jump to a relative position if the value in the register is 0
  1648. case asBC_JZ:
  1649. if( *(int*)&m_regs.valueRegister == 0 )
  1650. l_bc += asBC_INTARG(l_bc) + 2;
  1651. else
  1652. l_bc += 2;
  1653. break;
  1654. // Jump to a relative position if the value in the register is not 0
  1655. case asBC_JNZ:
  1656. if( *(int*)&m_regs.valueRegister != 0 )
  1657. l_bc += asBC_INTARG(l_bc) + 2;
  1658. else
  1659. l_bc += 2;
  1660. break;
  1661. // Jump to a relative position if the value in the register is negative
  1662. case asBC_JS:
  1663. if( *(int*)&m_regs.valueRegister < 0 )
  1664. l_bc += asBC_INTARG(l_bc) + 2;
  1665. else
  1666. l_bc += 2;
  1667. break;
  1668. // Jump to a relative position if the value in the register it not negative
  1669. case asBC_JNS:
  1670. if( *(int*)&m_regs.valueRegister >= 0 )
  1671. l_bc += asBC_INTARG(l_bc) + 2;
  1672. else
  1673. l_bc += 2;
  1674. break;
  1675. // Jump to a relative position if the value in the register is greater than 0
  1676. case asBC_JP:
  1677. if( *(int*)&m_regs.valueRegister > 0 )
  1678. l_bc += asBC_INTARG(l_bc) + 2;
  1679. else
  1680. l_bc += 2;
  1681. break;
  1682. // Jump to a relative position if the value in the register is not greater than 0
  1683. case asBC_JNP:
  1684. if( *(int*)&m_regs.valueRegister <= 0 )
  1685. l_bc += asBC_INTARG(l_bc) + 2;
  1686. else
  1687. l_bc += 2;
  1688. break;
  1689. //--------------------
  1690. // test instructions
  1691. // If the value in the register is 0, then set the register to 1, else to 0
  1692. case asBC_TZ:
  1693. #if AS_SIZEOF_BOOL == 1
  1694. {
  1695. // Set the value to true if it is equal to 0
  1696. // We need to use volatile here to tell the compiler it cannot
  1697. // change the order of read and write operations on valueRegister.
  1698. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1699. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1700. asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1701. regBptr[0] = val; // The result is stored in the lower byte
  1702. regBptr[1] = 0; // Make sure the rest of the register is 0
  1703. regBptr[2] = 0;
  1704. regBptr[3] = 0;
  1705. regBptr[4] = 0;
  1706. regBptr[5] = 0;
  1707. regBptr[6] = 0;
  1708. regBptr[7] = 0;
  1709. }
  1710. #else
  1711. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1712. #endif
  1713. l_bc++;
  1714. break;
  1715. // If the value in the register is not 0, then set the register to 1, else to 0
  1716. case asBC_TNZ:
  1717. #if AS_SIZEOF_BOOL == 1
  1718. {
  1719. // Set the value to true if it is not equal to 0
  1720. // We need to use volatile here to tell the compiler it cannot
  1721. // change the order of read and write operations on valueRegister.
  1722. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1723. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1724. asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE;
  1725. regBptr[0] = val; // The result is stored in the lower byte
  1726. regBptr[1] = 0; // Make sure the rest of the register is 0
  1727. regBptr[2] = 0;
  1728. regBptr[3] = 0;
  1729. regBptr[4] = 0;
  1730. regBptr[5] = 0;
  1731. regBptr[6] = 0;
  1732. regBptr[7] = 0;
  1733. }
  1734. #else
  1735. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1736. #endif
  1737. l_bc++;
  1738. break;
  1739. // If the value in the register is negative, then set the register to 1, else to 0
  1740. case asBC_TS:
  1741. #if AS_SIZEOF_BOOL == 1
  1742. {
  1743. // Set the value to true if it is less than 0
  1744. // We need to use volatile here to tell the compiler it cannot
  1745. // change the order of read and write operations on valueRegister.
  1746. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1747. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1748. asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1749. regBptr[0] = val; // The result is stored in the lower byte
  1750. regBptr[1] = 0; // Make sure the rest of the register is 0
  1751. regBptr[2] = 0;
  1752. regBptr[3] = 0;
  1753. regBptr[4] = 0;
  1754. regBptr[5] = 0;
  1755. regBptr[6] = 0;
  1756. regBptr[7] = 0;
  1757. }
  1758. #else
  1759. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1760. #endif
  1761. l_bc++;
  1762. break;
  1763. // If the value in the register is not negative, then set the register to 1, else to 0
  1764. case asBC_TNS:
  1765. #if AS_SIZEOF_BOOL == 1
  1766. {
  1767. // Set the value to true if it is not less than 0
  1768. // We need to use volatile here to tell the compiler it cannot
  1769. // change the order of read and write operations on valueRegister.
  1770. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1771. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1772. asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1773. regBptr[0] = val; // The result is stored in the lower byte
  1774. regBptr[1] = 0; // Make sure the rest of the register is 0
  1775. regBptr[2] = 0;
  1776. regBptr[3] = 0;
  1777. regBptr[4] = 0;
  1778. regBptr[5] = 0;
  1779. regBptr[6] = 0;
  1780. regBptr[7] = 0;
  1781. }
  1782. #else
  1783. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1784. #endif
  1785. l_bc++;
  1786. break;
  1787. // If the value in the register is greater than 0, then set the register to 1, else to 0
  1788. case asBC_TP:
  1789. #if AS_SIZEOF_BOOL == 1
  1790. {
  1791. // Set the value to true if it is greater than 0
  1792. // We need to use volatile here to tell the compiler it cannot
  1793. // change the order of read and write operations on valueRegister.
  1794. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1795. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1796. asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1797. regBptr[0] = val; // The result is stored in the lower byte
  1798. regBptr[1] = 0; // Make sure the rest of the register is 0
  1799. regBptr[2] = 0;
  1800. regBptr[3] = 0;
  1801. regBptr[4] = 0;
  1802. regBptr[5] = 0;
  1803. regBptr[6] = 0;
  1804. regBptr[7] = 0;
  1805. }
  1806. #else
  1807. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1808. #endif
  1809. l_bc++;
  1810. break;
  1811. // If the value in the register is not greater than 0, then set the register to 1, else to 0
  1812. case asBC_TNP:
  1813. #if AS_SIZEOF_BOOL == 1
  1814. {
  1815. // Set the value to true if it is not greater than 0
  1816. // We need to use volatile here to tell the compiler it cannot
  1817. // change the order of read and write operations on valueRegister.
  1818. volatile int *regPtr = (int*)&m_regs.valueRegister;
  1819. volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
  1820. asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1821. regBptr[0] = val; // The result is stored in the lower byte
  1822. regBptr[1] = 0; // Make sure the rest of the register is 0
  1823. regBptr[2] = 0;
  1824. regBptr[3] = 0;
  1825. regBptr[4] = 0;
  1826. regBptr[5] = 0;
  1827. regBptr[6] = 0;
  1828. regBptr[7] = 0;
  1829. }
  1830. #else
  1831. *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1832. #endif
  1833. l_bc++;
  1834. break;
  1835. //--------------------
  1836. // negate value
  1837. // Negate the integer value in the variable
  1838. case asBC_NEGi:
  1839. *(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc))));
  1840. l_bc++;
  1841. break;
  1842. // Negate the float value in the variable
  1843. case asBC_NEGf:
  1844. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc));
  1845. l_bc++;
  1846. break;
  1847. // Negate the double value in the variable
  1848. case asBC_NEGd:
  1849. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc));
  1850. l_bc++;
  1851. break;
  1852. //-------------------------
  1853. // Increment value pointed to by address in register
  1854. // Increment the short value pointed to by the register
  1855. case asBC_INCi16:
  1856. (**(short**)&m_regs.valueRegister)++;
  1857. l_bc++;
  1858. break;
  1859. // Increment the byte value pointed to by the register
  1860. case asBC_INCi8:
  1861. (**(char**)&m_regs.valueRegister)++;
  1862. l_bc++;
  1863. break;
  1864. // Decrement the short value pointed to by the register
  1865. case asBC_DECi16:
  1866. (**(short**)&m_regs.valueRegister)--;
  1867. l_bc++;
  1868. break;
  1869. // Decrement the byte value pointed to by the register
  1870. case asBC_DECi8:
  1871. (**(char**)&m_regs.valueRegister)--;
  1872. l_bc++;
  1873. break;
  1874. // Increment the integer value pointed to by the register
  1875. case asBC_INCi:
  1876. ++(**(int**)&m_regs.valueRegister);
  1877. l_bc++;
  1878. break;
  1879. // Decrement the integer value pointed to by the register
  1880. case asBC_DECi:
  1881. --(**(int**)&m_regs.valueRegister);
  1882. l_bc++;
  1883. break;
  1884. // Increment the float value pointed to by the register
  1885. case asBC_INCf:
  1886. ++(**(float**)&m_regs.valueRegister);
  1887. l_bc++;
  1888. break;
  1889. // Decrement the float value pointed to by the register
  1890. case asBC_DECf:
  1891. --(**(float**)&m_regs.valueRegister);
  1892. l_bc++;
  1893. break;
  1894. // Increment the double value pointed to by the register
  1895. case asBC_INCd:
  1896. ++(**(double**)&m_regs.valueRegister);
  1897. l_bc++;
  1898. break;
  1899. // Decrement the double value pointed to by the register
  1900. case asBC_DECd:
  1901. --(**(double**)&m_regs.valueRegister);
  1902. l_bc++;
  1903. break;
  1904. // Increment the local integer variable
  1905. case asBC_IncVi:
  1906. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++;
  1907. l_bc++;
  1908. break;
  1909. // Decrement the local integer variable
  1910. case asBC_DecVi:
  1911. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--;
  1912. l_bc++;
  1913. break;
  1914. //--------------------
  1915. // bits instructions
  1916. // Do a bitwise not on the value in the variable
  1917. case asBC_BNOT:
  1918. *(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc));
  1919. l_bc++;
  1920. break;
  1921. // Do a bitwise and of two variables and store the result in a third variable
  1922. case asBC_BAND:
  1923. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc));
  1924. l_bc += 2;
  1925. break;
  1926. // Do a bitwise or of two variables and store the result in a third variable
  1927. case asBC_BOR:
  1928. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc));
  1929. l_bc += 2;
  1930. break;
  1931. // Do a bitwise xor of two variables and store the result in a third variable
  1932. case asBC_BXOR:
  1933. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc));
  1934. l_bc += 2;
  1935. break;
  1936. // Do a logical shift left of two variables and store the result in a third variable
  1937. case asBC_BSLL:
  1938. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  1939. l_bc += 2;
  1940. break;
  1941. // Do a logical shift right of two variables and store the result in a third variable
  1942. case asBC_BSRL:
  1943. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1944. l_bc += 2;
  1945. break;
  1946. // Do an arithmetic shift right of two variables and store the result in a third variable
  1947. case asBC_BSRA:
  1948. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1949. l_bc += 2;
  1950. break;
  1951. case asBC_COPY:
  1952. {
  1953. void *d = (void*)*(asPWORD*)l_sp; l_sp += AS_PTR_SIZE;
  1954. void *s = (void*)*(asPWORD*)l_sp;
  1955. if( s == 0 || d == 0 )
  1956. {
  1957. // Need to move the values back to the context
  1958. m_regs.programPointer = l_bc;
  1959. m_regs.stackPointer = l_sp;
  1960. m_regs.stackFramePointer = l_fp;
  1961. // Raise exception
  1962. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1963. return;
  1964. }
  1965. memcpy(d, s, asBC_WORDARG0(l_bc)*4);
  1966. // replace the pointer on the stack with the lvalue
  1967. *(asPWORD**)l_sp = (asPWORD*)d;
  1968. }
  1969. l_bc += 2;
  1970. break;
  1971. case asBC_PshC8:
  1972. l_sp -= 2;
  1973. *(asQWORD*)l_sp = asBC_QWORDARG(l_bc);
  1974. l_bc += 3;
  1975. break;
  1976. case asBC_PshVPtr:
  1977. l_sp -= AS_PTR_SIZE;
  1978. *(asPWORD*)l_sp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1979. l_bc++;
  1980. break;
  1981. case asBC_RDSPtr:
  1982. {
  1983. // The pointer must not be null
  1984. asPWORD a = *(asPWORD*)l_sp;
  1985. if( a == 0 )
  1986. {
  1987. m_regs.programPointer = l_bc;
  1988. m_regs.stackPointer = l_sp;
  1989. m_regs.stackFramePointer = l_fp;
  1990. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1991. return;
  1992. }
  1993. // Pop an address from the stack, read a pointer from that address and push it on the stack
  1994. *(asPWORD*)l_sp = *(asPWORD*)a;
  1995. }
  1996. l_bc++;
  1997. break;
  1998. //----------------------------
  1999. // Comparisons
  2000. case asBC_CMPd:
  2001. {
  2002. // Do a comparison of the values, rather than a subtraction
  2003. // in order to get proper behaviour for infinity values.
  2004. double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc));
  2005. double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc));
  2006. if( dbl1 == dbl2 ) *(int*)&m_regs.valueRegister = 0;
  2007. else if( dbl1 < dbl2 ) *(int*)&m_regs.valueRegister = -1;
  2008. else *(int*)&m_regs.valueRegister = 1;
  2009. l_bc += 2;
  2010. }
  2011. break;
  2012. case asBC_CMPu:
  2013. {
  2014. asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2015. asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2016. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  2017. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  2018. else *(int*)&m_regs.valueRegister = 1;
  2019. l_bc += 2;
  2020. }
  2021. break;
  2022. case asBC_CMPf:
  2023. {
  2024. // Do a comparison of the values, rather than a subtraction
  2025. // in order to get proper behaviour for infinity values.
  2026. float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
  2027. float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc));
  2028. if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0;
  2029. else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
  2030. else *(int*)&m_regs.valueRegister = 1;
  2031. l_bc += 2;
  2032. }
  2033. break;
  2034. case asBC_CMPi:
  2035. {
  2036. int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
  2037. int i2 = *(int*)(l_fp - asBC_SWORDARG1(l_bc));
  2038. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  2039. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  2040. else *(int*)&m_regs.valueRegister = 1;
  2041. l_bc += 2;
  2042. }
  2043. break;
  2044. //----------------------------
  2045. // Comparisons with constant value
  2046. case asBC_CMPIi:
  2047. {
  2048. int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
  2049. int i2 = asBC_INTARG(l_bc);
  2050. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  2051. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  2052. else *(int*)&m_regs.valueRegister = 1;
  2053. l_bc += 2;
  2054. }
  2055. break;
  2056. case asBC_CMPIf:
  2057. {
  2058. // Do a comparison of the values, rather than a subtraction
  2059. // in order to get proper behaviour for infinity values.
  2060. float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
  2061. float f2 = asBC_FLOATARG(l_bc);
  2062. if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0;
  2063. else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
  2064. else *(int*)&m_regs.valueRegister = 1;
  2065. l_bc += 2;
  2066. }
  2067. break;
  2068. case asBC_CMPIu:
  2069. {
  2070. asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2071. asDWORD d2 = asBC_DWORDARG(l_bc);
  2072. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  2073. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  2074. else *(int*)&m_regs.valueRegister = 1;
  2075. l_bc += 2;
  2076. }
  2077. break;
  2078. case asBC_JMPP:
  2079. l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2;
  2080. break;
  2081. case asBC_PopRPtr:
  2082. *(asPWORD*)&m_regs.valueRegister = *(asPWORD*)l_sp;
  2083. l_sp += AS_PTR_SIZE;
  2084. l_bc++;
  2085. break;
  2086. case asBC_PshRPtr:
  2087. l_sp -= AS_PTR_SIZE;
  2088. *(asPWORD*)l_sp = *(asPWORD*)&m_regs.valueRegister;
  2089. l_bc++;
  2090. break;
  2091. case asBC_STR:
  2092. // TODO: NEWSTRING: Deprecate this instruction
  2093. asASSERT(false);
  2094. l_bc++;
  2095. break;
  2096. case asBC_CALLSYS:
  2097. {
  2098. // Get function ID from the argument
  2099. int i = asBC_INTARG(l_bc);
  2100. // Need to move the values back to the context as the called functions
  2101. // may use the debug interface to inspect the registers
  2102. m_regs.programPointer = l_bc;
  2103. m_regs.stackPointer = l_sp;
  2104. m_regs.stackFramePointer = l_fp;
  2105. l_sp += CallSystemFunction(i, this);
  2106. // Update the program position after the call so that line number is correct
  2107. l_bc += 2;
  2108. if( m_regs.doProcessSuspend )
  2109. {
  2110. // Should the execution be suspended?
  2111. if( m_doSuspend )
  2112. {
  2113. m_regs.programPointer = l_bc;
  2114. m_regs.stackPointer = l_sp;
  2115. m_regs.stackFramePointer = l_fp;
  2116. m_status = asEXECUTION_SUSPENDED;
  2117. return;
  2118. }
  2119. // An exception might have been raised
  2120. if( m_status != asEXECUTION_ACTIVE )
  2121. {
  2122. m_regs.programPointer = l_bc;
  2123. m_regs.stackPointer = l_sp;
  2124. m_regs.stackFramePointer = l_fp;
  2125. return;
  2126. }
  2127. }
  2128. }
  2129. break;
  2130. case asBC_CALLBND:
  2131. {
  2132. // TODO: Clean-up: This code is very similar to asBC_CallPtr. Create a shared method for them
  2133. // Get the function ID from the stack
  2134. int i = asBC_INTARG(l_bc);
  2135. asASSERT( i >= 0 );
  2136. asASSERT( i & FUNC_IMPORTED );
  2137. // Need to move the values back to the context
  2138. m_regs.programPointer = l_bc;
  2139. m_regs.stackPointer = l_sp;
  2140. m_regs.stackFramePointer = l_fp;
  2141. int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId;
  2142. if( funcId == -1 )
  2143. {
  2144. // Need to update the program pointer for the exception handler
  2145. m_regs.programPointer += 2;
  2146. // Tell the exception handler to clean up the arguments to this function
  2147. m_needToCleanupArgs = true;
  2148. SetInternalException(TXT_UNBOUND_FUNCTION);
  2149. return;
  2150. }
  2151. else
  2152. {
  2153. asCScriptFunction *func = m_engine->GetScriptFunction(funcId);
  2154. if( func->funcType == asFUNC_SCRIPT )
  2155. {
  2156. m_regs.programPointer += 2;
  2157. CallScriptFunction(func);
  2158. }
  2159. else if( func->funcType == asFUNC_DELEGATE )
  2160. {
  2161. // Push the object pointer on the stack. There is always a reserved space for this so
  2162. // we don't don't need to worry about overflowing the allocated memory buffer
  2163. asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
  2164. m_regs.stackPointer -= AS_PTR_SIZE;
  2165. *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
  2166. // Call the delegated method
  2167. if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
  2168. {
  2169. m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
  2170. // Update program position after the call so the line number
  2171. // is correct in case the system function queries it
  2172. m_regs.programPointer += 2;
  2173. }
  2174. else
  2175. {
  2176. m_regs.programPointer += 2;
  2177. // TODO: run-time optimize: The true method could be figured out when creating the delegate
  2178. CallInterfaceMethod(func->funcForDelegate);
  2179. }
  2180. }
  2181. else
  2182. {
  2183. asASSERT( func->funcType == asFUNC_SYSTEM );
  2184. m_regs.stackPointer += CallSystemFunction(func->id, this);
  2185. // Update program position after the call so the line number
  2186. // is correct in case the system function queries it
  2187. m_regs.programPointer += 2;
  2188. }
  2189. }
  2190. // Extract the values from the context again
  2191. l_bc = m_regs.programPointer;
  2192. l_sp = m_regs.stackPointer;
  2193. l_fp = m_regs.stackFramePointer;
  2194. // If status isn't active anymore then we must stop
  2195. if( m_status != asEXECUTION_ACTIVE )
  2196. return;
  2197. }
  2198. break;
  2199. case asBC_SUSPEND:
  2200. if( m_regs.doProcessSuspend )
  2201. {
  2202. if( m_lineCallback )
  2203. {
  2204. m_regs.programPointer = l_bc;
  2205. m_regs.stackPointer = l_sp;
  2206. m_regs.stackFramePointer = l_fp;
  2207. CallLineCallback();
  2208. }
  2209. if( m_doSuspend )
  2210. {
  2211. l_bc++;
  2212. // Need to move the values back to the context
  2213. m_regs.programPointer = l_bc;
  2214. m_regs.stackPointer = l_sp;
  2215. m_regs.stackFramePointer = l_fp;
  2216. m_status = asEXECUTION_SUSPENDED;
  2217. return;
  2218. }
  2219. }
  2220. l_bc++;
  2221. break;
  2222. case asBC_ALLOC:
  2223. {
  2224. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  2225. int func = asBC_INTARG(l_bc+AS_PTR_SIZE);
  2226. if( objType->flags & asOBJ_SCRIPT_OBJECT )
  2227. {
  2228. // Need to move the values back to the context as the construction
  2229. // of the script object may reuse the context for nested calls.
  2230. m_regs.programPointer = l_bc;
  2231. m_regs.stackPointer = l_sp;
  2232. m_regs.stackFramePointer = l_fp;
  2233. // Pre-allocate the memory
  2234. asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
  2235. // Pre-initialize the memory by calling the constructor for asCScriptObject
  2236. ScriptObject_Construct(objType, (asCScriptObject*)mem);
  2237. // Call the constructor to initalize the memory
  2238. asCScriptFunction *f = m_engine->scriptFunctions[func];
  2239. asDWORD **a = (asDWORD**)*(asPWORD*)(m_regs.stackPointer + f->GetSpaceNeededForArguments());
  2240. if( a ) *a = mem;
  2241. // Push the object pointer on the stack
  2242. m_regs.stackPointer -= AS_PTR_SIZE;
  2243. *(asPWORD*)m_regs.stackPointer = (asPWORD)mem;
  2244. m_regs.programPointer += 2+AS_PTR_SIZE;
  2245. CallScriptFunction(f);
  2246. // Extract the values from the context again
  2247. l_bc = m_regs.programPointer;
  2248. l_sp = m_regs.stackPointer;
  2249. l_fp = m_regs.stackFramePointer;
  2250. // If status isn't active anymore then we must stop
  2251. if( m_status != asEXECUTION_ACTIVE )
  2252. return;
  2253. }
  2254. else
  2255. {
  2256. // Pre-allocate the memory
  2257. asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
  2258. if( func )
  2259. {
  2260. // Push the object pointer on the stack (it will be popped by the function)
  2261. l_sp -= AS_PTR_SIZE;
  2262. *(asPWORD*)l_sp = (asPWORD)mem;
  2263. // Need to move the values back to the context as the called functions
  2264. // may use the debug interface to inspect the registers
  2265. m_regs.programPointer = l_bc;
  2266. m_regs.stackPointer = l_sp;
  2267. m_regs.stackFramePointer = l_fp;
  2268. l_sp += CallSystemFunction(func, this);
  2269. }
  2270. // Pop the variable address from the stack
  2271. asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
  2272. l_sp += AS_PTR_SIZE;
  2273. if( a ) *a = mem;
  2274. l_bc += 2+AS_PTR_SIZE;
  2275. if( m_regs.doProcessSuspend )
  2276. {
  2277. // Should the execution be suspended?
  2278. if( m_doSuspend )
  2279. {
  2280. m_regs.programPointer = l_bc;
  2281. m_regs.stackPointer = l_sp;
  2282. m_regs.stackFramePointer = l_fp;
  2283. m_status = asEXECUTION_SUSPENDED;
  2284. return;
  2285. }
  2286. // An exception might have been raised
  2287. if( m_status != asEXECUTION_ACTIVE )
  2288. {
  2289. m_regs.programPointer = l_bc;
  2290. m_regs.stackPointer = l_sp;
  2291. m_regs.stackFramePointer = l_fp;
  2292. m_engine->CallFree(mem);
  2293. *a = 0;
  2294. return;
  2295. }
  2296. }
  2297. }
  2298. }
  2299. break;
  2300. case asBC_FREE:
  2301. {
  2302. // Get the variable that holds the object handle/reference
  2303. asPWORD *a = (asPWORD*)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  2304. if( *a )
  2305. {
  2306. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  2307. asSTypeBehaviour *beh = &objType->beh;
  2308. // Need to move the values back to the context as the called functions
  2309. // may use the debug interface to inspect the registers
  2310. m_regs.programPointer = l_bc;
  2311. m_regs.stackPointer = l_sp;
  2312. m_regs.stackFramePointer = l_fp;
  2313. if( objType->flags & asOBJ_REF )
  2314. {
  2315. asASSERT( (objType->flags & asOBJ_NOCOUNT) || beh->release );
  2316. if( beh->release )
  2317. m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->release);
  2318. }
  2319. else
  2320. {
  2321. if( beh->destruct )
  2322. m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->destruct);
  2323. else if( objType->flags & asOBJ_LIST_PATTERN )
  2324. m_engine->DestroyList((asBYTE*)(asPWORD)*a, objType);
  2325. m_engine->CallFree((void*)(asPWORD)*a);
  2326. }
  2327. // Clear the variable
  2328. *a = 0;
  2329. }
  2330. }
  2331. l_bc += 1+AS_PTR_SIZE;
  2332. break;
  2333. case asBC_LOADOBJ:
  2334. {
  2335. // Move the object pointer from the object variable into the object register
  2336. void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc));
  2337. m_regs.objectType = 0;
  2338. m_regs.objectRegister = *a;
  2339. *a = 0;
  2340. }
  2341. l_bc++;
  2342. break;
  2343. case asBC_STOREOBJ:
  2344. // Move the object pointer from the object register to the object variable
  2345. *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asPWORD(m_regs.objectRegister);
  2346. m_regs.objectRegister = 0;
  2347. l_bc++;
  2348. break;
  2349. case asBC_GETOBJ:
  2350. {
  2351. // Read variable index from location on stack
  2352. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2353. asPWORD offset = *a;
  2354. // Move pointer from variable to the same location on the stack
  2355. asPWORD *v = (asPWORD*)(l_fp - offset);
  2356. *a = *v;
  2357. // Clear variable
  2358. *v = 0;
  2359. }
  2360. l_bc++;
  2361. break;
  2362. case asBC_REFCPY:
  2363. {
  2364. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  2365. asSTypeBehaviour *beh = &objType->beh;
  2366. // Pop address of destination pointer from the stack
  2367. void **d = (void**)*(asPWORD*)l_sp;
  2368. l_sp += AS_PTR_SIZE;
  2369. // Read wanted pointer from the stack
  2370. void *s = (void*)*(asPWORD*)l_sp;
  2371. // Need to move the values back to the context as the called functions
  2372. // may use the debug interface to inspect the registers
  2373. m_regs.programPointer = l_bc;
  2374. m_regs.stackPointer = l_sp;
  2375. m_regs.stackFramePointer = l_fp;
  2376. // Update ref counter for object types that require it
  2377. if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) )
  2378. {
  2379. // Release previous object held by destination pointer
  2380. if( *d != 0 && beh->release )
  2381. m_engine->CallObjectMethod(*d, beh->release);
  2382. // Increase ref counter of wanted object
  2383. if( s != 0 && beh->addref )
  2384. m_engine->CallObjectMethod(s, beh->addref);
  2385. }
  2386. // Set the new object in the destination
  2387. *d = s;
  2388. }
  2389. l_bc += 1+AS_PTR_SIZE;
  2390. break;
  2391. case asBC_CHKREF:
  2392. {
  2393. // Verify if the pointer on the stack is null
  2394. // This is used when validating a pointer that an operator will work on
  2395. asPWORD a = *(asPWORD*)l_sp;
  2396. if( a == 0 )
  2397. {
  2398. m_regs.programPointer = l_bc;
  2399. m_regs.stackPointer = l_sp;
  2400. m_regs.stackFramePointer = l_fp;
  2401. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2402. return;
  2403. }
  2404. }
  2405. l_bc++;
  2406. break;
  2407. case asBC_GETOBJREF:
  2408. {
  2409. // Get the location on the stack where the reference will be placed
  2410. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2411. // Replace the variable index with the object handle held in the variable
  2412. *(asPWORD**)a = *(asPWORD**)(l_fp - *a);
  2413. }
  2414. l_bc++;
  2415. break;
  2416. case asBC_GETREF:
  2417. {
  2418. // Get the location on the stack where the reference will be placed
  2419. asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  2420. // Replace the variable index with the address of the variable
  2421. *(asPWORD**)a = (asPWORD*)(l_fp - (int)*a);
  2422. }
  2423. l_bc++;
  2424. break;
  2425. case asBC_PshNull:
  2426. // Push a null pointer on the stack
  2427. l_sp -= AS_PTR_SIZE;
  2428. *(asPWORD*)l_sp = 0;
  2429. l_bc++;
  2430. break;
  2431. case asBC_ClrVPtr:
  2432. // TODO: runtime optimize: Is this instruction really necessary?
  2433. // CallScriptFunction() can clear the null handles upon entry, just as is done for
  2434. // all other object variables
  2435. // Clear pointer variable
  2436. *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
  2437. l_bc++;
  2438. break;
  2439. case asBC_OBJTYPE:
  2440. // Push the object type on the stack
  2441. l_sp -= AS_PTR_SIZE;
  2442. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  2443. l_bc += 1+AS_PTR_SIZE;
  2444. break;
  2445. case asBC_TYPEID:
  2446. // Equivalent to PshC4, but kept as separate instruction for bytecode serialization
  2447. --l_sp;
  2448. *l_sp = asBC_DWORDARG(l_bc);
  2449. l_bc += 2;
  2450. break;
  2451. case asBC_SetV4:
  2452. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2453. l_bc += 2;
  2454. break;
  2455. case asBC_SetV8:
  2456. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc);
  2457. l_bc += 3;
  2458. break;
  2459. case asBC_ADDSi:
  2460. {
  2461. // The pointer must not be null
  2462. asPWORD a = *(asPWORD*)l_sp;
  2463. if( a == 0 )
  2464. {
  2465. m_regs.programPointer = l_bc;
  2466. m_regs.stackPointer = l_sp;
  2467. m_regs.stackFramePointer = l_fp;
  2468. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2469. return;
  2470. }
  2471. // Add an offset to the pointer
  2472. *(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc);
  2473. }
  2474. l_bc += 2;
  2475. break;
  2476. case asBC_CpyVtoV4:
  2477. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc));
  2478. l_bc += 2;
  2479. break;
  2480. case asBC_CpyVtoV8:
  2481. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2482. l_bc += 2;
  2483. break;
  2484. case asBC_CpyVtoR4:
  2485. *(asDWORD*)&m_regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2486. l_bc++;
  2487. break;
  2488. case asBC_CpyVtoR8:
  2489. *(asQWORD*)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2490. l_bc++;
  2491. break;
  2492. case asBC_CpyVtoG4:
  2493. *(asDWORD*)asBC_PTRARG(l_bc) = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2494. l_bc += 1 + AS_PTR_SIZE;
  2495. break;
  2496. case asBC_CpyRtoV4:
  2497. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&m_regs.valueRegister;
  2498. l_bc++;
  2499. break;
  2500. case asBC_CpyRtoV8:
  2501. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = m_regs.valueRegister;
  2502. l_bc++;
  2503. break;
  2504. case asBC_CpyGtoV4:
  2505. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)asBC_PTRARG(l_bc);
  2506. l_bc += 1 + AS_PTR_SIZE;
  2507. break;
  2508. case asBC_WRTV1:
  2509. // The pointer in the register points to a byte, and *(l_fp - offset) too
  2510. **(asBYTE**)&m_regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2511. l_bc++;
  2512. break;
  2513. case asBC_WRTV2:
  2514. // The pointer in the register points to a word, and *(l_fp - offset) too
  2515. **(asWORD**)&m_regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2516. l_bc++;
  2517. break;
  2518. case asBC_WRTV4:
  2519. **(asDWORD**)&m_regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc));
  2520. l_bc++;
  2521. break;
  2522. case asBC_WRTV8:
  2523. **(asQWORD**)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2524. l_bc++;
  2525. break;
  2526. case asBC_RDR1:
  2527. {
  2528. // The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte
  2529. asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2530. bPtr[0] = **(asBYTE**)&m_regs.valueRegister; // read the byte
  2531. bPtr[1] = 0; // 0 the rest of the DWORD
  2532. bPtr[2] = 0;
  2533. bPtr[3] = 0;
  2534. }
  2535. l_bc++;
  2536. break;
  2537. case asBC_RDR2:
  2538. {
  2539. // The pointer in the register points to a word, and *(l_fp - offset) will also point to a word
  2540. asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2541. wPtr[0] = **(asWORD**)&m_regs.valueRegister; // read the word
  2542. wPtr[1] = 0; // 0 the rest of the DWORD
  2543. }
  2544. l_bc++;
  2545. break;
  2546. case asBC_RDR4:
  2547. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
  2548. l_bc++;
  2549. break;
  2550. case asBC_RDR8:
  2551. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&m_regs.valueRegister;
  2552. l_bc++;
  2553. break;
  2554. case asBC_LDG:
  2555. *(asPWORD*)&m_regs.valueRegister = asBC_PTRARG(l_bc);
  2556. l_bc += 1+AS_PTR_SIZE;
  2557. break;
  2558. case asBC_LDV:
  2559. *(asDWORD**)&m_regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc));
  2560. l_bc++;
  2561. break;
  2562. case asBC_PGA:
  2563. l_sp -= AS_PTR_SIZE;
  2564. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  2565. l_bc += 1+AS_PTR_SIZE;
  2566. break;
  2567. case asBC_CmpPtr:
  2568. {
  2569. // TODO: runtime optimize: This instruction should really just be an equals, and return true or false.
  2570. // The instruction is only used for is and !is tests anyway.
  2571. asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2572. asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2573. if( p1 == p2 ) *(int*)&m_regs.valueRegister = 0;
  2574. else if( p1 < p2 ) *(int*)&m_regs.valueRegister = -1;
  2575. else *(int*)&m_regs.valueRegister = 1;
  2576. l_bc += 2;
  2577. }
  2578. break;
  2579. case asBC_VAR:
  2580. l_sp -= AS_PTR_SIZE;
  2581. *(asPWORD*)l_sp = (asPWORD)asBC_SWORDARG0(l_bc);
  2582. l_bc++;
  2583. break;
  2584. //----------------------------
  2585. // Type conversions
  2586. case asBC_iTOf:
  2587. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc)));
  2588. l_bc++;
  2589. break;
  2590. case asBC_fTOi:
  2591. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)));
  2592. l_bc++;
  2593. break;
  2594. case asBC_uTOf:
  2595. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc)));
  2596. l_bc++;
  2597. break;
  2598. case asBC_fTOu:
  2599. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2600. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))));
  2601. l_bc++;
  2602. break;
  2603. case asBC_sbTOi:
  2604. // *(l_fp - offset) points to a char, and will point to an int afterwards
  2605. *(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc));
  2606. l_bc++;
  2607. break;
  2608. case asBC_swTOi:
  2609. // *(l_fp - offset) points to a short, and will point to an int afterwards
  2610. *(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc));
  2611. l_bc++;
  2612. break;
  2613. case asBC_ubTOi:
  2614. // (l_fp - offset) points to a byte, and will point to an int afterwards
  2615. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2616. l_bc++;
  2617. break;
  2618. case asBC_uwTOi:
  2619. // *(l_fp - offset) points to a word, and will point to an int afterwards
  2620. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2621. l_bc++;
  2622. break;
  2623. case asBC_dTOi:
  2624. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2625. l_bc += 2;
  2626. break;
  2627. case asBC_dTOu:
  2628. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2629. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))));
  2630. l_bc += 2;
  2631. break;
  2632. case asBC_dTOf:
  2633. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2634. l_bc += 2;
  2635. break;
  2636. case asBC_iTOd:
  2637. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2638. l_bc += 2;
  2639. break;
  2640. case asBC_uTOd:
  2641. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2642. l_bc += 2;
  2643. break;
  2644. case asBC_fTOd:
  2645. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2646. l_bc += 2;
  2647. break;
  2648. //------------------------------
  2649. // Math operations
  2650. case asBC_ADDi:
  2651. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2652. l_bc += 2;
  2653. break;
  2654. case asBC_SUBi:
  2655. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2656. l_bc += 2;
  2657. break;
  2658. case asBC_MULi:
  2659. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2660. l_bc += 2;
  2661. break;
  2662. case asBC_DIVi:
  2663. {
  2664. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2665. if( divider == 0 )
  2666. {
  2667. // Need to move the values back to the context
  2668. m_regs.programPointer = l_bc;
  2669. m_regs.stackPointer = l_sp;
  2670. m_regs.stackFramePointer = l_fp;
  2671. // Raise exception
  2672. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2673. return;
  2674. }
  2675. else if( divider == -1 )
  2676. {
  2677. // Need to check if the value that is divided is 0x80000000
  2678. // as dividing it with -1 will cause an overflow exception
  2679. if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
  2680. {
  2681. // Need to move the values back to the context
  2682. m_regs.programPointer = l_bc;
  2683. m_regs.stackPointer = l_sp;
  2684. m_regs.stackFramePointer = l_fp;
  2685. // Raise exception
  2686. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2687. return;
  2688. }
  2689. }
  2690. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2691. }
  2692. l_bc += 2;
  2693. break;
  2694. case asBC_MODi:
  2695. {
  2696. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2697. if( divider == 0 )
  2698. {
  2699. // Need to move the values back to the context
  2700. m_regs.programPointer = l_bc;
  2701. m_regs.stackPointer = l_sp;
  2702. m_regs.stackFramePointer = l_fp;
  2703. // Raise exception
  2704. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2705. return;
  2706. }
  2707. else if( divider == -1 )
  2708. {
  2709. // Need to check if the value that is divided is 0x80000000
  2710. // as dividing it with -1 will cause an overflow exception
  2711. if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
  2712. {
  2713. // Need to move the values back to the context
  2714. m_regs.programPointer = l_bc;
  2715. m_regs.stackPointer = l_sp;
  2716. m_regs.stackFramePointer = l_fp;
  2717. // Raise exception
  2718. SetInternalException(TXT_DIVIDE_OVERFLOW);
  2719. return;
  2720. }
  2721. }
  2722. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  2723. }
  2724. l_bc += 2;
  2725. break;
  2726. case asBC_ADDf:
  2727. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2728. l_bc += 2;
  2729. break;
  2730. case asBC_SUBf:
  2731. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2732. l_bc += 2;
  2733. break;
  2734. case asBC_MULf:
  2735. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2736. l_bc += 2;
  2737. break;
  2738. case asBC_DIVf:
  2739. {
  2740. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2741. if( divider == 0 )
  2742. {
  2743. // Need to move the values back to the context
  2744. m_regs.programPointer = l_bc;
  2745. m_regs.stackPointer = l_sp;
  2746. m_regs.stackFramePointer = l_fp;
  2747. // Raise exception
  2748. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2749. return;
  2750. }
  2751. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2752. }
  2753. l_bc += 2;
  2754. break;
  2755. case asBC_MODf:
  2756. {
  2757. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2758. if( divider == 0 )
  2759. {
  2760. // Need to move the values back to the context
  2761. m_regs.programPointer = l_bc;
  2762. m_regs.stackPointer = l_sp;
  2763. m_regs.stackFramePointer = l_fp;
  2764. // Raise exception
  2765. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2766. return;
  2767. }
  2768. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2769. }
  2770. l_bc += 2;
  2771. break;
  2772. case asBC_ADDd:
  2773. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2774. l_bc += 2;
  2775. break;
  2776. case asBC_SUBd:
  2777. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2778. l_bc += 2;
  2779. break;
  2780. case asBC_MULd:
  2781. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2782. l_bc += 2;
  2783. break;
  2784. case asBC_DIVd:
  2785. {
  2786. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2787. if( divider == 0 )
  2788. {
  2789. // Need to move the values back to the context
  2790. m_regs.programPointer = l_bc;
  2791. m_regs.stackPointer = l_sp;
  2792. m_regs.stackFramePointer = l_fp;
  2793. // Raise exception
  2794. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2795. return;
  2796. }
  2797. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2798. l_bc += 2;
  2799. }
  2800. break;
  2801. case asBC_MODd:
  2802. {
  2803. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2804. if( divider == 0 )
  2805. {
  2806. // Need to move the values back to the context
  2807. m_regs.programPointer = l_bc;
  2808. m_regs.stackPointer = l_sp;
  2809. m_regs.stackFramePointer = l_fp;
  2810. // Raise exception
  2811. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2812. return;
  2813. }
  2814. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2815. l_bc += 2;
  2816. }
  2817. break;
  2818. //------------------------------
  2819. // Math operations with constant value
  2820. case asBC_ADDIi:
  2821. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1);
  2822. l_bc += 3;
  2823. break;
  2824. case asBC_SUBIi:
  2825. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1);
  2826. l_bc += 3;
  2827. break;
  2828. case asBC_MULIi:
  2829. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1);
  2830. l_bc += 3;
  2831. break;
  2832. case asBC_ADDIf:
  2833. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1);
  2834. l_bc += 3;
  2835. break;
  2836. case asBC_SUBIf:
  2837. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1);
  2838. l_bc += 3;
  2839. break;
  2840. case asBC_MULIf:
  2841. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1);
  2842. l_bc += 3;
  2843. break;
  2844. //-----------------------------------
  2845. case asBC_SetG4:
  2846. *(asDWORD*)asBC_PTRARG(l_bc) = asBC_DWORDARG(l_bc+AS_PTR_SIZE);
  2847. l_bc += 2 + AS_PTR_SIZE;
  2848. break;
  2849. case asBC_ChkRefS:
  2850. {
  2851. // Verify if the pointer on the stack refers to a non-null value
  2852. // This is used to validate a reference to a handle
  2853. asPWORD *a = (asPWORD*)*(asPWORD*)l_sp;
  2854. if( *a == 0 )
  2855. {
  2856. m_regs.programPointer = l_bc;
  2857. m_regs.stackPointer = l_sp;
  2858. m_regs.stackFramePointer = l_fp;
  2859. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2860. return;
  2861. }
  2862. }
  2863. l_bc++;
  2864. break;
  2865. case asBC_ChkNullV:
  2866. {
  2867. // Verify if variable (on the stack) is not null
  2868. asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc));
  2869. if( a == 0 )
  2870. {
  2871. m_regs.programPointer = l_bc;
  2872. m_regs.stackPointer = l_sp;
  2873. m_regs.stackFramePointer = l_fp;
  2874. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2875. return;
  2876. }
  2877. }
  2878. l_bc++;
  2879. break;
  2880. case asBC_CALLINTF:
  2881. {
  2882. int i = asBC_INTARG(l_bc);
  2883. l_bc += 2;
  2884. asASSERT( i >= 0 );
  2885. asASSERT( (i & FUNC_IMPORTED) == 0 );
  2886. // Need to move the values back to the context
  2887. m_regs.programPointer = l_bc;
  2888. m_regs.stackPointer = l_sp;
  2889. m_regs.stackFramePointer = l_fp;
  2890. CallInterfaceMethod(m_engine->GetScriptFunction(i));
  2891. // Extract the values from the context again
  2892. l_bc = m_regs.programPointer;
  2893. l_sp = m_regs.stackPointer;
  2894. l_fp = m_regs.stackFramePointer;
  2895. // If status isn't active anymore then we must stop
  2896. if( m_status != asEXECUTION_ACTIVE )
  2897. return;
  2898. }
  2899. break;
  2900. case asBC_iTOb:
  2901. {
  2902. // *(l_fp - offset) points to an int, and will point to a byte afterwards
  2903. // We need to use volatile here to tell the compiler not to rearrange
  2904. // read and write operations during optimizations.
  2905. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2906. volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2907. bPtr[0] = (asBYTE)val; // write the byte
  2908. bPtr[1] = 0; // 0 the rest of the DWORD
  2909. bPtr[2] = 0;
  2910. bPtr[3] = 0;
  2911. }
  2912. l_bc++;
  2913. break;
  2914. case asBC_iTOw:
  2915. {
  2916. // *(l_fp - offset) points to an int, and will point to word afterwards
  2917. // We need to use volatile here to tell the compiler not to rearrange
  2918. // read and write operations during optimizations.
  2919. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2920. volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2921. wPtr[0] = (asWORD)val; // write the word
  2922. wPtr[1] = 0; // 0 the rest of the DWORD
  2923. }
  2924. l_bc++;
  2925. break;
  2926. case asBC_SetV1:
  2927. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2928. // when the bytecode instructions were more tightly packed. It can now
  2929. // be removed. When removing it, make sure the value is correctly converted
  2930. // on big-endian CPUs.
  2931. // The byte is already stored correctly in the argument
  2932. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2933. l_bc += 2;
  2934. break;
  2935. case asBC_SetV2:
  2936. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2937. // when the bytecode instructions were more tightly packed. It can now
  2938. // be removed. When removing it, make sure the value is correctly converted
  2939. // on big-endian CPUs.
  2940. // The word is already stored correctly in the argument
  2941. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2942. l_bc += 2;
  2943. break;
  2944. case asBC_Cast:
  2945. // Cast the handle at the top of the stack to the type in the argument
  2946. {
  2947. asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
  2948. if( a && *a )
  2949. {
  2950. asDWORD typeId = asBC_DWORDARG(l_bc);
  2951. asCScriptObject *obj = (asCScriptObject *)* a;
  2952. asCObjectType *objType = obj->objType;
  2953. asCObjectType *to = m_engine->GetObjectTypeFromTypeId(typeId);
  2954. // This instruction can only be used with script classes and interfaces
  2955. asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT );
  2956. asASSERT( to->flags & asOBJ_SCRIPT_OBJECT );
  2957. if( objType->Implements(to) || objType->DerivesFrom(to) )
  2958. {
  2959. m_regs.objectType = 0;
  2960. m_regs.objectRegister = obj;
  2961. obj->AddRef();
  2962. }
  2963. else
  2964. {
  2965. // The object register should already be null, so there
  2966. // is no need to clear it if the cast is unsuccessful
  2967. asASSERT( m_regs.objectRegister == 0 );
  2968. }
  2969. }
  2970. l_sp += AS_PTR_SIZE;
  2971. }
  2972. l_bc += 2;
  2973. break;
  2974. case asBC_i64TOi:
  2975. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  2976. l_bc += 2;
  2977. break;
  2978. case asBC_uTOi64:
  2979. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2980. l_bc += 2;
  2981. break;
  2982. case asBC_iTOi64:
  2983. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2984. l_bc += 2;
  2985. break;
  2986. case asBC_fTOi64:
  2987. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2988. l_bc += 2;
  2989. break;
  2990. case asBC_dTOi64:
  2991. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)));
  2992. l_bc++;
  2993. break;
  2994. case asBC_fTOu64:
  2995. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))));
  2996. l_bc += 2;
  2997. break;
  2998. case asBC_dTOu64:
  2999. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))));
  3000. l_bc++;
  3001. break;
  3002. case asBC_i64TOf:
  3003. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  3004. l_bc += 2;
  3005. break;
  3006. case asBC_u64TOf:
  3007. #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
  3008. {
  3009. // MSVC6 doesn't permit UINT64 to double
  3010. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  3011. if( v < 0 )
  3012. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v);
  3013. else
  3014. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v);
  3015. }
  3016. #else
  3017. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)));
  3018. #endif
  3019. l_bc += 2;
  3020. break;
  3021. case asBC_i64TOd:
  3022. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)));
  3023. l_bc++;
  3024. break;
  3025. case asBC_u64TOd:
  3026. #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
  3027. {
  3028. // MSVC6 doesn't permit UINT64 to double
  3029. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  3030. if( v < 0 )
  3031. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v);
  3032. else
  3033. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v);
  3034. }
  3035. #else
  3036. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)));
  3037. #endif
  3038. l_bc++;
  3039. break;
  3040. case asBC_NEGi64:
  3041. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  3042. l_bc++;
  3043. break;
  3044. case asBC_INCi64:
  3045. ++(**(asQWORD**)&m_regs.valueRegister);
  3046. l_bc++;
  3047. break;
  3048. case asBC_DECi64:
  3049. --(**(asQWORD**)&m_regs.valueRegister);
  3050. l_bc++;
  3051. break;
  3052. case asBC_BNOT64:
  3053. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3054. l_bc++;
  3055. break;
  3056. case asBC_ADDi64:
  3057. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3058. l_bc += 2;
  3059. break;
  3060. case asBC_SUBi64:
  3061. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3062. l_bc += 2;
  3063. break;
  3064. case asBC_MULi64:
  3065. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3066. l_bc += 2;
  3067. break;
  3068. case asBC_DIVi64:
  3069. {
  3070. asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
  3071. if( divider == 0 )
  3072. {
  3073. // Need to move the values back to the context
  3074. m_regs.programPointer = l_bc;
  3075. m_regs.stackPointer = l_sp;
  3076. m_regs.stackFramePointer = l_fp;
  3077. // Raise exception
  3078. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3079. return;
  3080. }
  3081. else if( divider == -1 )
  3082. {
  3083. // Need to check if the value that is divided is 1<<63
  3084. // as dividing it with -1 will cause an overflow exception
  3085. if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
  3086. {
  3087. // Need to move the values back to the context
  3088. m_regs.programPointer = l_bc;
  3089. m_regs.stackPointer = l_sp;
  3090. m_regs.stackFramePointer = l_fp;
  3091. // Raise exception
  3092. SetInternalException(TXT_DIVIDE_OVERFLOW);
  3093. return;
  3094. }
  3095. }
  3096. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  3097. }
  3098. l_bc += 2;
  3099. break;
  3100. case asBC_MODi64:
  3101. {
  3102. asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
  3103. if( divider == 0 )
  3104. {
  3105. // Need to move the values back to the context
  3106. m_regs.programPointer = l_bc;
  3107. m_regs.stackPointer = l_sp;
  3108. m_regs.stackFramePointer = l_fp;
  3109. // Raise exception
  3110. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3111. return;
  3112. }
  3113. else if( divider == -1 )
  3114. {
  3115. // Need to check if the value that is divided is 1<<63
  3116. // as dividing it with -1 will cause an overflow exception
  3117. if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
  3118. {
  3119. // Need to move the values back to the context
  3120. m_regs.programPointer = l_bc;
  3121. m_regs.stackPointer = l_sp;
  3122. m_regs.stackFramePointer = l_fp;
  3123. // Raise exception
  3124. SetInternalException(TXT_DIVIDE_OVERFLOW);
  3125. return;
  3126. }
  3127. }
  3128. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  3129. }
  3130. l_bc += 2;
  3131. break;
  3132. case asBC_BAND64:
  3133. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3134. l_bc += 2;
  3135. break;
  3136. case asBC_BOR64:
  3137. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3138. l_bc += 2;
  3139. break;
  3140. case asBC_BXOR64:
  3141. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3142. l_bc += 2;
  3143. break;
  3144. case asBC_BSLL64:
  3145. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  3146. l_bc += 2;
  3147. break;
  3148. case asBC_BSRL64:
  3149. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  3150. l_bc += 2;
  3151. break;
  3152. case asBC_BSRA64:
  3153. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  3154. l_bc += 2;
  3155. break;
  3156. case asBC_CMPi64:
  3157. {
  3158. asINT64 i1 = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  3159. asINT64 i2 = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  3160. if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0;
  3161. else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
  3162. else *(int*)&m_regs.valueRegister = 1;
  3163. l_bc += 2;
  3164. }
  3165. break;
  3166. case asBC_CMPu64:
  3167. {
  3168. asQWORD d1 = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3169. asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  3170. if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0;
  3171. else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
  3172. else *(int*)&m_regs.valueRegister = 1;
  3173. l_bc += 2;
  3174. }
  3175. break;
  3176. case asBC_ChkNullS:
  3177. {
  3178. // Verify if the pointer on the stack is null
  3179. // This is used for example when validating handles passed as function arguments
  3180. asPWORD a = *(asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
  3181. if( a == 0 )
  3182. {
  3183. m_regs.programPointer = l_bc;
  3184. m_regs.stackPointer = l_sp;
  3185. m_regs.stackFramePointer = l_fp;
  3186. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3187. return;
  3188. }
  3189. }
  3190. l_bc++;
  3191. break;
  3192. case asBC_ClrHi:
  3193. #if AS_SIZEOF_BOOL == 1
  3194. {
  3195. // Clear the upper bytes, so that trash data don't interfere with boolean operations
  3196. // We need to use volatile here to tell the compiler it cannot
  3197. // change the order of read and write operations on the pointer.
  3198. volatile asBYTE *ptr = (asBYTE*)&m_regs.valueRegister;
  3199. ptr[1] = 0; // The boolean value is stored in the lower byte, so we clear the rest
  3200. ptr[2] = 0;
  3201. ptr[3] = 0;
  3202. }
  3203. #else
  3204. // We don't have anything to do here
  3205. #endif
  3206. l_bc++;
  3207. break;
  3208. case asBC_JitEntry:
  3209. {
  3210. if( m_currentFunction->scriptData->jitFunction )
  3211. {
  3212. asPWORD jitArg = asBC_PTRARG(l_bc);
  3213. if( jitArg )
  3214. {
  3215. // Resume JIT operation
  3216. m_regs.programPointer = l_bc;
  3217. m_regs.stackPointer = l_sp;
  3218. m_regs.stackFramePointer = l_fp;
  3219. (m_currentFunction->scriptData->jitFunction)(&m_regs, jitArg);
  3220. l_bc = m_regs.programPointer;
  3221. l_sp = m_regs.stackPointer;
  3222. l_fp = m_regs.stackFramePointer;
  3223. // If status isn't active anymore then we must stop
  3224. if( m_status != asEXECUTION_ACTIVE )
  3225. return;
  3226. break;
  3227. }
  3228. }
  3229. // Not a JIT resume point, treat as nop
  3230. l_bc += 1+AS_PTR_SIZE;
  3231. }
  3232. break;
  3233. case asBC_CallPtr:
  3234. {
  3235. // Get the function pointer from the local variable
  3236. asCScriptFunction *func = *(asCScriptFunction**)(l_fp - asBC_SWORDARG0(l_bc));
  3237. // Need to move the values back to the context
  3238. m_regs.programPointer = l_bc;
  3239. m_regs.stackPointer = l_sp;
  3240. m_regs.stackFramePointer = l_fp;
  3241. if( func == 0 )
  3242. {
  3243. // Need to update the program pointer anyway for the exception handler
  3244. m_regs.programPointer++;
  3245. // Tell the exception handler to clean up the arguments to this method
  3246. m_needToCleanupArgs = true;
  3247. // TODO: funcdef: Should we have a different exception string?
  3248. SetInternalException(TXT_UNBOUND_FUNCTION);
  3249. return;
  3250. }
  3251. else
  3252. {
  3253. if (func->funcType == asFUNC_SCRIPT)
  3254. {
  3255. m_regs.programPointer++;
  3256. CallScriptFunction(func);
  3257. }
  3258. else if (func->funcType == asFUNC_DELEGATE)
  3259. {
  3260. // Push the object pointer on the stack. There is always a reserved space for this so
  3261. // we don't don't need to worry about overflowing the allocated memory buffer
  3262. asASSERT(m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex]);
  3263. m_regs.stackPointer -= AS_PTR_SIZE;
  3264. *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
  3265. // Call the delegated method
  3266. if (func->funcForDelegate->funcType == asFUNC_SYSTEM)
  3267. {
  3268. m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
  3269. // Update program position after the call so the line number
  3270. // is correct in case the system function queries it
  3271. m_regs.programPointer++;
  3272. }
  3273. else
  3274. {
  3275. m_regs.programPointer++;
  3276. // TODO: run-time optimize: The true method could be figured out when creating the delegate
  3277. CallInterfaceMethod(func->funcForDelegate);
  3278. }
  3279. }
  3280. else if (func->funcType == asFUNC_SYSTEM)
  3281. {
  3282. m_regs.stackPointer += CallSystemFunction(func->id, this);
  3283. // Update program position after the call so the line number
  3284. // is correct in case the system function queries it
  3285. m_regs.programPointer++;
  3286. }
  3287. else if (func->funcType == asFUNC_IMPORTED)
  3288. {
  3289. m_regs.programPointer++;
  3290. int funcId = m_engine->importedFunctions[func->id & ~FUNC_IMPORTED]->boundFunctionId;
  3291. if (funcId > 0)
  3292. CallScriptFunction(m_engine->scriptFunctions[funcId]);
  3293. else
  3294. {
  3295. // Tell the exception handler to clean up the arguments to this method
  3296. m_needToCleanupArgs = true;
  3297. SetInternalException(TXT_UNBOUND_FUNCTION);
  3298. }
  3299. }
  3300. else
  3301. {
  3302. // Should not get here
  3303. asASSERT(false);
  3304. }
  3305. }
  3306. // Extract the values from the context again
  3307. l_bc = m_regs.programPointer;
  3308. l_sp = m_regs.stackPointer;
  3309. l_fp = m_regs.stackFramePointer;
  3310. // If status isn't active anymore then we must stop
  3311. if( m_status != asEXECUTION_ACTIVE )
  3312. return;
  3313. }
  3314. break;
  3315. case asBC_FuncPtr:
  3316. // Push the function pointer on the stack. The pointer is in the argument
  3317. l_sp -= AS_PTR_SIZE;
  3318. *(asPWORD*)l_sp = asBC_PTRARG(l_bc);
  3319. l_bc += 1+AS_PTR_SIZE;
  3320. break;
  3321. case asBC_LoadThisR:
  3322. {
  3323. // PshVPtr 0
  3324. asPWORD tmp = *(asPWORD*)l_fp;
  3325. // Make sure the pointer is not null
  3326. if( tmp == 0 )
  3327. {
  3328. // Need to move the values back to the context
  3329. m_regs.programPointer = l_bc;
  3330. m_regs.stackPointer = l_sp;
  3331. m_regs.stackFramePointer = l_fp;
  3332. // Raise exception
  3333. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3334. return;
  3335. }
  3336. // ADDSi
  3337. tmp = tmp + asBC_SWORDARG0(l_bc);
  3338. // PopRPtr
  3339. *(asPWORD*)&m_regs.valueRegister = tmp;
  3340. l_bc += 2;
  3341. }
  3342. break;
  3343. // Push the qword value of a variable on the stack
  3344. case asBC_PshV8:
  3345. l_sp -= 2;
  3346. *(asQWORD*)l_sp = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3347. l_bc++;
  3348. break;
  3349. case asBC_DIVu:
  3350. {
  3351. asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
  3352. if( divider == 0 )
  3353. {
  3354. // Need to move the values back to the context
  3355. m_regs.programPointer = l_bc;
  3356. m_regs.stackPointer = l_sp;
  3357. m_regs.stackFramePointer = l_fp;
  3358. // Raise exception
  3359. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3360. return;
  3361. }
  3362. *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  3363. }
  3364. l_bc += 2;
  3365. break;
  3366. case asBC_MODu:
  3367. {
  3368. asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
  3369. if( divider == 0 )
  3370. {
  3371. // Need to move the values back to the context
  3372. m_regs.programPointer = l_bc;
  3373. m_regs.stackPointer = l_sp;
  3374. m_regs.stackFramePointer = l_fp;
  3375. // Raise exception
  3376. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3377. return;
  3378. }
  3379. *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  3380. }
  3381. l_bc += 2;
  3382. break;
  3383. case asBC_DIVu64:
  3384. {
  3385. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3386. if( divider == 0 )
  3387. {
  3388. // Need to move the values back to the context
  3389. m_regs.programPointer = l_bc;
  3390. m_regs.stackPointer = l_sp;
  3391. m_regs.stackFramePointer = l_fp;
  3392. // Raise exception
  3393. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3394. return;
  3395. }
  3396. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  3397. }
  3398. l_bc += 2;
  3399. break;
  3400. case asBC_MODu64:
  3401. {
  3402. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  3403. if( divider == 0 )
  3404. {
  3405. // Need to move the values back to the context
  3406. m_regs.programPointer = l_bc;
  3407. m_regs.stackPointer = l_sp;
  3408. m_regs.stackFramePointer = l_fp;
  3409. // Raise exception
  3410. SetInternalException(TXT_DIVIDE_BY_ZERO);
  3411. return;
  3412. }
  3413. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  3414. }
  3415. l_bc += 2;
  3416. break;
  3417. case asBC_LoadRObjR:
  3418. {
  3419. // PshVPtr x
  3420. asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  3421. // Make sure the pointer is not null
  3422. if( tmp == 0 )
  3423. {
  3424. // Need to move the values back to the context
  3425. m_regs.programPointer = l_bc;
  3426. m_regs.stackPointer = l_sp;
  3427. m_regs.stackFramePointer = l_fp;
  3428. // Raise exception
  3429. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3430. return;
  3431. }
  3432. // ADDSi y
  3433. tmp = tmp + asBC_SWORDARG1(l_bc);
  3434. // PopRPtr
  3435. *(asPWORD*)&m_regs.valueRegister = tmp;
  3436. l_bc += 3;
  3437. }
  3438. break;
  3439. case asBC_LoadVObjR:
  3440. {
  3441. // PSF x
  3442. asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc));
  3443. // ADDSi y
  3444. tmp = tmp + asBC_SWORDARG1(l_bc);
  3445. // PopRPtr
  3446. *(asPWORD*)&m_regs.valueRegister = tmp;
  3447. l_bc += 3;
  3448. }
  3449. break;
  3450. case asBC_RefCpyV:
  3451. // Same as PSF v, REFCPY
  3452. {
  3453. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
  3454. asSTypeBehaviour *beh = &objType->beh;
  3455. // Determine destination from argument
  3456. void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
  3457. // Read wanted pointer from the stack
  3458. void *s = (void*)*(asPWORD*)l_sp;
  3459. // Need to move the values back to the context as the called functions
  3460. // may use the debug interface to inspect the registers
  3461. m_regs.programPointer = l_bc;
  3462. m_regs.stackPointer = l_sp;
  3463. m_regs.stackFramePointer = l_fp;
  3464. // Update ref counter for object types that require it
  3465. if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) )
  3466. {
  3467. // Release previous object held by destination pointer
  3468. if( *d != 0 && beh->release )
  3469. m_engine->CallObjectMethod(*d, beh->release);
  3470. // Increase ref counter of wanted object
  3471. if( s != 0 && beh->addref )
  3472. m_engine->CallObjectMethod(s, beh->addref);
  3473. }
  3474. // Set the new object in the destination
  3475. *d = s;
  3476. }
  3477. l_bc += 1+AS_PTR_SIZE;
  3478. break;
  3479. case asBC_JLowZ:
  3480. if( *(asBYTE*)&m_regs.valueRegister == 0 )
  3481. l_bc += asBC_INTARG(l_bc) + 2;
  3482. else
  3483. l_bc += 2;
  3484. break;
  3485. case asBC_JLowNZ:
  3486. if( *(asBYTE*)&m_regs.valueRegister != 0 )
  3487. l_bc += asBC_INTARG(l_bc) + 2;
  3488. else
  3489. l_bc += 2;
  3490. break;
  3491. case asBC_AllocMem:
  3492. // Allocate a buffer and store the pointer in the local variable
  3493. {
  3494. // TODO: runtime optimize: As the list buffers are going to be short lived, it may be interesting
  3495. // to use a memory pool to avoid reallocating the memory all the time
  3496. asUINT size = asBC_DWORDARG(l_bc);
  3497. asBYTE **var = (asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
  3498. #ifndef WIP_16BYTE_ALIGN
  3499. *var = asNEWARRAY(asBYTE, size);
  3500. #else
  3501. *var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT);
  3502. #endif
  3503. // Clear the buffer for the pointers that will be placed in it
  3504. memset(*var, 0, size);
  3505. }
  3506. l_bc += 2;
  3507. break;
  3508. case asBC_SetListSize:
  3509. {
  3510. // Set the size element in the buffer
  3511. asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
  3512. asUINT off = asBC_DWORDARG(l_bc);
  3513. asUINT size = asBC_DWORDARG(l_bc+1);
  3514. asASSERT( var );
  3515. *(asUINT*)(var+off) = size;
  3516. }
  3517. l_bc += 3;
  3518. break;
  3519. case asBC_PshListElmnt:
  3520. {
  3521. // Push the pointer to the list element on the stack
  3522. // In essence it does the same as PSF, RDSPtr, ADDSi
  3523. asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
  3524. asUINT off = asBC_DWORDARG(l_bc);
  3525. asASSERT( var );
  3526. l_sp -= AS_PTR_SIZE;
  3527. *(asPWORD*)l_sp = asPWORD(var+off);
  3528. }
  3529. l_bc += 2;
  3530. break;
  3531. case asBC_SetListType:
  3532. {
  3533. // Set the type id in the buffer
  3534. asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
  3535. asUINT off = asBC_DWORDARG(l_bc);
  3536. asUINT type = asBC_DWORDARG(l_bc+1);
  3537. asASSERT( var );
  3538. *(asUINT*)(var+off) = type;
  3539. }
  3540. l_bc += 3;
  3541. break;
  3542. //------------------------------
  3543. // Exponent operations
  3544. case asBC_POWi:
  3545. {
  3546. bool isOverflow;
  3547. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi(*(int*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
  3548. if( isOverflow )
  3549. {
  3550. // Need to move the values back to the context
  3551. m_regs.programPointer = l_bc;
  3552. m_regs.stackPointer = l_sp;
  3553. m_regs.stackFramePointer = l_fp;
  3554. // Raise exception
  3555. SetInternalException(TXT_POW_OVERFLOW);
  3556. return;
  3557. }
  3558. }
  3559. l_bc += 2;
  3560. break;
  3561. case asBC_POWu:
  3562. {
  3563. bool isOverflow;
  3564. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu(*(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asDWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
  3565. if( isOverflow )
  3566. {
  3567. // Need to move the values back to the context
  3568. m_regs.programPointer = l_bc;
  3569. m_regs.stackPointer = l_sp;
  3570. m_regs.stackFramePointer = l_fp;
  3571. // Raise exception
  3572. SetInternalException(TXT_POW_OVERFLOW);
  3573. return;
  3574. }
  3575. }
  3576. l_bc += 2;
  3577. break;
  3578. case asBC_POWf:
  3579. {
  3580. float r = powf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), *(float*)(l_fp - asBC_SWORDARG2(l_bc)));
  3581. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
  3582. if( r == float(HUGE_VAL) )
  3583. {
  3584. // Need to move the values back to the context
  3585. m_regs.programPointer = l_bc;
  3586. m_regs.stackPointer = l_sp;
  3587. m_regs.stackFramePointer = l_fp;
  3588. // Raise exception
  3589. SetInternalException(TXT_POW_OVERFLOW);
  3590. return;
  3591. }
  3592. }
  3593. l_bc += 2;
  3594. break;
  3595. case asBC_POWd:
  3596. {
  3597. double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(double*)(l_fp - asBC_SWORDARG2(l_bc)));
  3598. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
  3599. if( r == HUGE_VAL )
  3600. {
  3601. // Need to move the values back to the context
  3602. m_regs.programPointer = l_bc;
  3603. m_regs.stackPointer = l_sp;
  3604. m_regs.stackFramePointer = l_fp;
  3605. // Raise exception
  3606. SetInternalException(TXT_POW_OVERFLOW);
  3607. return;
  3608. }
  3609. }
  3610. l_bc += 2;
  3611. break;
  3612. case asBC_POWdi:
  3613. {
  3614. double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)));
  3615. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
  3616. if( r == HUGE_VAL )
  3617. {
  3618. // Need to move the values back to the context
  3619. m_regs.programPointer = l_bc;
  3620. m_regs.stackPointer = l_sp;
  3621. m_regs.stackFramePointer = l_fp;
  3622. // Raise exception
  3623. SetInternalException(TXT_POW_OVERFLOW);
  3624. return;
  3625. }
  3626. l_bc += 2;
  3627. }
  3628. break;
  3629. case asBC_POWi64:
  3630. {
  3631. bool isOverflow;
  3632. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi64(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)), *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
  3633. if( isOverflow )
  3634. {
  3635. // Need to move the values back to the context
  3636. m_regs.programPointer = l_bc;
  3637. m_regs.stackPointer = l_sp;
  3638. m_regs.stackFramePointer = l_fp;
  3639. // Raise exception
  3640. SetInternalException(TXT_POW_OVERFLOW);
  3641. return;
  3642. }
  3643. }
  3644. l_bc += 2;
  3645. break;
  3646. case asBC_POWu64:
  3647. {
  3648. bool isOverflow;
  3649. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu64(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
  3650. if( isOverflow )
  3651. {
  3652. // Need to move the values back to the context
  3653. m_regs.programPointer = l_bc;
  3654. m_regs.stackPointer = l_sp;
  3655. m_regs.stackFramePointer = l_fp;
  3656. // Raise exception
  3657. SetInternalException(TXT_POW_OVERFLOW);
  3658. return;
  3659. }
  3660. }
  3661. l_bc += 2;
  3662. break;
  3663. case asBC_Thiscall1:
  3664. // This instruction is a faster version of asBC_CALLSYS. It is faster because
  3665. // it has much less runtime overhead with determining the calling convention
  3666. // and no dynamic code for loading the parameters. The instruction can only
  3667. // be used to call functions with the following signatures:
  3668. //
  3669. // type &obj::func(int)
  3670. // type &obj::func(uint)
  3671. // void obj::func(int)
  3672. // void obj::func(uint)
  3673. {
  3674. // Get function ID from the argument
  3675. int i = asBC_INTARG(l_bc);
  3676. // Need to move the values back to the context as the called functions
  3677. // may use the debug interface to inspect the registers
  3678. m_regs.programPointer = l_bc;
  3679. m_regs.stackPointer = l_sp;
  3680. m_regs.stackFramePointer = l_fp;
  3681. // Pop the thispointer from the stack
  3682. void *obj = *(void**)l_sp;
  3683. if (obj == 0)
  3684. SetInternalException(TXT_NULL_POINTER_ACCESS);
  3685. else
  3686. {
  3687. // Only update the stack pointer if all is OK so the
  3688. // exception handler can properly clean up the stack
  3689. l_sp += AS_PTR_SIZE;
  3690. // Pop the int arg from the stack
  3691. int arg = *(int*)l_sp;
  3692. l_sp++;
  3693. // Call the method
  3694. m_callingSystemFunction = m_engine->scriptFunctions[i];
  3695. void *ptr = 0;
  3696. #ifdef AS_NO_EXCEPTIONS
  3697. ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction);
  3698. #else
  3699. // This try/catch block is to catch potential exception that may
  3700. // be thrown by the registered function.
  3701. try
  3702. {
  3703. ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction);
  3704. }
  3705. catch (...)
  3706. {
  3707. // Convert the exception to a script exception so the VM can
  3708. // properly report the error to the application and then clean up
  3709. HandleAppException();
  3710. }
  3711. #endif
  3712. m_callingSystemFunction = 0;
  3713. *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr;
  3714. }
  3715. // Update the program position after the call so that line number is correct
  3716. l_bc += 2;
  3717. if( m_regs.doProcessSuspend )
  3718. {
  3719. // Should the execution be suspended?
  3720. if( m_doSuspend )
  3721. {
  3722. m_regs.programPointer = l_bc;
  3723. m_regs.stackPointer = l_sp;
  3724. m_regs.stackFramePointer = l_fp;
  3725. m_status = asEXECUTION_SUSPENDED;
  3726. return;
  3727. }
  3728. // An exception might have been raised
  3729. if( m_status != asEXECUTION_ACTIVE )
  3730. {
  3731. m_regs.programPointer = l_bc;
  3732. m_regs.stackPointer = l_sp;
  3733. m_regs.stackFramePointer = l_fp;
  3734. return;
  3735. }
  3736. }
  3737. }
  3738. break;
  3739. // Don't let the optimizer optimize for size,
  3740. // since it requires extra conditions and jumps
  3741. case 201: l_bc = (asDWORD*)201; break;
  3742. case 202: l_bc = (asDWORD*)202; break;
  3743. case 203: l_bc = (asDWORD*)203; break;
  3744. case 204: l_bc = (asDWORD*)204; break;
  3745. case 205: l_bc = (asDWORD*)205; break;
  3746. case 206: l_bc = (asDWORD*)206; break;
  3747. case 207: l_bc = (asDWORD*)207; break;
  3748. case 208: l_bc = (asDWORD*)208; break;
  3749. case 209: l_bc = (asDWORD*)209; break;
  3750. case 210: l_bc = (asDWORD*)210; break;
  3751. case 211: l_bc = (asDWORD*)211; break;
  3752. case 212: l_bc = (asDWORD*)212; break;
  3753. case 213: l_bc = (asDWORD*)213; break;
  3754. case 214: l_bc = (asDWORD*)214; break;
  3755. case 215: l_bc = (asDWORD*)215; break;
  3756. case 216: l_bc = (asDWORD*)216; break;
  3757. case 217: l_bc = (asDWORD*)217; break;
  3758. case 218: l_bc = (asDWORD*)218; break;
  3759. case 219: l_bc = (asDWORD*)219; break;
  3760. case 220: l_bc = (asDWORD*)220; break;
  3761. case 221: l_bc = (asDWORD*)221; break;
  3762. case 222: l_bc = (asDWORD*)222; break;
  3763. case 223: l_bc = (asDWORD*)223; break;
  3764. case 224: l_bc = (asDWORD*)224; break;
  3765. case 225: l_bc = (asDWORD*)225; break;
  3766. case 226: l_bc = (asDWORD*)226; break;
  3767. case 227: l_bc = (asDWORD*)227; break;
  3768. case 228: l_bc = (asDWORD*)228; break;
  3769. case 229: l_bc = (asDWORD*)229; break;
  3770. case 230: l_bc = (asDWORD*)230; break;
  3771. case 231: l_bc = (asDWORD*)231; break;
  3772. case 232: l_bc = (asDWORD*)232; break;
  3773. case 233: l_bc = (asDWORD*)233; break;
  3774. case 234: l_bc = (asDWORD*)234; break;
  3775. case 235: l_bc = (asDWORD*)235; break;
  3776. case 236: l_bc = (asDWORD*)236; break;
  3777. case 237: l_bc = (asDWORD*)237; break;
  3778. case 238: l_bc = (asDWORD*)238; break;
  3779. case 239: l_bc = (asDWORD*)239; break;
  3780. case 240: l_bc = (asDWORD*)240; break;
  3781. case 241: l_bc = (asDWORD*)241; break;
  3782. case 242: l_bc = (asDWORD*)242; break;
  3783. case 243: l_bc = (asDWORD*)243; break;
  3784. case 244: l_bc = (asDWORD*)244; break;
  3785. case 245: l_bc = (asDWORD*)245; break;
  3786. case 246: l_bc = (asDWORD*)246; break;
  3787. case 247: l_bc = (asDWORD*)247; break;
  3788. case 248: l_bc = (asDWORD*)248; break;
  3789. case 249: l_bc = (asDWORD*)249; break;
  3790. case 250: l_bc = (asDWORD*)250; break;
  3791. case 251: l_bc = (asDWORD*)251; break;
  3792. case 252: l_bc = (asDWORD*)252; break;
  3793. case 253: l_bc = (asDWORD*)253; break;
  3794. case 254: l_bc = (asDWORD*)254; break;
  3795. case 255: l_bc = (asDWORD*)255; break;
  3796. #ifdef AS_DEBUG
  3797. default:
  3798. asASSERT(false);
  3799. SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
  3800. #endif
  3801. #if defined(_MSC_VER) && !defined(AS_DEBUG)
  3802. default:
  3803. // This Microsoft specific code allows the
  3804. // compiler to optimize the switch case as
  3805. // it will know that the code will never
  3806. // reach this point
  3807. __assume(0);
  3808. #endif
  3809. }
  3810. #ifdef AS_DEBUG
  3811. asDWORD instr = *(asBYTE*)old;
  3812. if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ &&
  3813. instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr &&
  3814. instr != asBC_JitEntry )
  3815. {
  3816. asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] );
  3817. }
  3818. #endif
  3819. }
  3820. }
  3821. // interface
  3822. int asCContext::SetException(const char *descr, bool allowCatch)
  3823. {
  3824. // Only allow this if we're executing a CALL byte code
  3825. if( m_callingSystemFunction == 0 ) return asERROR;
  3826. SetInternalException(descr, allowCatch);
  3827. return 0;
  3828. }
  3829. void asCContext::SetInternalException(const char *descr, bool allowCatch)
  3830. {
  3831. if( m_inExceptionHandler )
  3832. {
  3833. asASSERT(false); // Shouldn't happen
  3834. return; // but if it does, at least this will not crash the application
  3835. }
  3836. m_status = asEXECUTION_EXCEPTION;
  3837. m_regs.doProcessSuspend = true;
  3838. m_exceptionString = descr;
  3839. m_exceptionFunction = m_currentFunction->id;
  3840. if( m_currentFunction->scriptData )
  3841. {
  3842. m_exceptionLine = m_currentFunction->GetLineNumber(int(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()), &m_exceptionSectionIdx);
  3843. m_exceptionColumn = m_exceptionLine >> 20;
  3844. m_exceptionLine &= 0xFFFFF;
  3845. }
  3846. else
  3847. {
  3848. m_exceptionSectionIdx = 0;
  3849. m_exceptionLine = 0;
  3850. m_exceptionColumn = 0;
  3851. }
  3852. // Recursively search the callstack for try/catch blocks
  3853. m_exceptionWillBeCaught = allowCatch && FindExceptionTryCatch();
  3854. if( m_exceptionCallback )
  3855. CallExceptionCallback();
  3856. }
  3857. // interface
  3858. bool asCContext::WillExceptionBeCaught()
  3859. {
  3860. return m_exceptionWillBeCaught;
  3861. }
  3862. void asCContext::CleanReturnObject()
  3863. {
  3864. if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED )
  3865. {
  3866. // If function returns on stack we need to call the destructor on the returned object
  3867. if(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct )
  3868. m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct);
  3869. return;
  3870. }
  3871. if( m_regs.objectRegister == 0 ) return;
  3872. asASSERT( m_regs.objectType != 0 );
  3873. if( m_regs.objectType )
  3874. {
  3875. if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF)
  3876. {
  3877. // Release the function pointer
  3878. reinterpret_cast<asIScriptFunction*>(m_regs.objectRegister)->Release();
  3879. m_regs.objectRegister = 0;
  3880. }
  3881. else
  3882. {
  3883. // Call the destructor on the object
  3884. asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast<asCTypeInfo*>(m_regs.objectType))->beh);
  3885. if (m_regs.objectType->GetFlags() & asOBJ_REF)
  3886. {
  3887. asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT));
  3888. if (beh->release)
  3889. m_engine->CallObjectMethod(m_regs.objectRegister, beh->release);
  3890. m_regs.objectRegister = 0;
  3891. }
  3892. else
  3893. {
  3894. if (beh->destruct)
  3895. m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct);
  3896. // Free the memory
  3897. m_engine->CallFree(m_regs.objectRegister);
  3898. m_regs.objectRegister = 0;
  3899. }
  3900. }
  3901. }
  3902. }
  3903. void asCContext::CleanStack(bool catchException)
  3904. {
  3905. m_inExceptionHandler = true;
  3906. // Run the clean up code and move to catch block
  3907. bool caught = CleanStackFrame(catchException);
  3908. if( !caught )
  3909. {
  3910. // Set the status to exception so that the stack unwind is done correctly.
  3911. // This shouldn't be done for the current function, which is why we only
  3912. // do this after the first CleanStackFrame() is done.
  3913. m_status = asEXECUTION_EXCEPTION;
  3914. while (!caught && m_callStack.GetLength() > 0)
  3915. {
  3916. // Only clean up until the top most marker for a nested call
  3917. asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  3918. if (s[0] == 0)
  3919. break;
  3920. PopCallState();
  3921. caught = CleanStackFrame(catchException);
  3922. }
  3923. }
  3924. // If the exception was caught, then move the status to
  3925. // active as is now possible to resume the execution
  3926. if (caught)
  3927. m_status = asEXECUTION_ACTIVE;
  3928. m_inExceptionHandler = false;
  3929. }
  3930. // Interface
  3931. bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel)
  3932. {
  3933. // Don't return anything if there is no bytecode, e.g. before calling Execute()
  3934. if( m_regs.programPointer == 0 ) return false;
  3935. if( stackLevel >= GetCallstackSize() ) return false;
  3936. asCScriptFunction *func;
  3937. asUINT pos;
  3938. if( stackLevel == 0 )
  3939. {
  3940. func = m_currentFunction;
  3941. if( func->scriptData == 0 ) return false;
  3942. pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf());
  3943. }
  3944. else
  3945. {
  3946. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  3947. func = (asCScriptFunction*)s[1];
  3948. if( func->scriptData == 0 ) return false;
  3949. pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
  3950. }
  3951. // First determine if the program position is after the variable declaration
  3952. if( func->scriptData->variables.GetLength() <= varIndex ) return false;
  3953. if( func->scriptData->variables[varIndex]->declaredAtProgramPos > pos ) return false;
  3954. asUINT declaredAt = func->scriptData->variables[varIndex]->declaredAtProgramPos;
  3955. // If the program position is after the variable declaration it is necessary
  3956. // determine if the program position is still inside the statement block where
  3957. // the variable was delcared.
  3958. for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
  3959. {
  3960. if( func->scriptData->objVariableInfo[n].programPos >= declaredAt )
  3961. {
  3962. // If the current block ends between the declaredAt and current
  3963. // program position, then we know the variable is no longer visible
  3964. int level = 0;
  3965. for( ; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
  3966. {
  3967. if( func->scriptData->objVariableInfo[n].programPos > pos )
  3968. break;
  3969. if( func->scriptData->objVariableInfo[n].option == asBLOCK_BEGIN ) level++;
  3970. if( func->scriptData->objVariableInfo[n].option == asBLOCK_END && --level < 0 )
  3971. return false;
  3972. }
  3973. break;
  3974. }
  3975. }
  3976. // Variable is visible
  3977. return true;
  3978. }
  3979. // Internal
  3980. void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel)
  3981. {
  3982. asASSERT( stackLevel < GetCallstackSize() );
  3983. asCScriptFunction *func;
  3984. asUINT pos;
  3985. if( stackLevel == 0 )
  3986. {
  3987. func = m_currentFunction;
  3988. if( func->scriptData == 0 )
  3989. return;
  3990. pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf());
  3991. if( m_status == asEXECUTION_EXCEPTION )
  3992. {
  3993. // Don't consider the last instruction as executed, as it failed with an exception
  3994. // It's not actually necessary to decrease the exact size of the instruction. Just
  3995. // before the current position is enough to disconsider it.
  3996. pos--;
  3997. }
  3998. }
  3999. else
  4000. {
  4001. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  4002. func = (asCScriptFunction*)s[1];
  4003. if( func->scriptData == 0 )
  4004. return;
  4005. pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
  4006. // Don't consider the last instruction as executed, as the function that was called by it
  4007. // is still being executed. If we consider it as executed already, then a value object
  4008. // returned by value would be considered alive, which it is not.
  4009. pos--;
  4010. }
  4011. // Determine which object variables that are really live ones
  4012. liveObjects.SetLength(func->scriptData->objVariablePos.GetLength());
  4013. memset(liveObjects.AddressOf(), 0, sizeof(int)*liveObjects.GetLength());
  4014. for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
  4015. {
  4016. // Find the first variable info with a larger position than the current
  4017. // As the variable info are always placed on the instruction right after the
  4018. // one that initialized or freed the object, the current position needs to be
  4019. // considered as valid.
  4020. if( func->scriptData->objVariableInfo[n].programPos > pos )
  4021. {
  4022. // We've determined how far the execution ran, now determine which variables are alive
  4023. for( --n; n >= 0; n-- )
  4024. {
  4025. switch( func->scriptData->objVariableInfo[n].option )
  4026. {
  4027. case asOBJ_UNINIT: // Object was destroyed
  4028. {
  4029. // TODO: optimize: This should have been done by the compiler already
  4030. // Which variable is this?
  4031. asUINT var = 0;
  4032. for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
  4033. if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset )
  4034. {
  4035. var = v;
  4036. break;
  4037. }
  4038. liveObjects[var] -= 1;
  4039. }
  4040. break;
  4041. case asOBJ_INIT: // Object was created
  4042. {
  4043. // Which variable is this?
  4044. asUINT var = 0;
  4045. for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
  4046. if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset )
  4047. {
  4048. var = v;
  4049. break;
  4050. }
  4051. liveObjects[var] += 1;
  4052. }
  4053. break;
  4054. case asBLOCK_BEGIN: // Start block
  4055. // We should ignore start blocks, since it just means the
  4056. // program was within the block when the exception occurred
  4057. break;
  4058. case asBLOCK_END: // End block
  4059. // We need to skip the entire block, as the objects created
  4060. // and destroyed inside this block are already out of scope
  4061. {
  4062. int nested = 1;
  4063. while( nested > 0 )
  4064. {
  4065. int option = func->scriptData->objVariableInfo[--n].option;
  4066. if( option == 3 )
  4067. nested++;
  4068. if( option == 2 )
  4069. nested--;
  4070. }
  4071. }
  4072. break;
  4073. case asOBJ_VARDECL: // A variable was declared
  4074. // We don't really care about the variable declarations at this moment
  4075. break;
  4076. }
  4077. }
  4078. // We're done with the investigation
  4079. break;
  4080. }
  4081. }
  4082. }
  4083. void asCContext::CleanArgsOnStack()
  4084. {
  4085. if( !m_needToCleanupArgs )
  4086. return;
  4087. asASSERT( m_currentFunction->scriptData );
  4088. // Find the instruction just before the current program pointer
  4089. asDWORD *instr = m_currentFunction->scriptData->byteCode.AddressOf();
  4090. asDWORD *prevInstr = 0;
  4091. while( instr < m_regs.programPointer )
  4092. {
  4093. prevInstr = instr;
  4094. instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type];
  4095. }
  4096. // Determine what function was being called
  4097. asCScriptFunction *func = 0;
  4098. asBYTE bc = *(asBYTE*)prevInstr;
  4099. if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF )
  4100. {
  4101. int funcId = asBC_INTARG(prevInstr);
  4102. func = m_engine->scriptFunctions[funcId];
  4103. }
  4104. else if( bc == asBC_CALLBND )
  4105. {
  4106. int funcId = asBC_INTARG(prevInstr);
  4107. func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
  4108. }
  4109. else if( bc == asBC_CallPtr )
  4110. {
  4111. asUINT v;
  4112. int var = asBC_SWORDARG0(prevInstr);
  4113. // Find the funcdef from the local variable
  4114. for( v = 0; v < m_currentFunction->scriptData->objVariablePos.GetLength(); v++ )
  4115. if( m_currentFunction->scriptData->objVariablePos[v] == var )
  4116. {
  4117. func = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef;
  4118. break;
  4119. }
  4120. if( func == 0 )
  4121. {
  4122. // Look in parameters
  4123. int paramPos = 0;
  4124. if( m_currentFunction->objectType )
  4125. paramPos -= AS_PTR_SIZE;
  4126. if( m_currentFunction->DoesReturnOnStack() )
  4127. paramPos -= AS_PTR_SIZE;
  4128. for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ )
  4129. {
  4130. if( var == paramPos )
  4131. {
  4132. if (m_currentFunction->parameterTypes[v].IsFuncdef())
  4133. func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef;
  4134. break;
  4135. }
  4136. paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords();
  4137. }
  4138. }
  4139. }
  4140. else
  4141. asASSERT( false );
  4142. asASSERT( func );
  4143. // Clean parameters
  4144. int offset = 0;
  4145. if( func->objectType )
  4146. offset += AS_PTR_SIZE;
  4147. if( func->DoesReturnOnStack() )
  4148. offset += AS_PTR_SIZE;
  4149. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  4150. {
  4151. if( (func->parameterTypes[n].IsObject() || func->parameterTypes[n].IsFuncdef()) && !func->parameterTypes[n].IsReference() )
  4152. {
  4153. // TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code
  4154. if( *(asPWORD*)&m_regs.stackPointer[offset] )
  4155. {
  4156. // Call the object's destructor
  4157. asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour();
  4158. if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF)
  4159. {
  4160. (*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release();
  4161. }
  4162. else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF )
  4163. {
  4164. asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release );
  4165. if( beh->release )
  4166. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release);
  4167. }
  4168. else
  4169. {
  4170. if( beh->destruct )
  4171. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct);
  4172. // Free the memory
  4173. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]);
  4174. }
  4175. *(asPWORD*)&m_regs.stackPointer[offset] = 0;
  4176. }
  4177. }
  4178. offset += func->parameterTypes[n].GetSizeOnStackDWords();
  4179. }
  4180. m_needToCleanupArgs = false;
  4181. }
  4182. bool asCContext::FindExceptionTryCatch()
  4183. {
  4184. // Check each of the script functions on the callstack to see if
  4185. // the current program position is within a try/catch block
  4186. if (m_currentFunction && m_currentFunction->scriptData)
  4187. {
  4188. asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf());
  4189. for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++)
  4190. {
  4191. if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos &&
  4192. currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos)
  4193. return true;
  4194. }
  4195. }
  4196. int stackSize = GetCallstackSize();
  4197. for (int level = 1; level < stackSize; level++)
  4198. {
  4199. asPWORD *s = m_callStack.AddressOf() + (stackSize - level - 1)*CALLSTACK_FRAME_SIZE;
  4200. asCScriptFunction *func = (asCScriptFunction*)s[1];
  4201. if (func && func->scriptData)
  4202. {
  4203. asUINT currPos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
  4204. for (asUINT n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
  4205. {
  4206. if (currPos >= func->scriptData->tryCatchInfo[n].tryPos &&
  4207. currPos < func->scriptData->tryCatchInfo[n].catchPos)
  4208. return true;
  4209. }
  4210. }
  4211. }
  4212. return false;
  4213. }
  4214. bool asCContext::CleanStackFrame(bool catchException)
  4215. {
  4216. bool exceptionCaught = false;
  4217. asSTryCatchInfo *tryCatchInfo = 0;
  4218. // Clean object variables on the stack
  4219. // If the stack memory is not allocated or the program pointer
  4220. // is not set, then there is nothing to clean up on the stack frame
  4221. if( !m_isStackMemoryNotAllocated && m_regs.programPointer )
  4222. {
  4223. // If the exception occurred while calling a function it is necessary
  4224. // to clean up the arguments that were put on the stack.
  4225. CleanArgsOnStack();
  4226. // Check if this function will catch the exception
  4227. // Try blocks can be nested, so use the innermost block
  4228. asASSERT(m_currentFunction->scriptData);
  4229. if (catchException && m_currentFunction->scriptData)
  4230. {
  4231. asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf());
  4232. for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++)
  4233. {
  4234. if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos &&
  4235. currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos)
  4236. {
  4237. tryCatchInfo = &m_currentFunction->scriptData->tryCatchInfo[n];
  4238. exceptionCaught = true;
  4239. }
  4240. if (currPos < m_currentFunction->scriptData->tryCatchInfo[n].tryPos)
  4241. break;
  4242. }
  4243. }
  4244. // Restore the stack pointer
  4245. if( !exceptionCaught )
  4246. m_regs.stackPointer += m_currentFunction->scriptData->variableSpace;
  4247. // Determine which object variables that are really live ones
  4248. asCArray<int> liveObjects;
  4249. DetermineLiveObjects(liveObjects, 0);
  4250. for( asUINT n = 0; n < m_currentFunction->scriptData->objVariablePos.GetLength(); n++ )
  4251. {
  4252. int pos = m_currentFunction->scriptData->objVariablePos[n];
  4253. // If the exception was caught, then only clean up objects within the try block
  4254. if (exceptionCaught)
  4255. {
  4256. // Find out where the variable was declared, and skip cleaning of those that were declared before the try catch
  4257. // Multiple variables in different scopes may occupy the same slot on the stack so it is necessary to search
  4258. // the entire list to determine which variable occupies the slot now.
  4259. int skipClean = 0;
  4260. for( asUINT p = 0; p < m_currentFunction->scriptData->objVariableInfo.GetLength(); p++ )
  4261. {
  4262. asSObjectVariableInfo &info = m_currentFunction->scriptData->objVariableInfo[p];
  4263. if (info.variableOffset == pos &&
  4264. info.option == asOBJ_VARDECL )
  4265. {
  4266. asUINT progPos = info.programPos;
  4267. if (progPos < tryCatchInfo->tryPos )
  4268. {
  4269. if( skipClean >= 0 )
  4270. skipClean = 1;
  4271. break;
  4272. }
  4273. else if( progPos < tryCatchInfo->catchPos )
  4274. {
  4275. skipClean = -1;
  4276. break;
  4277. }
  4278. }
  4279. }
  4280. // Skip only variables that have been declared before the try block. Variables declared
  4281. // within the try block and variables whose declaration was not identified (temporary objects)
  4282. // will not be skipped.
  4283. // TODO: What if a temporary variable reuses a slot from a declared variable that is no longer in scope?
  4284. if (skipClean > 0)
  4285. continue;
  4286. }
  4287. if( n < m_currentFunction->scriptData->objVariablesOnHeap )
  4288. {
  4289. // Check if the pointer is initialized
  4290. if( *(asPWORD*)&m_regs.stackFramePointer[-pos] )
  4291. {
  4292. // Call the object's destructor
  4293. if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF)
  4294. {
  4295. (*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release();
  4296. }
  4297. else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF )
  4298. {
  4299. asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
  4300. asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release );
  4301. if( beh->release )
  4302. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release);
  4303. }
  4304. else
  4305. {
  4306. asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
  4307. if( beh->destruct )
  4308. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
  4309. else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN )
  4310. m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n]));
  4311. // Free the memory
  4312. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]);
  4313. }
  4314. *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
  4315. }
  4316. }
  4317. else
  4318. {
  4319. asASSERT( m_currentFunction->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE );
  4320. // Only destroy the object if it is truly alive
  4321. if( liveObjects[n] > 0 )
  4322. {
  4323. asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
  4324. if( beh->destruct )
  4325. m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
  4326. }
  4327. }
  4328. }
  4329. }
  4330. else
  4331. m_isStackMemoryNotAllocated = false;
  4332. // If the exception was caught then move the program position to the catch block then stop the unwinding
  4333. if (exceptionCaught)
  4334. {
  4335. m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf() + tryCatchInfo->catchPos;
  4336. return exceptionCaught;
  4337. }
  4338. // Functions that do not own the object and parameters shouldn't do any clean up
  4339. if( m_currentFunction->dontCleanUpOnException )
  4340. return exceptionCaught;
  4341. // Clean object and parameters
  4342. int offset = 0;
  4343. if( m_currentFunction->objectType )
  4344. offset += AS_PTR_SIZE;
  4345. if( m_currentFunction->DoesReturnOnStack() )
  4346. offset += AS_PTR_SIZE;
  4347. for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ )
  4348. {
  4349. if( (m_currentFunction->parameterTypes[n].IsObject() ||m_currentFunction->parameterTypes[n].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() )
  4350. {
  4351. if( *(asPWORD*)&m_regs.stackFramePointer[offset] )
  4352. {
  4353. // Call the object's destructor
  4354. asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour();
  4355. if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF)
  4356. {
  4357. (*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release();
  4358. }
  4359. else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF )
  4360. {
  4361. asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release );
  4362. if( beh->release )
  4363. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release);
  4364. }
  4365. else
  4366. {
  4367. if( beh->destruct )
  4368. m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->destruct);
  4369. // Free the memory
  4370. m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]);
  4371. }
  4372. *(asPWORD*)&m_regs.stackFramePointer[offset] = 0;
  4373. }
  4374. }
  4375. offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords();
  4376. }
  4377. return exceptionCaught;
  4378. }
  4379. // interface
  4380. int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
  4381. {
  4382. // Return the last exception even if the context is no longer in the exception state
  4383. // if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
  4384. if( column ) *column = m_exceptionColumn;
  4385. if( sectionName )
  4386. {
  4387. // The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates
  4388. if( m_exceptionSectionIdx >= 0 )
  4389. *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf();
  4390. else
  4391. *sectionName = 0;
  4392. }
  4393. return m_exceptionLine;
  4394. }
  4395. // interface
  4396. asIScriptFunction *asCContext::GetExceptionFunction()
  4397. {
  4398. // Return the last exception even if the context is no longer in the exception state
  4399. // if( GetState() != asEXECUTION_EXCEPTION ) return 0;
  4400. return m_engine->scriptFunctions[m_exceptionFunction];
  4401. }
  4402. // interface
  4403. const char *asCContext::GetExceptionString()
  4404. {
  4405. // Return the last exception even if the context is no longer in the exception state
  4406. // if( GetState() != asEXECUTION_EXCEPTION ) return 0;
  4407. return m_exceptionString.AddressOf();
  4408. }
  4409. // interface
  4410. asEContextState asCContext::GetState() const
  4411. {
  4412. return m_status;
  4413. }
  4414. // interface
  4415. int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
  4416. {
  4417. // First turn off the line callback to avoid a second thread
  4418. // attempting to call it while the new one is still being set
  4419. m_lineCallback = false;
  4420. m_lineCallbackObj = obj;
  4421. bool isObj = false;
  4422. if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
  4423. {
  4424. m_regs.doProcessSuspend = m_doSuspend;
  4425. return asNOT_SUPPORTED;
  4426. }
  4427. if( (unsigned)callConv >= asCALL_THISCALL )
  4428. {
  4429. isObj = true;
  4430. if( obj == 0 )
  4431. {
  4432. m_regs.doProcessSuspend = m_doSuspend;
  4433. return asINVALID_ARG;
  4434. }
  4435. }
  4436. int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc);
  4437. // Turn on the line callback after setting both the function pointer and object pointer
  4438. if( r >= 0 ) m_lineCallback = true;
  4439. // The BC_SUSPEND instruction should be processed if either line
  4440. // callback is set or if the application has requested a suspension
  4441. m_regs.doProcessSuspend = m_doSuspend || m_lineCallback;
  4442. return r;
  4443. }
  4444. void asCContext::CallLineCallback()
  4445. {
  4446. if( m_lineCallbackFunc.callConv < ICC_THISCALL )
  4447. m_engine->CallGlobalFunction(this, m_lineCallbackObj, &m_lineCallbackFunc, 0);
  4448. else
  4449. m_engine->CallObjectMethod(m_lineCallbackObj, this, &m_lineCallbackFunc, 0);
  4450. }
  4451. // interface
  4452. int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv)
  4453. {
  4454. m_exceptionCallback = true;
  4455. m_exceptionCallbackObj = obj;
  4456. bool isObj = false;
  4457. if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
  4458. return asNOT_SUPPORTED;
  4459. if( (unsigned)callConv >= asCALL_THISCALL )
  4460. {
  4461. isObj = true;
  4462. if( obj == 0 )
  4463. {
  4464. m_exceptionCallback = false;
  4465. return asINVALID_ARG;
  4466. }
  4467. }
  4468. int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_exceptionCallbackFunc);
  4469. if( r < 0 ) m_exceptionCallback = false;
  4470. return r;
  4471. }
  4472. void asCContext::CallExceptionCallback()
  4473. {
  4474. if( m_exceptionCallbackFunc.callConv < ICC_THISCALL )
  4475. m_engine->CallGlobalFunction(this, m_exceptionCallbackObj, &m_exceptionCallbackFunc, 0);
  4476. else
  4477. m_engine->CallObjectMethod(m_exceptionCallbackObj, this, &m_exceptionCallbackFunc, 0);
  4478. }
  4479. #ifndef AS_NO_EXCEPTIONS
  4480. // internal
  4481. void asCContext::HandleAppException()
  4482. {
  4483. // This method is called from within a catch(...) block
  4484. if (m_engine->translateExceptionCallback)
  4485. {
  4486. // Allow the application to translate the application exception to a proper exception string
  4487. if (m_engine->translateExceptionCallbackFunc.callConv < ICC_THISCALL)
  4488. m_engine->CallGlobalFunction(this, m_engine->translateExceptionCallbackObj, &m_engine->translateExceptionCallbackFunc, 0);
  4489. else
  4490. m_engine->CallObjectMethod(m_engine->translateExceptionCallbackObj, this, &m_engine->translateExceptionCallbackFunc, 0);
  4491. }
  4492. // Make sure an exception is set even if the application decides not to do any specific translation
  4493. if( m_status != asEXECUTION_EXCEPTION )
  4494. SetException(TXT_EXCEPTION_CAUGHT);
  4495. }
  4496. #endif
  4497. // interface
  4498. void asCContext::ClearLineCallback()
  4499. {
  4500. m_lineCallback = false;
  4501. m_regs.doProcessSuspend = m_doSuspend;
  4502. }
  4503. // interface
  4504. void asCContext::ClearExceptionCallback()
  4505. {
  4506. m_exceptionCallback = false;
  4507. }
  4508. int asCContext::CallGeneric(asCScriptFunction *descr)
  4509. {
  4510. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  4511. void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func;
  4512. int popSize = sysFunc->paramSize;
  4513. asDWORD *args = m_regs.stackPointer;
  4514. // Verify the object pointer if it is a class method
  4515. void *currentObject = 0;
  4516. asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD );
  4517. if( sysFunc->callConv == ICC_GENERIC_METHOD )
  4518. {
  4519. // The object pointer should be popped from the context stack
  4520. popSize += AS_PTR_SIZE;
  4521. // Check for null pointer
  4522. currentObject = (void*)*(asPWORD*)(args);
  4523. if( currentObject == 0 )
  4524. {
  4525. SetInternalException(TXT_NULL_POINTER_ACCESS);
  4526. return 0;
  4527. }
  4528. asASSERT( sysFunc->baseOffset == 0 );
  4529. // Skip object pointer
  4530. args += AS_PTR_SIZE;
  4531. }
  4532. if( descr->DoesReturnOnStack() )
  4533. {
  4534. // Skip the address where the return value will be stored
  4535. args += AS_PTR_SIZE;
  4536. popSize += AS_PTR_SIZE;
  4537. }
  4538. asCGeneric gen(m_engine, descr, currentObject, args);
  4539. m_callingSystemFunction = descr;
  4540. #ifdef AS_NO_EXCEPTIONS
  4541. func(&gen);
  4542. #else
  4543. // This try/catch block is to catch potential exception that may
  4544. // be thrown by the registered function.
  4545. try
  4546. {
  4547. func(&gen);
  4548. }
  4549. catch (...)
  4550. {
  4551. // Convert the exception to a script exception so the VM can
  4552. // properly report the error to the application and then clean up
  4553. HandleAppException();
  4554. }
  4555. #endif
  4556. m_callingSystemFunction = 0;
  4557. m_regs.valueRegister = gen.returnVal;
  4558. m_regs.objectRegister = gen.objectRegister;
  4559. m_regs.objectType = descr->returnType.GetTypeInfo();
  4560. // Increase the returned handle if the function has been declared with autohandles
  4561. // and the engine is not set to use the old mode for the generic calling convention
  4562. if (sysFunc->returnAutoHandle && m_engine->ep.genericCallMode == 1 && m_regs.objectRegister)
  4563. {
  4564. asASSERT(!(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT));
  4565. m_engine->CallObjectMethod(m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref);
  4566. }
  4567. // Clean up arguments
  4568. const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
  4569. if( cleanCount )
  4570. {
  4571. asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
  4572. for( asUINT n = 0; n < cleanCount; n++, clean++ )
  4573. {
  4574. void **addr = (void**)&args[clean->off];
  4575. if( clean->op == 0 )
  4576. {
  4577. if( *addr != 0 )
  4578. {
  4579. m_engine->CallObjectMethod(*addr, clean->ot->beh.release);
  4580. *addr = 0;
  4581. }
  4582. }
  4583. else
  4584. {
  4585. asASSERT( clean->op == 1 || clean->op == 2 );
  4586. asASSERT( *addr );
  4587. if( clean->op == 2 )
  4588. m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
  4589. m_engine->CallFree(*addr);
  4590. }
  4591. }
  4592. }
  4593. // Return how much should be popped from the stack
  4594. return popSize;
  4595. }
  4596. // interface
  4597. int asCContext::GetVarCount(asUINT stackLevel)
  4598. {
  4599. asIScriptFunction *func = GetFunction(stackLevel);
  4600. if( func == 0 ) return asINVALID_ARG;
  4601. return func->GetVarCount();
  4602. }
  4603. // interface
  4604. const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel)
  4605. {
  4606. asIScriptFunction *func = GetFunction(stackLevel);
  4607. if( func == 0 ) return 0;
  4608. const char *name = 0;
  4609. int r = func->GetVar(varIndex, &name);
  4610. return r >= 0 ? name : 0;
  4611. }
  4612. // interface
  4613. const char *asCContext::GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace)
  4614. {
  4615. asIScriptFunction *func = GetFunction(stackLevel);
  4616. if( func == 0 ) return 0;
  4617. return func->GetVarDecl(varIndex, includeNamespace);
  4618. }
  4619. // interface
  4620. int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel)
  4621. {
  4622. asIScriptFunction *func = GetFunction(stackLevel);
  4623. if( func == 0 ) return asINVALID_ARG;
  4624. int typeId;
  4625. int r = func->GetVar(varIndex, 0, &typeId);
  4626. return r < 0 ? r : typeId;
  4627. }
  4628. // interface
  4629. void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel)
  4630. {
  4631. // Don't return anything if there is no bytecode, e.g. before calling Execute()
  4632. if( m_regs.programPointer == 0 ) return 0;
  4633. if( stackLevel >= GetCallstackSize() ) return 0;
  4634. asCScriptFunction *func;
  4635. asDWORD *sf;
  4636. if( stackLevel == 0 )
  4637. {
  4638. func = m_currentFunction;
  4639. sf = m_regs.stackFramePointer;
  4640. }
  4641. else
  4642. {
  4643. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  4644. func = (asCScriptFunction*)s[1];
  4645. sf = (asDWORD*)s[0];
  4646. }
  4647. if( func == 0 )
  4648. return 0;
  4649. if( func->scriptData == 0 )
  4650. return 0;
  4651. if( varIndex >= func->scriptData->variables.GetLength() )
  4652. return 0;
  4653. // For object variables it's necessary to dereference the pointer to get the address of the value
  4654. // Reference parameters must also be dereferenced to give the address of the value
  4655. int pos = func->scriptData->variables[varIndex]->stackOffset;
  4656. if( (func->scriptData->variables[varIndex]->type.IsObject() && !func->scriptData->variables[varIndex]->type.IsObjectHandle()) || (pos <= 0) )
  4657. {
  4658. // Determine if the object is really on the heap
  4659. bool onHeap = false;
  4660. if( func->scriptData->variables[varIndex]->type.IsObject() &&
  4661. !func->scriptData->variables[varIndex]->type.IsObjectHandle() )
  4662. {
  4663. onHeap = true;
  4664. if( func->scriptData->variables[varIndex]->type.GetTypeInfo()->GetFlags() & asOBJ_VALUE )
  4665. {
  4666. for( asUINT n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
  4667. {
  4668. if( func->scriptData->objVariablePos[n] == pos )
  4669. {
  4670. onHeap = n < func->scriptData->objVariablesOnHeap;
  4671. if( !onHeap )
  4672. {
  4673. // If the object on the stack is not initialized return a null pointer instead
  4674. asCArray<int> liveObjects;
  4675. DetermineLiveObjects(liveObjects, stackLevel);
  4676. if( liveObjects[n] <= 0 )
  4677. return 0;
  4678. }
  4679. break;
  4680. }
  4681. }
  4682. }
  4683. }
  4684. // If it wasn't an object on the heap, then check if it is a reference parameter
  4685. if( !onHeap && pos <= 0 )
  4686. {
  4687. // Determine what function argument this position matches
  4688. int stackPos = 0;
  4689. if( func->objectType )
  4690. stackPos -= AS_PTR_SIZE;
  4691. if( func->DoesReturnOnStack() )
  4692. stackPos -= AS_PTR_SIZE;
  4693. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  4694. {
  4695. if( stackPos == pos )
  4696. {
  4697. // The right argument was found. Is this a reference parameter?
  4698. if( func->inOutFlags[n] != asTM_NONE )
  4699. onHeap = true;
  4700. break;
  4701. }
  4702. stackPos -= func->parameterTypes[n].GetSizeOnStackDWords();
  4703. }
  4704. }
  4705. if( onHeap )
  4706. return *(void**)(sf - func->scriptData->variables[varIndex]->stackOffset);
  4707. }
  4708. return sf - func->scriptData->variables[varIndex]->stackOffset;
  4709. }
  4710. // interface
  4711. // returns the typeId of the 'this' object at the given call stack level (0 for current)
  4712. // returns 0 if the function call at the given stack level is not a method
  4713. int asCContext::GetThisTypeId(asUINT stackLevel)
  4714. {
  4715. asIScriptFunction *func = GetFunction(stackLevel);
  4716. if( func == 0 ) return asINVALID_ARG;
  4717. if( func->GetObjectType() == 0 )
  4718. return 0; // not in a method
  4719. // create a datatype
  4720. asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false);
  4721. // return a typeId from the data type
  4722. return m_engine->GetTypeIdFromDataType(dt);
  4723. }
  4724. // interface
  4725. // returns the 'this' object pointer at the given call stack level (0 for current)
  4726. // returns 0 if the function call at the given stack level is not a method
  4727. void *asCContext::GetThisPointer(asUINT stackLevel)
  4728. {
  4729. if( stackLevel >= GetCallstackSize() )
  4730. return 0;
  4731. asCScriptFunction *func;
  4732. asDWORD *sf;
  4733. if( stackLevel == 0 )
  4734. {
  4735. func = m_currentFunction;
  4736. sf = m_regs.stackFramePointer;
  4737. }
  4738. else
  4739. {
  4740. asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
  4741. func = (asCScriptFunction*)s[1];
  4742. sf = (asDWORD*)s[0];
  4743. }
  4744. if( func == 0 )
  4745. return 0;
  4746. if( func->objectType == 0 )
  4747. return 0; // not in a method
  4748. void *thisPointer = (void*)*(asPWORD*)(sf);
  4749. if( thisPointer == 0 )
  4750. {
  4751. return 0;
  4752. }
  4753. // NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return
  4754. // a pointer to a pointer. I can't imagine someone would want to change the 'this'
  4755. return thisPointer;
  4756. }
  4757. // TODO: Move these to as_utils.cpp
  4758. struct POW_INFO
  4759. {
  4760. asQWORD MaxBaseu64;
  4761. asDWORD MaxBasei64;
  4762. asWORD MaxBaseu32;
  4763. asWORD MaxBasei32;
  4764. char HighBit;
  4765. };
  4766. const POW_INFO pow_info[] =
  4767. {
  4768. { 0ULL, 0UL, 0, 0, 0 }, // 0 is a special case
  4769. { 0ULL, 0UL, 0, 0, 1 }, // 1 is a special case
  4770. { 3037000499ULL, 2147483647UL, 65535, 46340, 2 }, // 2
  4771. { 2097152ULL, 1664510UL, 1625, 1290, 2 }, // 3
  4772. { 55108ULL, 46340UL, 255, 215, 3 }, // 4
  4773. { 6208ULL, 5404UL, 84, 73, 3 }, // 5
  4774. { 1448ULL, 1290UL, 40, 35, 3 }, // 6
  4775. { 511ULL, 463UL, 23, 21, 3 }, // 7
  4776. { 234ULL, 215UL, 15, 14, 4 }, // 8
  4777. { 128ULL, 118UL, 11, 10, 4 }, // 9
  4778. { 78ULL, 73UL, 9, 8, 4 }, // 10
  4779. { 52ULL, 49UL, 7, 7, 4 }, // 11
  4780. { 38ULL, 35UL, 6, 5, 4 }, // 12
  4781. { 28ULL, 27UL, 5, 5, 4 }, // 13
  4782. { 22ULL, 21UL, 4, 4, 4 }, // 14
  4783. { 18ULL, 17UL, 4, 4, 4 }, // 15
  4784. { 15ULL, 14UL, 3, 3, 5 }, // 16
  4785. { 13ULL, 12UL, 3, 3, 5 }, // 17
  4786. { 11ULL, 10UL, 3, 3, 5 }, // 18
  4787. { 9ULL, 9UL, 3, 3, 5 }, // 19
  4788. { 8ULL, 8UL, 3, 2, 5 }, // 20
  4789. { 8ULL, 7UL, 2, 2, 5 }, // 21
  4790. { 7ULL, 7UL, 2, 2, 5 }, // 22
  4791. { 6ULL, 6UL, 2, 2, 5 }, // 23
  4792. { 6ULL, 5UL, 2, 2, 5 }, // 24
  4793. { 5ULL, 5UL, 2, 2, 5 }, // 25
  4794. { 5ULL, 5UL, 2, 2, 5 }, // 26
  4795. { 5ULL, 4UL, 2, 2, 5 }, // 27
  4796. { 4ULL, 4UL, 2, 2, 5 }, // 28
  4797. { 4ULL, 4UL, 2, 2, 5 }, // 29
  4798. { 4ULL, 4UL, 2, 2, 5 }, // 30
  4799. { 4ULL, 4UL, 2, 1, 5 }, // 31
  4800. { 3ULL, 3UL, 1, 1, 6 }, // 32
  4801. { 3ULL, 3UL, 1, 1, 6 }, // 33
  4802. { 3ULL, 3UL, 1, 1, 6 }, // 34
  4803. { 3ULL, 3UL, 1, 1, 6 }, // 35
  4804. { 3ULL, 3UL, 1, 1, 6 }, // 36
  4805. { 3ULL, 3UL, 1, 1, 6 }, // 37
  4806. { 3ULL, 3UL, 1, 1, 6 }, // 38
  4807. { 3ULL, 3UL, 1, 1, 6 }, // 39
  4808. { 2ULL, 2UL, 1, 1, 6 }, // 40
  4809. { 2ULL, 2UL, 1, 1, 6 }, // 41
  4810. { 2ULL, 2UL, 1, 1, 6 }, // 42
  4811. { 2ULL, 2UL, 1, 1, 6 }, // 43
  4812. { 2ULL, 2UL, 1, 1, 6 }, // 44
  4813. { 2ULL, 2UL, 1, 1, 6 }, // 45
  4814. { 2ULL, 2UL, 1, 1, 6 }, // 46
  4815. { 2ULL, 2UL, 1, 1, 6 }, // 47
  4816. { 2ULL, 2UL, 1, 1, 6 }, // 48
  4817. { 2ULL, 2UL, 1, 1, 6 }, // 49
  4818. { 2ULL, 2UL, 1, 1, 6 }, // 50
  4819. { 2ULL, 2UL, 1, 1, 6 }, // 51
  4820. { 2ULL, 2UL, 1, 1, 6 }, // 52
  4821. { 2ULL, 2UL, 1, 1, 6 }, // 53
  4822. { 2ULL, 2UL, 1, 1, 6 }, // 54
  4823. { 2ULL, 2UL, 1, 1, 6 }, // 55
  4824. { 2ULL, 2UL, 1, 1, 6 }, // 56
  4825. { 2ULL, 2UL, 1, 1, 6 }, // 57
  4826. { 2ULL, 2UL, 1, 1, 6 }, // 58
  4827. { 2ULL, 2UL, 1, 1, 6 }, // 59
  4828. { 2ULL, 2UL, 1, 1, 6 }, // 60
  4829. { 2ULL, 2UL, 1, 1, 6 }, // 61
  4830. { 2ULL, 2UL, 1, 1, 6 }, // 62
  4831. { 2ULL, 1UL, 1, 1, 6 }, // 63
  4832. };
  4833. int as_powi(int base, int exponent, bool& isOverflow)
  4834. {
  4835. if( exponent < 0 )
  4836. {
  4837. if( base == 0 )
  4838. // Divide by zero
  4839. isOverflow = true;
  4840. else
  4841. // Result is less than 1, so it truncates to 0
  4842. isOverflow = false;
  4843. return 0;
  4844. }
  4845. else if( exponent == 0 && base == 0 )
  4846. {
  4847. // Domain error
  4848. isOverflow = true;
  4849. return 0;
  4850. }
  4851. else if( exponent >= 31 )
  4852. {
  4853. switch( base )
  4854. {
  4855. case -1:
  4856. isOverflow = false;
  4857. return exponent & 1 ? -1 : 1;
  4858. case 0:
  4859. isOverflow = false;
  4860. break;
  4861. case 1:
  4862. isOverflow = false;
  4863. return 1;
  4864. default:
  4865. isOverflow = true;
  4866. break;
  4867. }
  4868. return 0;
  4869. }
  4870. else
  4871. {
  4872. const asWORD max_base = pow_info[exponent].MaxBasei32;
  4873. const char high_bit = pow_info[exponent].HighBit;
  4874. if( max_base != 0 && max_base < (base < 0 ? -base : base) )
  4875. {
  4876. isOverflow = true;
  4877. return 0; // overflow
  4878. }
  4879. int result = 1;
  4880. switch( high_bit )
  4881. {
  4882. case 5:
  4883. if( exponent & 1 ) result *= base;
  4884. exponent >>= 1;
  4885. base *= base;
  4886. case 4:
  4887. if( exponent & 1 ) result *= base;
  4888. exponent >>= 1;
  4889. base *= base;
  4890. case 3:
  4891. if( exponent & 1 ) result *= base;
  4892. exponent >>= 1;
  4893. base *= base;
  4894. case 2:
  4895. if( exponent & 1 ) result *= base;
  4896. exponent >>= 1;
  4897. base *= base;
  4898. case 1:
  4899. if( exponent ) result *= base;
  4900. default:
  4901. isOverflow = false;
  4902. return result;
  4903. }
  4904. }
  4905. }
  4906. asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow)
  4907. {
  4908. if( exponent == 0 && base == 0 )
  4909. {
  4910. // Domain error
  4911. isOverflow = true;
  4912. return 0;
  4913. }
  4914. else if( exponent >= 32 )
  4915. {
  4916. switch( base )
  4917. {
  4918. case 0:
  4919. isOverflow = false;
  4920. break;
  4921. case 1:
  4922. isOverflow = false;
  4923. return 1;
  4924. default:
  4925. isOverflow = true;
  4926. break;
  4927. }
  4928. return 0;
  4929. }
  4930. else
  4931. {
  4932. const asWORD max_base = pow_info[exponent].MaxBaseu32;
  4933. const char high_bit = pow_info[exponent].HighBit;
  4934. if( max_base != 0 && max_base < base )
  4935. {
  4936. isOverflow = true;
  4937. return 0; // overflow
  4938. }
  4939. asDWORD result = 1;
  4940. switch( high_bit )
  4941. {
  4942. case 5:
  4943. if( exponent & 1 ) result *= base;
  4944. exponent >>= 1;
  4945. base *= base;
  4946. case 4:
  4947. if( exponent & 1 ) result *= base;
  4948. exponent >>= 1;
  4949. base *= base;
  4950. case 3:
  4951. if( exponent & 1 ) result *= base;
  4952. exponent >>= 1;
  4953. base *= base;
  4954. case 2:
  4955. if( exponent & 1 ) result *= base;
  4956. exponent >>= 1;
  4957. base *= base;
  4958. case 1:
  4959. if( exponent ) result *= base;
  4960. default:
  4961. isOverflow = false;
  4962. return result;
  4963. }
  4964. }
  4965. }
  4966. asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow)
  4967. {
  4968. if( exponent < 0 )
  4969. {
  4970. if( base == 0 )
  4971. // Divide by zero
  4972. isOverflow = true;
  4973. else
  4974. // Result is less than 1, so it truncates to 0
  4975. isOverflow = false;
  4976. return 0;
  4977. }
  4978. else if( exponent == 0 && base == 0 )
  4979. {
  4980. // Domain error
  4981. isOverflow = true;
  4982. return 0;
  4983. }
  4984. else if( exponent >= 63 )
  4985. {
  4986. switch( base )
  4987. {
  4988. case -1:
  4989. isOverflow = false;
  4990. return exponent & 1 ? -1 : 1;
  4991. case 0:
  4992. isOverflow = false;
  4993. break;
  4994. case 1:
  4995. isOverflow = false;
  4996. return 1;
  4997. default:
  4998. isOverflow = true;
  4999. break;
  5000. }
  5001. return 0;
  5002. }
  5003. else
  5004. {
  5005. const asDWORD max_base = pow_info[exponent].MaxBasei64;
  5006. const char high_bit = pow_info[exponent].HighBit;
  5007. if( max_base != 0 && max_base < (base < 0 ? -base : base) )
  5008. {
  5009. isOverflow = true;
  5010. return 0; // overflow
  5011. }
  5012. asINT64 result = 1;
  5013. switch( high_bit )
  5014. {
  5015. case 6:
  5016. if( exponent & 1 ) result *= base;
  5017. exponent >>= 1;
  5018. base *= base;
  5019. case 5:
  5020. if( exponent & 1 ) result *= base;
  5021. exponent >>= 1;
  5022. base *= base;
  5023. case 4:
  5024. if( exponent & 1 ) result *= base;
  5025. exponent >>= 1;
  5026. base *= base;
  5027. case 3:
  5028. if( exponent & 1 ) result *= base;
  5029. exponent >>= 1;
  5030. base *= base;
  5031. case 2:
  5032. if( exponent & 1 ) result *= base;
  5033. exponent >>= 1;
  5034. base *= base;
  5035. case 1:
  5036. if( exponent ) result *= base;
  5037. default:
  5038. isOverflow = false;
  5039. return result;
  5040. }
  5041. }
  5042. }
  5043. asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow)
  5044. {
  5045. if( exponent == 0 && base == 0 )
  5046. {
  5047. // Domain error
  5048. isOverflow = true;
  5049. return 0;
  5050. }
  5051. else if( exponent >= 64 )
  5052. {
  5053. switch( base )
  5054. {
  5055. case 0:
  5056. isOverflow = false;
  5057. break;
  5058. case 1:
  5059. isOverflow = false;
  5060. return 1;
  5061. default:
  5062. isOverflow = true;
  5063. break;
  5064. }
  5065. return 0;
  5066. }
  5067. else
  5068. {
  5069. const asQWORD max_base = pow_info[exponent].MaxBaseu64;
  5070. const char high_bit = pow_info[exponent].HighBit;
  5071. if( max_base != 0 && max_base < base )
  5072. {
  5073. isOverflow = true;
  5074. return 0; // overflow
  5075. }
  5076. asQWORD result = 1;
  5077. switch( high_bit )
  5078. {
  5079. case 6:
  5080. if( exponent & 1 ) result *= base;
  5081. exponent >>= 1;
  5082. base *= base;
  5083. case 5:
  5084. if( exponent & 1 ) result *= base;
  5085. exponent >>= 1;
  5086. base *= base;
  5087. case 4:
  5088. if( exponent & 1 ) result *= base;
  5089. exponent >>= 1;
  5090. base *= base;
  5091. case 3:
  5092. if( exponent & 1 ) result *= base;
  5093. exponent >>= 1;
  5094. base *= base;
  5095. case 2:
  5096. if( exponent & 1 ) result *= base;
  5097. exponent >>= 1;
  5098. base *= base;
  5099. case 1:
  5100. if( exponent ) result *= base;
  5101. default:
  5102. isOverflow = false;
  5103. return result;
  5104. }
  5105. }
  5106. }
  5107. END_AS_NAMESPACE