as_context.cpp 187 KB

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