| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2022 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- The original version of this library can be located at:
- http://www.angelcode.com/angelscript/
- Andreas Jonsson
- [email protected]
- */
- //
- // as_restore.cpp
- //
- // Functions for saving and restoring module bytecode
- // asCRestore was originally written by Dennis Bollyn, [email protected]
- #include "as_config.h"
- #include "as_restore.h"
- #include "as_bytecode.h"
- #include "as_scriptobject.h"
- #include "as_texts.h"
- #include "as_debug.h"
- BEGIN_AS_NAMESPACE
- // Macros for doing endianess agnostic bitmask serialization
- #define SAVE_TO_BIT(dst, val, bit) ((dst) |= ((val) << (bit)))
- #define LOAD_FROM_BIT(dst, val, bit) ((dst) = ((val) >> (bit)) & 1)
- asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine)
- : module(_module), stream(_stream), engine(_engine)
- {
- error = false;
- bytesRead = 0;
- }
- int asCReader::ReadData(void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- int ret = 0;
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; ret >= 0 && n < size; n++ )
- ret = stream->Read(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; ret >= 0 && n >= 0; n-- )
- ret = stream->Read(((asBYTE*)data)+n, 1);
- #endif
- if (ret < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- bytesRead += size;
- return ret;
- }
- int asCReader::Read(bool *wasDebugInfoStripped)
- {
- TimeIt("asCReader::Read");
- // Before starting the load, make sure that
- // any existing resources have been freed
- module->InternalReset();
- // Call the inner method to do the actual loading
- int r = ReadInner();
- if( r < 0 )
- {
- // Something went wrong while loading the bytecode, so we need
- // to clean-up whatever has been created during the process.
- // Make sure none of the loaded functions attempt to release
- // references that have not yet been increased
- asUINT i;
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) )
- if( module->m_scriptFunctions[i]->scriptData )
- module->m_scriptFunctions[i]->scriptData->byteCode.SetLength(0);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->m_scriptGlobals.List();
- for( ; it; it++ )
- if( (*it)->GetInitFunc() )
- if( (*it)->GetInitFunc()->scriptData )
- (*it)->GetInitFunc()->scriptData->byteCode.SetLength(0);
- module->InternalReset();
- }
- else
- {
- // Init system functions properly
- engine->PrepareEngine();
- // Initialize the global variables (unless requested not to)
- if( engine->ep.initGlobalVarsAfterBuild )
- r = module->ResetGlobalVars(0);
- if( wasDebugInfoStripped )
- *wasDebugInfoStripped = noDebugInfo;
- }
- // Clean up the loaded string constants
- for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
- engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
- usedStringConstants.SetLength(0);
- return r;
- }
- int asCReader::Error(const char *msg)
- {
- // Don't write if it has already been reported an error earlier
- if( !error )
- {
- asCString str;
- str.Format(msg, bytesRead);
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- error = true;
- }
- return asERROR;
- }
- int asCReader::ReadInner()
- {
- TimeIt("asCReader::ReadInner");
- // This function will load each entity one by one from the stream.
- // If any error occurs, it will return to the caller who is
- // responsible for cleaning up the partially loaded entities.
- engine->deferValidationOfTemplateTypes = true;
- unsigned long i, count;
- asCScriptFunction* func;
- // Read the flag as 1 byte even on platforms with 4byte booleans
- noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0;
- // Read enums
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_enumTypes.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCEnumType *et = asNEW(asCEnumType)(engine);
- if( et == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(et, 1, &isExternal);
- // If the type is shared then we should use the original if it exists
- bool sharedExists = false;
- if( et->IsShared() )
- {
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
- {
- asCTypeInfo *t = engine->sharedScriptTypes[n];
- if( t &&
- t->IsShared() &&
- t->name == et->name &&
- t->nameSpace == et->nameSpace &&
- (t->flags & asOBJ_ENUM) )
- {
- asDELETE(et, asCEnumType);
- et = CastToEnumType(t);
- sharedExists = true;
- break;
- }
- }
- }
- if (isExternal && !sharedExists)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- asDELETE(et, asCEnumType);
- error = true;
- return asERROR;
- }
- if( sharedExists )
- {
- existingShared.Insert(et, true);
- et->AddRefInternal();
- }
- else
- {
- if( et->IsShared() )
- {
- engine->sharedScriptTypes.PushLast(et);
- et->AddRefInternal();
- }
- // Set this module as the owner
- et->module = module;
- }
- module->AddEnumType(et);
- if (isExternal)
- module->m_externalTypes.PushLast(et);
- ReadTypeDeclaration(et, 2);
- }
- if( error ) return asERROR;
- // classTypes[]
- // First restore the structure names, then the properties
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_classTypes.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- asCObjectType *ot = asNEW(asCObjectType)(engine);
- if( ot == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(ot, 1, &isExternal);
- // If the type is shared, then we should use the original if it exists
- bool sharedExists = false;
- if( ot->IsShared() )
- {
- for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ )
- {
- asCTypeInfo *ti = engine->sharedScriptTypes[n];
- asCObjectType *t = CastToObjectType(ti);
- if( t &&
- t->IsShared() &&
- t->name == ot->name &&
- t->nameSpace == ot->nameSpace &&
- t->IsInterface() == ot->IsInterface() )
- {
- asDELETE(ot, asCObjectType);
- ot = CastToObjectType(t);
- sharedExists = true;
- break;
- }
- }
- }
- if (isExternal && !sharedExists)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- asDELETE(ot, asCObjectType);
- error = true;
- return asERROR;
- }
- if( sharedExists )
- {
- existingShared.Insert(ot, true);
- ot->AddRefInternal();
- }
- else
- {
- if( ot->IsShared() )
- {
- engine->sharedScriptTypes.PushLast(ot);
- ot->AddRefInternal();
- }
- // Set this module as the owner
- ot->module = module;
- }
- module->AddClassType(ot);
- if (isExternal)
- module->m_externalTypes.PushLast(ot);
- }
- if( error ) return asERROR;
- // Read func defs
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_funcDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- bool isNew, isExternal;
- asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal);
- if(funcDef)
- {
- funcDef->module = module;
- asCFuncdefType *fdt = funcDef->funcdefType;
- fdt->module = module;
- module->AddFuncDef(fdt);
- engine->funcDefs.PushLast(fdt);
- // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module
- // Check if there is another identical funcdef from another module and if so reuse that instead
- if(funcDef->IsShared())
- {
- for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
- {
- asCFuncdefType *f2 = engine->funcDefs[n];
- if( f2 == 0 || fdt == f2 )
- continue;
- if( !f2->funcdef->IsShared() )
- continue;
- if( f2->name == fdt->name &&
- f2->nameSpace == fdt->nameSpace &&
- f2->parentClass == fdt->parentClass &&
- f2->funcdef->IsSignatureExceptNameEqual(funcDef) )
- {
- // Replace our funcdef for the existing one
- module->ReplaceFuncDef(fdt, f2);
- f2->AddRefInternal();
- if (isExternal)
- module->m_externalTypes.PushLast(f2);
- engine->funcDefs.RemoveValue(fdt);
- savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef;
- if (fdt->parentClass)
- {
- // The real funcdef should already be in the object
- asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0);
- fdt->parentClass = 0;
- }
- fdt->ReleaseInternal();
- funcDef = 0;
- break;
- }
- }
- }
- // Add the funcdef to the parentClass if this is a child funcdef
- if (funcDef && fdt->parentClass)
- fdt->parentClass->childFuncDefs.PushLast(fdt);
- // Check if an external shared funcdef was really found
- if (isExternal && funcDef)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- error = true;
- return asERROR;
- }
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- // Read interface methods
- for( i = 0; i < module->m_classTypes.GetLength() && !error; i++ )
- {
- if( module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 2);
- }
- // Read class methods and behaviours
- for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 2);
- }
- // Read class properties
- for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- ReadTypeDeclaration(module->m_classTypes[i], 3);
- }
- if( error ) return asERROR;
- // Read typedefs
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_typeDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCTypedefType *td = asNEW(asCTypedefType)(engine);
- if( td == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isExternal = false;
- ReadTypeDeclaration(td, 1, &isExternal);
- td->module = module;
- module->AddTypeDef(td);
- ReadTypeDeclaration(td, 2);
- }
- if( error ) return asERROR;
- // scriptGlobals[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- if( count && engine->ep.disallowGlobalVars )
- {
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED);
- Error(TXT_INVALID_BYTECODE_d);
- }
- module->m_scriptGlobals.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- ReadGlobalProperty();
- }
- // scriptFunctions[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- for( i = 0; i < count && !error; ++i )
- {
- size_t len = module->m_scriptFunctions.GetLength();
- bool isNew, isExternal;
- func = ReadFunction(isNew, true, true, true, &isExternal);
- if( func == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- // Is the function shared and was it created now?
- if( func->IsShared() && len != module->m_scriptFunctions.GetLength() )
- {
- // If the function already existed in another module, then
- // we need to replace it with previously existing one
- for( asUINT n = 0; n < engine->scriptFunctions.GetLength() && !error; n++ )
- {
- asCScriptFunction *realFunc = engine->scriptFunctions[n];
- if( realFunc &&
- realFunc != func &&
- realFunc->IsShared() &&
- realFunc->nameSpace == func->nameSpace &&
- realFunc->IsSignatureEqual(func) )
- {
- // Replace the recently created function with the pre-existing function
- module->m_scriptFunctions[module->m_scriptFunctions.GetLength()-1] = realFunc;
- realFunc->AddRefInternal();
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- engine->RemoveScriptFunction(func);
- // Insert the function in the dontTranslate array
- dontTranslate.Insert(realFunc, true);
- if (isExternal)
- module->m_externalFunctions.PushLast(realFunc);
- // Release the function, but make sure nothing else is released
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- func = 0;
- break;
- }
- }
- }
- // Check if an external shared func was really found
- if (isExternal && func)
- {
- asCString msg;
- msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
- error = true;
- return asERROR;
- }
- }
- // globalFunctions[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- for( i = 0; i < count && !error; ++i )
- {
- bool isNew;
- func = ReadFunction(isNew, false, false);
- if( func )
- {
- // All the global functions were already loaded while loading the scriptFunctions, here
- // we're just re-reading the references to know which goes into the globalFunctions array
- asASSERT( !isNew );
- module->m_globalFunctions.Put(func);
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( error ) return asERROR;
- // bindInformations[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- module->m_bindInformations.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- sBindInfo *info = asNEW(sBindInfo);
- if( info == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- bool isNew;
- info->importedFunctionSignature = ReadFunction(isNew, false, false);
- if( info->importedFunctionSignature == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- if( engine->freeImportedFunctionIdxs.GetLength() )
- {
- int id = engine->freeImportedFunctionIdxs.PopLast();
- info->importedFunctionSignature->id = int(FUNC_IMPORTED + id);
- engine->importedFunctions[id] = info;
- }
- else
- {
- info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength());
- engine->importedFunctions.PushLast(info);
- }
- ReadString(&info->importFromModule);
- info->boundFunctionId = -1;
- module->m_bindInformations.PushLast(info);
- }
- if( error ) return asERROR;
- // usedTypes[]
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedTypes.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- asCTypeInfo *ti = ReadTypeInfo();
- usedTypes.PushLast(ti);
- }
- // usedTypeIds[]
- if( !error )
- ReadUsedTypeIds();
- // usedFunctions[]
- if( !error )
- ReadUsedFunctions();
- // usedGlobalProperties[]
- if( !error )
- ReadUsedGlobalProps();
- // usedStringConstants[]
- if( !error )
- ReadUsedStringConstants();
- // usedObjectProperties
- if( !error )
- ReadUsedObjectProps();
- // Validate the template types
- if( !error )
- {
- for( i = 0; i < usedTypes.GetLength() && !error; i++ )
- {
- asCObjectType *ot = CastToObjectType(usedTypes[i]);
- if( !ot ||
- !(ot->flags & asOBJ_TEMPLATE) ||
- !ot->beh.templateCallback )
- continue;
- bool dontGarbageCollect = false;
- asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback];
- if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) )
- {
- asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace);
- for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += ot->templateSubTypes[n].Format(ot->nameSpace);
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- else
- {
- // If the callback said this template instance won't be garbage collected then remove the flag
- if( dontGarbageCollect )
- ot->flags &= ~asOBJ_GC;
- }
- }
- }
- engine->deferValidationOfTemplateTypes = false;
- if( error ) return asERROR;
- // Update the loaded bytecode to point to the correct types, property offsets,
- // function ids, etc. This is basically a linking stage.
- for( i = 0; i < module->m_scriptFunctions.GetLength() && !error; i++ )
- if( module->m_scriptFunctions[i]->funcType == asFUNC_SCRIPT )
- TranslateFunction(module->m_scriptFunctions[i]);
- asCSymbolTable<asCGlobalProperty>::iterator globIt = module->m_scriptGlobals.List();
- while( globIt && !error )
- {
- asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
- if( initFunc )
- TranslateFunction(initFunc);
- globIt++;
- }
- if( error ) return asERROR;
- // Add references for all functions (except for the pre-existing shared code)
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) )
- module->m_scriptFunctions[i]->AddReferences();
- globIt = module->m_scriptGlobals.List();
- while( globIt )
- {
- asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
- if( initFunc )
- initFunc->AddReferences();
- globIt++;
- }
- return error ? asERROR : asSUCCESS;
- }
- void asCReader::ReadUsedStringConstants()
- {
- TimeIt("asCReader::ReadUsedStringConstants");
- asCString str;
- asUINT count;
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- if (count > 0 && engine->stringFactory == 0)
- {
- Error(TXT_STRINGS_NOT_RECOGNIZED);
- return;
- }
- usedStringConstants.Allocate(count, false);
- for( asUINT i = 0; i < count; ++i )
- {
- ReadString(&str);
- usedStringConstants.PushLast(const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())));
- }
- }
- void asCReader::ReadUsedFunctions()
- {
- TimeIt("asCReader::ReadUsedFunctions");
- asUINT count;
- count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedFunctions.SetLength(count);
- if( usedFunctions.GetLength() != count )
- {
- // Out of memory
- error = true;
- return;
- }
- memset(usedFunctions.AddressOf(), 0, sizeof(asCScriptFunction *)*count);
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- char c;
- // Read the data to be able to uniquely identify the function
- // Is the function from the module or the application?
- ReadData(&c, 1);
- if( c == 'n' )
- {
- // Null function pointer
- usedFunctions[n] = 0;
- }
- else
- {
- asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY);
- asCObjectType *parentClass = 0;
- ReadFunctionSignature(&func, &parentClass);
- if( error )
- {
- func.funcType = asFUNC_DUMMY;
- return;
- }
- // Find the correct function
- if( c == 'm' )
- {
- if( func.funcType == asFUNC_IMPORTED )
- {
- for( asUINT i = 0; i < module->m_bindInformations.GetLength(); i++ )
- {
- asCScriptFunction *f = module->m_bindInformations[i]->importedFunctionSignature;
- if( func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.funcType == asFUNC_FUNCDEF )
- {
- const asCArray<asCFuncdefType *> &funcs = module->m_funcDefs;
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if( f == 0 ||
- func.name != f->name ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
- funcs[i]->parentClass != parentClass )
- continue;
- asASSERT( f->objectType == 0 );
- usedFunctions[n] = f;
- break;
- }
- }
- else
- {
- // TODO: optimize: Global functions should be searched for in module->globalFunctions
- // TODO: optimize: funcdefs should be searched for in module->funcDefs
- // TODO: optimize: object methods should be searched for directly in the object type
- for( asUINT i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = module->m_scriptFunctions[i];
- if( func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if (c == 's')
- {
- // Look for shared entities in the engine, as they may not necessarily be part
- // of the scope of the module if they have been inhereted from other modules.
- if (func.funcType == asFUNC_FUNCDEF)
- {
- const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
- for (asUINT i = 0; i < funcs.GetLength(); i++)
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if (f == 0 ||
- func.name != f->name ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) ||
- funcs[i]->parentClass != parentClass)
- continue;
- asASSERT(f->objectType == 0);
- usedFunctions[n] = f;
- break;
- }
- }
- else
- {
- for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[i];
- if (f == 0 || !f->IsShared() ||
- func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else
- {
- asASSERT(c == 'a');
- if( func.funcType == asFUNC_FUNCDEF )
- {
- // This is a funcdef (registered or shared)
- const asCArray<asCFuncdefType *> &funcs = engine->funcDefs;
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = funcs[i]->funcdef;
- if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass )
- continue;
- asASSERT( f->objectType == 0 );
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.name[0] == '$' )
- {
- // This is a special function
- if( func.name == "$beh0" && func.objectType )
- {
- if (func.objectType->flags & asOBJ_TEMPLATE)
- {
- // Look for the matching constructor inside the factory stubs generated for the template instance
- // See asCCompiler::PerformFunctionCall
- for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
-
- // Find the id of the real constructor and not the generated stub
- asUINT id = 0;
- asDWORD *bc = f->scriptData->byteCode.AddressOf();
- while (bc)
- {
- if ((*(asBYTE*)bc) == asBC_CALLSYS)
- {
- id = asBC_INTARG(bc);
- break;
- }
- bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
- }
- f = engine->scriptFunctions[id];
- if (f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- if( usedFunctions[n] == 0 )
- {
- // This is a class constructor, so we can search directly in the object type's constructors
- for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++)
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
- if (f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f))
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if( func.name == "$fact" || func.name == "$beh3" )
- {
- // This is a factory (or stub), so look for the function in the return type's factories
- asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo());
- if( objType )
- {
- for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]];
- if( f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- }
- else if( func.name == "$list" )
- {
- // listFactory is used for both factory is global and returns a handle and constructor that is a method
- asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo());
- if( objType )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
- if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- usedFunctions[n] = f;
- }
- }
- else if( func.name == "$beh2" )
- {
- // This is a destructor, so check the object type's destructor
- asCObjectType *objType = func.objectType;
- if( objType )
- {
- asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct];
- if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- usedFunctions[n] = f;
- }
- }
- else if( func.name == "$dlgte" )
- {
- // This is the delegate factory
- asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
- asASSERT( f && func.IsSignatureEqual(f) );
- usedFunctions[n] = f;
- }
- else
- {
- // Must match one of the above cases
- asASSERT(false);
- }
- }
- else if( func.objectType == 0 )
- {
- // This is a global function
- const asCArray<asUINT> &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name);
- for( asUINT i = 0; i < funcs.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]);
- if( f == 0 ||
- !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- else if( func.objectType )
- {
- // It is a class member, so we can search directly in the object type's members
- // TODO: virtual function is different that implemented method
- for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]];
- if( f == 0 ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- if( usedFunctions[n] == 0 )
- {
- // TODO: clean up: This part of the code should never happen. All functions should
- // be found in the above logic. The only valid reason to come here
- // is if the bytecode is wrong and the function doesn't exist anyway.
- // This loop is kept temporarily until we can be certain all scenarios
- // are covered.
- for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[i];
- if( f == 0 ||
- func.objectType != f->objectType ||
- func.nameSpace != f->nameSpace ||
- !func.IsSignatureEqual(f) )
- continue;
- usedFunctions[n] = f;
- break;
- }
- // No function is expected to be found
- asASSERT(usedFunctions[n] == 0);
- }
- }
- // Set the type to dummy so it won't try to release the id
- func.funcType = asFUNC_DUMMY;
- if( usedFunctions[n] == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- }
- void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass)
- {
- asUINT i, count;
- asCDataType dt;
- int num;
- ReadString(&func->name);
- if( func->name == DELEGATE_FACTORY )
- {
- // It's not necessary to read anymore, everything is known
- asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
- asASSERT( f );
- func->returnType = f->returnType;
- func->parameterTypes = f->parameterTypes;
- func->inOutFlags = f->inOutFlags;
- func->funcType = f->funcType;
- func->defaultArgs = f->defaultArgs;
- func->nameSpace = f->nameSpace;
- return;
- }
- ReadDataType(&func->returnType);
- count = SanityCheck(ReadEncodedUInt(), 256);
- func->parameterTypes.Allocate(count, false);
- for( i = 0; i < count; ++i )
- {
- ReadDataType(&dt);
- func->parameterTypes.PushLast(dt);
- }
- func->inOutFlags.SetLength(func->parameterTypes.GetLength());
- if( func->inOutFlags.GetLength() != func->parameterTypes.GetLength() )
- {
- // Out of memory
- error = true;
- return;
- }
- memset(func->inOutFlags.AddressOf(), 0, sizeof(asETypeModifiers)*func->inOutFlags.GetLength());
- if (func->parameterTypes.GetLength() > 0)
- {
- count = ReadEncodedUInt();
- if (count > func->parameterTypes.GetLength())
- {
- // Cannot be more than the number of arguments
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- for (i = 0; i < count; ++i)
- {
- num = ReadEncodedUInt();
- func->inOutFlags[i] = static_cast<asETypeModifiers>(num);
- }
- }
- func->funcType = (asEFuncType)ReadEncodedUInt();
- // Read the default args, from last to first
- if (func->parameterTypes.GetLength() > 0)
- {
- count = ReadEncodedUInt();
- if (count > func->parameterTypes.GetLength())
- {
- // Cannot be more than the number of arguments
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- if (count)
- {
- func->defaultArgs.SetLength(func->parameterTypes.GetLength());
- if (func->defaultArgs.GetLength() != func->parameterTypes.GetLength())
- {
- // Out of memory
- error = true;
- return;
- }
- memset(func->defaultArgs.AddressOf(), 0, sizeof(asCString*)*func->defaultArgs.GetLength());
- for (i = 0; i < count; i++)
- {
- asCString *str = asNEW(asCString);
- if (str == 0)
- {
- // Out of memory
- error = true;
- return;
- }
- func->defaultArgs[func->defaultArgs.GetLength() - 1 - i] = str;
- ReadString(str);
- }
- }
- }
- func->objectType = CastToObjectType(ReadTypeInfo());
- if( func->objectType )
- {
- func->objectType->AddRefInternal();
- asBYTE b;
- ReadData(&b, 1);
- func->SetReadOnly((b & 1) ? true : false);
- func->SetPrivate((b & 2) ? true : false);
- func->SetProtected((b & 4) ? true : false);
- func->nameSpace = func->objectType->nameSpace;
- }
- else
- {
- if (func->funcType == asFUNC_FUNCDEF)
- {
- asBYTE b;
- ReadData(&b, 1);
- if (b == 'n')
- {
- asCString ns;
- ReadString(&ns);
- func->nameSpace = engine->AddNameSpace(ns.AddressOf());
- }
- else if (b == 'o')
- {
- func->nameSpace = 0;
- if (parentClass)
- *parentClass = CastToObjectType(ReadTypeInfo());
- else
- error = true;
- }
- else
- error = true;
- }
- else
- {
- asCString ns;
- ReadString(&ns);
- func->nameSpace = engine->AddNameSpace(ns.AddressOf());
- }
- }
- }
- asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal)
- {
- isNew = false;
- if (isExternal) *isExternal = false;
- if( error ) return 0;
- char c;
- ReadData(&c, 1);
- if( c == '\0' )
- {
- // There is no function, so return a null pointer
- return 0;
- }
- if( c == 'r' )
- {
- // This is a reference to a previously saved function
- asUINT index = ReadEncodedUInt();
- if( index < savedFunctions.GetLength() )
- return savedFunctions[index];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- // Load the new function
- isNew = true;
- asCScriptFunction *func = asNEW(asCScriptFunction)(engine,0,asFUNC_DUMMY);
- if( func == 0 )
- {
- // Out of memory
- error = true;
- return 0;
- }
- savedFunctions.PushLast(func);
- int i;
- asCDataType dt;
- asCObjectType *parentClass = 0;
- ReadFunctionSignature(func, &parentClass);
- if( error )
- {
- func->DestroyHalfCreated();
- return 0;
- }
- if( func->funcType == asFUNC_SCRIPT )
- {
- // Skip this for external shared entities
- if (module->m_externalTypes.IndexOf(func->objectType) >= 0)
- {
- // Replace with the real function from the existing entity
- isNew = false;
- asCObjectType *ot = func->objectType;
- for (asUINT n = 0; n < ot->methods.GetLength(); n++)
- {
- asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]];
- if (func2->funcType == asFUNC_VIRTUAL)
- func2 = ot->virtualFunctionTable[func2->vfTableIdx];
- if (func->IsSignatureEqual(func2))
- {
- func->DestroyHalfCreated();
- // as this is an existing function it shouldn't be translated as if just loaded
- dontTranslate.Insert(func2, true);
- // update the saved functions for future references
- savedFunctions[savedFunctions.GetLength() - 1] = func2;
- // As it is an existing function it shouldn't be added to the module or the engine
- return func2;
- }
- }
- }
- else
- {
- char bits;
- ReadData(&bits, 1);
- func->SetShared((bits & 1) ? true : false);
- func->SetExplicit((bits & 32) ? true : false);
- func->dontCleanUpOnException = (bits & 2) ? true : false;
- if ((bits & 4) && isExternal)
- *isExternal = true;
- // for external shared functions the rest is not needed
- if (!(bits & 4))
- {
- func->AllocateScriptFunctionData();
- if (func->scriptData == 0)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- if (addToGC && !addToModule)
- engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours);
- ReadByteCode(func);
- func->scriptData->variableSpace = SanityCheck(ReadEncodedUInt(), 1000000);
- if (bits & 8)
- {
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariableInfo.SetLength(length);
- for (i = 0; i < length; ++i)
- {
- func->scriptData->objVariableInfo[i].programPos = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->objVariableInfo[i].variableOffset = SanityCheck(ReadEncodedInt(), 10000);
- asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt();
- func->scriptData->objVariableInfo[i].option = option;
- if (option != asOBJ_INIT &&
- option != asOBJ_UNINIT &&
- option != asBLOCK_BEGIN &&
- option != asBLOCK_END &&
- option != asOBJ_VARDECL)
- {
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- }
- }
- if (bits & 16)
- {
- // Read info on try/catch blocks
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->tryCatchInfo.SetLength(length);
- for (i = 0; i < length; ++i)
- {
- // The program position must be adjusted to be in number of instructions
- func->scriptData->tryCatchInfo[i].tryPos = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->tryCatchInfo[i].catchPos = SanityCheck(ReadEncodedUInt(), 1000000);
- }
- }
- if (!noDebugInfo)
- {
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->lineNumbers.SetLength(length);
- if (int(func->scriptData->lineNumbers.GetLength()) != length)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- for (i = 0; i < length; ++i)
- func->scriptData->lineNumbers[i] = ReadEncodedUInt();
- // Read the array of script sections
- length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->sectionIdxs.SetLength(length);
- if (int(func->scriptData->sectionIdxs.GetLength()) != length)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- for (i = 0; i < length; ++i)
- {
- if ((i & 1) == 0)
- func->scriptData->sectionIdxs[i] = ReadEncodedUInt();
- else
- {
- asCString str;
- ReadString(&str);
- func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf());
- }
- }
- }
- // Read the variable information
- int length = SanityCheck(ReadEncodedUInt(), 1000000);
- func->scriptData->variables.Allocate(length, false);
- for (i = 0; i < length; i++)
- {
- asSScriptVariable *var = asNEW(asSScriptVariable);
- if (var == 0)
- {
- // Out of memory
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- func->scriptData->variables.PushLast(var);
- if (!noDebugInfo)
- {
- var->declaredAtProgramPos = ReadEncodedUInt();
- ReadString(&var->name);
- }
- else
- var->declaredAtProgramPos = 0;
- var->stackOffset = SanityCheck(ReadEncodedInt(),10000);
- var->onHeap = var->stackOffset & 1;
- var->stackOffset >>= 1;
- ReadDataType(&var->type);
- if (error)
- {
- // No need to continue (the error has already been reported before)
- func->DestroyHalfCreated();
- return 0;
- }
- }
- // Read script section name
- if (!noDebugInfo)
- {
- asCString name;
- ReadString(&name);
- func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf());
- func->scriptData->declaredAt = ReadEncodedUInt();
- }
- // Read parameter names
- if (!noDebugInfo)
- {
- asUINT countParam = asUINT(ReadEncodedUInt64());
- if (countParam > func->parameterTypes.GetLength())
- {
- error = true;
- func->DestroyHalfCreated();
- return 0;
- }
- func->parameterNames.SetLength(countParam);
- for (asUINT n = 0; n < countParam; n++)
- ReadString(&func->parameterNames[n]);
- }
- }
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- func->vfTableIdx = ReadEncodedUInt();
- }
- else if( func->funcType == asFUNC_FUNCDEF )
- {
- asBYTE bits;
- ReadData(&bits, 1);
- if( bits & 1 )
- func->SetShared(true);
- if ((bits & 2) && isExternal)
- *isExternal = true;
- // The asCFuncdefType constructor adds itself to the func->funcdefType member
- asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func);
- fdt->parentClass = parentClass;
- }
- // Methods loaded for shared objects, owned by other modules should not be created as new functions
- if( func->objectType && func->objectType->module != module )
- {
- // Return the real function from the object
- asCScriptFunction *realFunc = 0;
- bool found = false;
- if( func->funcType == asFUNC_SCRIPT )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.destruct];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- }
- for( asUINT n = 0; !found && n < func->objectType->beh.constructors.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.constructors[n]];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->beh.factories.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->beh.factories[n]];
- if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->methods.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->methods[n]];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- for( asUINT n = 0; !found && n < func->objectType->virtualFunctionTable.GetLength(); n++ )
- {
- realFunc = func->objectType->virtualFunctionTable[n];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- found = true;
- break;
- }
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- // If the loaded function is a virtual function, then look for the identical virtual function in the methods array
- for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ )
- {
- realFunc = engine->scriptFunctions[func->objectType->methods[n]];
- if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) )
- {
- asASSERT( func->vfTableIdx == realFunc->vfTableIdx );
- found = true;
- break;
- }
- }
- }
- if( found )
- {
- // as this is an existing function it shouldn't be translated as if just loaded
- dontTranslate.Insert(realFunc, true);
- // update the saved functions for future references
- savedFunctions[savedFunctions.GetLength() - 1] = realFunc;
- if( realFunc->funcType == asFUNC_VIRTUAL && addToModule )
- {
- // Virtual methods must be added to the module's script functions array,
- // even if they are not owned by the module
- module->m_scriptFunctions.PushLast(realFunc);
- realFunc->AddRefInternal();
- }
- }
- else
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, func->objectType->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
-
- Error(TXT_INVALID_BYTECODE_d);
- savedFunctions.PopLast();
- realFunc = 0;
- }
- // Destroy the newly created function instance since it has been replaced by an existing function
- isNew = false;
- func->DestroyHalfCreated();
-
- // As it is an existing function it shouldn't be added to the module or the engine
- return realFunc;
- }
- if( addToModule )
- {
- // The refCount is already 1
- module->m_scriptFunctions.PushLast(func);
- func->module = module;
- }
- if( addToEngine )
- {
- func->id = engine->GetNextScriptFunctionId();
- engine->AddScriptFunction(func);
- }
- if( func->objectType )
- func->ComputeSignatureId();
- return func;
- }
- void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal)
- {
- if( phase == 1 )
- {
- asASSERT(isExternal);
- if (isExternal)
- *isExternal = false;
- // Read the initial attributes
- ReadString(&type->name);
- ReadData(&type->flags, 4);
- type->size = SanityCheck(ReadEncodedUInt(), 1000000);
- asCString ns;
- ReadString(&ns);
- type->nameSpace = engine->AddNameSpace(ns.AddressOf());
- // Verify that the flags match the asCTypeInfo
- if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) ||
- (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) ||
- (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE))))
- {
- error = true;
- return;
- }
- // Reset the size of script classes, since it will be recalculated as properties are added
- if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 )
- type->size = sizeof(asCScriptObject);
- asCObjectType *ot = CastToObjectType(type);
- if (ot)
- {
- // Use the default script class behaviours
- ot->beh = engine->scriptTypeBehaviours.beh;
- ot->beh.construct = 0;
- ot->beh.factory = 0;
- ot->beh.constructors.PopLast(); // These will be read from the file
- ot->beh.factories.PopLast(); // These will be read from the file
- engine->scriptFunctions[ot->beh.addref]->AddRefInternal();
- engine->scriptFunctions[ot->beh.release]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal();
- engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal();
- engine->scriptFunctions[ot->beh.copy]->AddRefInternal();
- // TODO: weak: Should not do this if the class has been declared with 'noweak'
- engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal();
- }
- // external shared flag
- if (type->flags & asOBJ_SHARED)
- {
- char c;
- ReadData(&c, 1);
- if (c == 'e')
- *isExternal = true;
- else if (c != ' ')
- {
- error = true;
- return;
- }
- }
- }
- else if( phase == 2 )
- {
- // external shared types doesn't store this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- if( type->flags & asOBJ_ENUM )
- {
- asCEnumType *t = CastToEnumType(type);
- int count = SanityCheck(ReadEncodedUInt(), 1000000);
- bool sharedExists = existingShared.MoveTo(0, type);
- if( !sharedExists )
- {
- t->enumValues.Allocate(count, false);
- for( int n = 0; n < count; n++ )
- {
- asSEnumValue *e = asNEW(asSEnumValue);
- if( e == 0 )
- {
- // Out of memory
- error = true;
- return;
- }
- ReadString(&e->name);
- ReadData(&e->value, 4); // TODO: Should be encoded
- t->enumValues.PushLast(e);
- }
- }
- else
- {
- // Verify that the enum values exists in the original
- asCString name;
- int value;
- for( int n = 0; n < count; n++ )
- {
- ReadString(&name);
- ReadData(&value, 4); // TODO: Should be encoded
- bool found = false;
- for( asUINT e = 0; e < t->enumValues.GetLength(); e++ )
- {
- if( t->enumValues[e]->name == name &&
- t->enumValues[e]->value == value )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( type->flags & asOBJ_TYPEDEF )
- {
- asCTypedefType *td = CastToTypedefType(type);
- asASSERT(td);
- eTokenType t = (eTokenType)ReadEncodedUInt();
- td->aliasForType = asCDataType::CreatePrimitive(t, false);
- }
- else
- {
- asCObjectType *ot = CastToObjectType(type);
- asASSERT(ot);
- // If the type is shared and pre-existing, we should just
- // validate that the loaded methods match the original
- bool sharedExists = existingShared.MoveTo(0, type);
- if( sharedExists )
- {
- asCObjectType *dt = CastToObjectType(ReadTypeInfo());
- if( ot->derivedFrom != dt )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- else
- {
- ot->derivedFrom = CastToObjectType(ReadTypeInfo());
- if( ot->derivedFrom )
- ot->derivedFrom->AddRefInternal();
- }
- // interfaces[] / interfaceVFTOffsets[]
- int size = SanityCheck(ReadEncodedUInt(), 1000000);
- if( sharedExists )
- {
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = CastToObjectType(ReadTypeInfo());
- if (!ot->IsInterface())
- ReadEncodedUInt();
- if( !type->Implements(intf) )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- else
- {
- ot->interfaces.Allocate(size, false);
- if( !ot->IsInterface() )
- ot->interfaceVFTOffsets.Allocate(size, false);
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = CastToObjectType(ReadTypeInfo());
- ot->interfaces.PushLast(intf);
- if (!ot->IsInterface())
- {
- asUINT offset = SanityCheck(ReadEncodedUInt(), 1000000);
- ot->interfaceVFTOffsets.PushLast(offset);
- }
- }
- }
- // behaviours
- if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.destruct);
- if( (realFunc == 0 && func == 0) || realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( func && savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- }
- else
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( func )
- {
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- dontTranslate.Insert(realFunc, true);
- }
- }
- else
- {
- if( func )
- {
- ot->beh.destruct = func->id;
- func->AddRefInternal();
- }
- else
- ot->beh.destruct = 0;
- }
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( int n = 0; n < size; n++ )
- {
- func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->beh.constructors.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->beh.constructors.PushLast(func->id);
- func->AddRefInternal();
- if( func->parameterTypes.GetLength() == 0 )
- ot->beh.construct = func->id;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->beh.factories.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->beh.factories.PushLast(func->id);
- func->AddRefInternal();
- if( func->parameterTypes.GetLength() == 0 )
- ot->beh.factory = func->id;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- // methods[]
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- int n;
- for( n = 0; n < size; n++ )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->methods.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]);
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- if( func->id == func->signatureId )
- engine->signatureIds.RemoveValue(func);
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- // If the method is the assignment operator we need to replace the default implementation
- if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 &&
- func->parameterTypes[0].GetTypeInfo() == func->objectType &&
- (func->inOutFlags[0] & asTM_INREF) )
- {
- engine->scriptFunctions[ot->beh.copy]->ReleaseInternal();
- ot->beh.copy = func->id;
- func->AddRefInternal();
- }
- ot->methods.PushLast(func->id);
- func->AddRefInternal();
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- // virtualFunctionTable[]
- size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( n = 0; n < size; n++ )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists);
- if( func )
- {
- if( sharedExists )
- {
- // Find the real function in the object, and update the savedFunctions array
- bool found = false;
- for( asUINT f = 0; f < ot->virtualFunctionTable.GetLength(); f++ )
- {
- asCScriptFunction *realFunc = ot->virtualFunctionTable[f];
- if( realFunc->IsSignatureEqual(func) )
- {
- // If the function is not the last, then the substitution has already occurred before
- if( savedFunctions[savedFunctions.GetLength()-1] == func )
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- found = true;
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( isNew )
- {
- // Destroy the function without releasing any references
- func->id = 0;
- if( func->scriptData )
- func->scriptData->byteCode.SetLength(0);
- func->ReleaseInternal();
- }
- }
- else
- {
- ot->virtualFunctionTable.PushLast(func);
- func->AddRefInternal();
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( phase == 3 )
- {
- // external shared types doesn't store this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- asCObjectType *ot = CastToObjectType(type);
- // This is only done for object types
- asASSERT(ot);
- // properties[]
- asUINT size = SanityCheck(ReadEncodedUInt(), 1000000);
- for( asUINT n = 0; n < size; n++ )
- ReadObjectProperty(ot);
- }
- }
- asWORD asCReader::ReadEncodedUInt16()
- {
- asDWORD dw = ReadEncodedUInt();
- if( (dw>>16) != 0 && (dw>>16) != 0xFFFF )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- return asWORD(dw & 0xFFFF);
- }
- asUINT asCReader::ReadEncodedUInt()
- {
- asQWORD qw = ReadEncodedUInt64();
- if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- return asUINT(qw & 0xFFFFFFFFu);
- }
- int asCReader::ReadEncodedInt()
- {
- return int(ReadEncodedUInt());
- }
- asQWORD asCReader::ReadEncodedUInt64()
- {
- asQWORD i = 0;
- asBYTE b = 0xFF; // set to 0xFF to better catch if the stream doesn't update the value
- ReadData(&b, 1);
- bool isNegative = ( b & 0x80 ) ? true : false;
- b &= 0x7F;
- if( (b & 0x7F) == 0x7F )
- {
- ReadData(&b, 1); i = asQWORD(b) << 56;
- ReadData(&b, 1); i += asQWORD(b) << 48;
- ReadData(&b, 1); i += asQWORD(b) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x7E) == 0x7E )
- {
- i = asQWORD(b & 0x01) << 48;
- ReadData(&b, 1); i += asQWORD(b) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x7C) == 0x7C )
- {
- i = asQWORD(b & 0x03) << 40;
- ReadData(&b, 1); i += asQWORD(b) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x78) == 0x78 )
- {
- i = asQWORD(b & 0x07) << 32;
- ReadData(&b, 1); i += asUINT(b) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x70) == 0x70 )
- {
- i = asUINT(b & 0x0F) << 24;
- ReadData(&b, 1); i += asUINT(b) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x60) == 0x60 )
- {
- i = asUINT(b & 0x1F) << 16;
- ReadData(&b, 1); i += asUINT(b) << 8;
- ReadData(&b, 1); i += b;
- }
- else if( (b & 0x40) == 0x40 )
- {
- i = asUINT(b & 0x3F) << 8;
- ReadData(&b, 1); i += b;
- }
- else
- {
- i = b;
- }
- if( isNegative )
- i = (asQWORD)(-asINT64(i));
- return i;
- }
- asUINT asCReader::SanityCheck(asUINT val, asUINT max)
- {
- if (val > max)
- {
- Error(TXT_INVALID_BYTECODE_d);
- // Return 0 as default value
- return 0;
- }
- return val;
- }
- int asCReader::SanityCheck(int val, asUINT max)
- {
- if (val > int(max) || val < -int(max))
- {
- Error(TXT_INVALID_BYTECODE_d);
- // Return 0 as default value
- return 0;
- }
- return val;
- }
- void asCReader::ReadString(asCString* str)
- {
- asUINT len = SanityCheck(ReadEncodedUInt(), 1000000);
- if( len & 1 )
- {
- asUINT idx = len/2;
- if( idx < savedStrings.GetLength() )
- *str = savedStrings[idx];
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- else if( len > 0 )
- {
- len /= 2;
- str->SetLength(len);
- int r = stream->Read(str->AddressOf(), len);
- if (r < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- savedStrings.PushLast(*str);
- }
- else
- str->SetLength(0);
- }
- void asCReader::ReadGlobalProperty()
- {
- asCString name;
- asCDataType type;
- ReadString(&name);
- asCString ns;
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- ReadDataType(&type);
- asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace);
- // Read the initialization function
- bool isNew;
- // Do not add the function to the GC at this time. It will
- // only be added to the GC when the module releases the property
- asCScriptFunction *func = ReadFunction(isNew, false, true, false);
- if( func )
- {
- // Make sure the function knows it is owned by the module
- func->module = module;
- prop->SetInitFunc(func);
- func->ReleaseInternal();
- }
- }
- void asCReader::ReadObjectProperty(asCObjectType *ot)
- {
- asCString name;
- ReadString(&name);
- asCDataType dt;
- ReadDataType(&dt);
- int flags = ReadEncodedUInt();
- bool isPrivate = (flags & 1) ? true : false;
- bool isProtected = (flags & 2) ? true : false;
- bool isInherited = (flags & 4) ? true : false;
- // TODO: shared: If the type is shared and pre-existing, we should just
- // validate that the loaded methods match the original
- if( !existingShared.MoveTo(0, ot) )
- ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited);
- }
- void asCReader::ReadDataType(asCDataType *dt)
- {
- // Check if this is a previously used type
- asUINT idx = ReadEncodedUInt();
- if( idx != 0 )
- {
- // Get the datatype from the cache
- *dt = savedDataTypes[idx-1];
- return;
- }
- // Read the type definition
- eTokenType tokenType = (eTokenType)ReadEncodedUInt();
- // Reserve a spot in the savedDataTypes
- asUINT saveSlot = savedDataTypes.GetLength();
- savedDataTypes.PushLast(asCDataType());
- // Read the datatype for the first time
- asCTypeInfo *ti = 0;
- if( tokenType == ttIdentifier )
- ti = ReadTypeInfo();
- // Read type flags as a bitmask
- // Endian-safe code
- bool isObjectHandle, isHandleToConst, isReference, isReadOnly;
- char b = 0;
- ReadData(&b, 1);
- LOAD_FROM_BIT(isObjectHandle, b, 0);
- LOAD_FROM_BIT(isHandleToConst, b, 1);
- LOAD_FROM_BIT(isReference, b, 2);
- LOAD_FROM_BIT(isReadOnly, b, 3);
- if( tokenType == ttIdentifier )
- *dt = asCDataType::CreateType(ti, false);
- else
- *dt = asCDataType::CreatePrimitive(tokenType, false);
- if( isObjectHandle )
- {
- dt->MakeReadOnly(isHandleToConst ? true : false);
- // Here we must allow a scoped type to be a handle
- // e.g. if the datatype is for a system function
- dt->MakeHandle(true, true);
- }
- dt->MakeReadOnly(isReadOnly ? true : false);
- dt->MakeReference(isReference ? true : false);
- if (tokenType == ttUnrecognizedToken && isObjectHandle && ti == 0)
- *dt = asCDataType::CreateNullHandle();
- // Update the previously saved slot
- savedDataTypes[saveSlot] = *dt;
- }
- asCTypeInfo* asCReader::ReadTypeInfo()
- {
- asCTypeInfo *ot = 0;
- char ch;
- ReadData(&ch, 1);
- if( ch == 'a' )
- {
- // Read the name of the template type
- asCString typeName, ns;
- ReadString(&typeName);
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
- asCObjectType *tmpl = CastToObjectType(tmp);
- if( tmpl == 0 )
- {
- asCString str;
- str.Format(TXT_TEMPLATE_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- asUINT numSubTypes = SanityCheck(ReadEncodedUInt(), 100);
- asCArray<asCDataType> subTypes;
- for( asUINT n = 0; n < numSubTypes; n++ )
- {
- ReadData(&ch, 1);
- if( ch == 's' )
- {
- asCDataType dt;
- ReadDataType(&dt);
- subTypes.PushLast(dt);
- }
- else
- {
- eTokenType tokenType = (eTokenType)ReadEncodedUInt();
- asCDataType dt = asCDataType::CreatePrimitive(tokenType, false);
- subTypes.PushLast(dt);
- }
- }
- // Return the actual template if the subtypes are the template's dummy types
- if( tmpl->templateSubTypes == subTypes )
- ot = tmpl;
- else
- {
- // Get the template instance type based on the loaded subtypes
- ot = engine->GetTemplateInstanceType(tmpl, subTypes, module);
- }
- if( ot == 0 )
- {
- // Show all subtypes in error message
- asCString sub = subTypes[0].Format(nameSpace);
- for( asUINT n = 1; n < subTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += subTypes[n].Format(nameSpace);
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, typeName.AddressOf(), sub.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( ch == 'l' )
- {
- asCObjectType *st = CastToObjectType(ReadTypeInfo());
- if( st == 0 || st->beh.listFactory == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- ot = engine->GetListPatternType(st->beh.listFactory);
- }
- else if( ch == 's' )
- {
- // Read the name of the template subtype
- asCString typeName;
- ReadString(&typeName);
- // Find the template subtype
- ot = 0;
- for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ )
- {
- if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName )
- {
- ot = engine->templateSubTypes[n];
- break;
- }
- }
- if( ot == 0 )
- {
- asCString str;
- str.Format(TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( ch == 'o' )
- {
- // Read the object type name
- asCString typeName, ns;
- ReadString(&typeName);
- ReadString(&ns);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" )
- {
- // Find the object type
- ot = module->GetType(typeName.AddressOf(), nameSpace);
- if (!ot)
- ot = engine->GetRegisteredType(typeName.AddressOf(), nameSpace);
- if( ot == 0 )
- {
- asCString str;
- str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else if( typeName == "$obj" )
- {
- ot = &engine->scriptTypeBehaviours;
- }
- else if( typeName == "$func" )
- {
- ot = &engine->functionBehaviours;
- }
- else
- asASSERT( false );
- }
- else if (ch == 'c')
- {
- // Read the object type name
- asCString typeName, ns;
- ReadString(&typeName);
- // Read the parent class
- asCObjectType *parentClass = CastToObjectType(ReadTypeInfo());
- if (parentClass == 0)
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- // Find the child type in the parentClass
- for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++)
- {
- if (parentClass->childFuncDefs[n]->name == typeName)
- ot = parentClass->childFuncDefs[n];
- }
- if (ot == 0)
- {
- asCString str;
- str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- else
- {
- // No object type
- asASSERT( ch == '\0' || error );
- ot = 0;
- }
- return ot;
- }
- void asCReader::ReadByteCode(asCScriptFunction *func)
- {
- asASSERT( func->scriptData );
- // Read number of instructions
- asUINT total, numInstructions;
- total = numInstructions = SanityCheck(ReadEncodedUInt(), 1000000);
- // Reserve some space for the instructions
- func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false);
- asUINT pos = 0;
- while( numInstructions )
- {
- asBYTE b;
- ReadData(&b, 1);
- // Allocate the space for the instruction
- asUINT len = asBCTypeSize[asBCInfo[b].type];
- asUINT newSize = asUINT(func->scriptData->byteCode.GetLength()) + len;
- if( func->scriptData->byteCode.GetCapacity() < newSize )
- {
- // Determine the average size of the loaded instructions and re-estimate the final size
- asUINT size = asUINT(float(newSize) / (total - numInstructions) * total) + 1;
- func->scriptData->byteCode.AllocateNoConstruct(size, true);
- }
- if( !func->scriptData->byteCode.SetLengthNoConstruct(newSize) )
- {
- // Out of memory
- error = true;
- return;
- }
- asDWORD *bc = func->scriptData->byteCode.AddressOf() + pos;
- pos += len;
- switch( asBCInfo[b].type )
- {
- case asBCTYPE_NO_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- }
- break;
- case asBCTYPE_W_ARG:
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- }
- break;
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the word argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the dword argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the first argument
- *bc++ = ReadEncodedUInt();
- // Read the second argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- // Read the third argument
- w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- case asBCTYPE_wW_W_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- bc++;
- }
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the second argument
- w = ReadEncodedUInt16();
- *(asWORD*)bc = w;
- bc++;
- // Read the third argument
- asDWORD dw = ReadEncodedUInt();
- *bc++ = dw;
- }
- break;
- case asBCTYPE_QW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- }
- break;
- case asBCTYPE_QW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- bc++;
- // Read the first argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- // Read the second argument
- asDWORD dw = ReadEncodedUInt();
- *bc++ = dw;
- }
- break;
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_wW_QW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the first argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the argument
- asQWORD qw = ReadEncodedUInt64();
- *(asQWORD*)bc = qw;
- bc += 2;
- }
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- {
- *(asBYTE*)(bc) = b;
- // Read the 1st argument
- asWORD w = ReadEncodedUInt16();
- *(((asWORD*)bc)+1) = w;
- bc++;
- // Read the 2nd argument
- *bc++ = ReadEncodedUInt();
- // Read the 3rd argument
- *bc++ = ReadEncodedUInt();
- }
- break;
- default:
- {
- // This should never happen
- asASSERT(false);
- // Read the next 3 bytes
- asDWORD c; asBYTE t;
- #if defined(AS_BIG_ENDIAN)
- c = b << 24;
- ReadData(&t, 1); c += t << 16;
- ReadData(&t, 1); c += t << 8;
- ReadData(&t, 1); c += t;
- #else
- c = b;
- ReadData(&t, 1); c += t << 8;
- ReadData(&t, 1); c += t << 16;
- ReadData(&t, 1); c += t << 24;
- #endif
- *bc++ = c;
- c = *(asBYTE*)&c;
- // Read the bc as is
- for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ )
- ReadData(&*bc++, 4);
- }
- }
- numInstructions--;
- }
- // Correct the final size in case we over-estimated it
- func->scriptData->byteCode.SetLengthNoConstruct(pos);
- }
- void asCReader::ReadUsedTypeIds()
- {
- TimeIt("asCReader::ReadUsedTypeIds");
- asUINT count = SanityCheck(ReadEncodedUInt(), 1000000);
- usedTypeIds.Allocate(count, false);
- for( asUINT n = 0; n < count; n++ )
- {
- asCDataType dt;
- ReadDataType(&dt);
- usedTypeIds.PushLast(engine->GetTypeIdFromDataType(dt));
- }
- }
- void asCReader::ReadUsedGlobalProps()
- {
- TimeIt("asCReader::ReadUsedGlobalProps");
- int c = SanityCheck(ReadEncodedUInt(), 1000000);
- usedGlobalProperties.Allocate(c, false);
- for( int n = 0; n < c; n++ )
- {
- asCString name, ns;
- asCDataType type;
- char moduleProp;
- ReadString(&name);
- ReadString(&ns);
- ReadDataType(&type);
- ReadData(&moduleProp, 1);
- asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
- // Find the real property
- asCGlobalProperty *globProp = 0;
- if( moduleProp )
- globProp = module->m_scriptGlobals.GetFirst(nameSpace, name);
- else
- globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name);
- void *prop = 0;
- if( globProp && globProp->type == type )
- prop = globProp->GetAddressOfValue();
- usedGlobalProperties.PushLast(prop);
- if( prop == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- void asCReader::ReadUsedObjectProps()
- {
- TimeIt("asCReader::ReadUsedObjectProps");
- asUINT c = SanityCheck(ReadEncodedUInt(), 1000000);
- usedObjectProperties.SetLength(c);
- for( asUINT n = 0; n < c; n++ )
- {
- asCObjectType *objType = CastToObjectType(ReadTypeInfo());
- if( objType == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- asCString name;
- ReadString(&name);
- // Find the property
- bool found = false;
- for( asUINT p = 0; p < objType->properties.GetLength(); p++ )
- {
- if( objType->properties[p]->name == name )
- {
- usedObjectProperties[n].objType = objType;
- usedObjectProperties[n].prop = objType->properties[p];
- found = true;
- break;
- }
- }
- if( !found )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- short asCReader::FindObjectPropOffset(asWORD index)
- {
- static asCObjectProperty *lastCompositeProp = 0;
- if (lastCompositeProp)
- {
- if (index != 0)
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- short offset = (short)lastCompositeProp->byteOffset;
- lastCompositeProp = 0;
- return offset;
- }
- if( index >= usedObjectProperties.GetLength() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect)
- {
- lastCompositeProp = usedObjectProperties[index].prop;
- return (short)lastCompositeProp->compositeOffset;
- }
- return (short)usedObjectProperties[index].prop->byteOffset;
- }
- asCScriptFunction *asCReader::FindFunction(int idx)
- {
- if( idx >= 0 && idx < (int)usedFunctions.GetLength() )
- return usedFunctions[idx];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- void asCReader::TranslateFunction(asCScriptFunction *func)
- {
- // Skip this if the function is part of an pre-existing shared object
- if( dontTranslate.MoveTo(0, func) ) return;
- asASSERT( func->scriptData );
- // Pre-compute the size of each instruction in order to translate jump offsets
- asUINT n;
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
- asCArray<asUINT> bcSizes(bcLength);
- asCArray<asUINT> instructionNbrToPos(bcLength);
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- asUINT size = asBCTypeSize[asBCInfo[c].type];
- if( size == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- bcSizes.PushLast(size);
- instructionNbrToPos.PushLast(n);
- n += size;
- }
- asUINT bcNum = 0;
- for( n = 0; n < bcLength; bcNum++ )
- {
- int c = *(asBYTE*)&bc[n];
- if( c == asBC_REFCPY ||
- c == asBC_RefCpyV ||
- c == asBC_OBJTYPE )
- {
- // Translate the index to the true object type
- asPWORD *ot = (asPWORD*)&bc[n+1];
- *(asCObjectType**)ot = CastToObjectType(FindType(int(*ot)));
- }
- else if( c == asBC_TYPEID ||
- c == asBC_Cast )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- }
- else if( c == asBC_ADDSi ||
- c == asBC_LoadThisR )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- // Translate the prop index into the property offset
- *(((short*)&bc[n])+1) = FindObjectPropOffset(*(((short*)&bc[n])+1));
- }
- else if( c == asBC_LoadRObjR ||
- c == asBC_LoadVObjR )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+2];
- *tid = FindTypeId(*tid);
- asCObjectType *ot = engine->GetObjectTypeFromTypeId(*tid);
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- // List patterns have a different way of adjusting the offsets
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- *(((short*)&bc[n])+2) = (short)listAdj->AdjustOffset(*(((short*)&bc[n])+2));
- }
- else
- {
- // Translate the prop index into the property offset
- *(((short*)&bc[n])+2) = FindObjectPropOffset(*(((short*)&bc[n])+2));
- }
- }
- else if( c == asBC_COPY )
- {
- // Translate the index to the type id
- int *tid = (int*)&bc[n+1];
- *tid = FindTypeId(*tid);
- // COPY is used to copy POD types that don't have the opAssign method. It is
- // also used to copy references to scoped types during variable initializations.
- // Update the number of dwords to copy as it may be different on the target platform
- if( (*tid) & asTYPEID_OBJHANDLE )
- {
- // It is the actual reference that is being copied, not the object itself
- asBC_SWORDARG0(&bc[n]) = AS_PTR_SIZE;
- }
- else
- {
- asCDataType dt = engine->GetDataTypeFromTypeId(*tid);
- if( !dt.IsValid() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- else
- asBC_SWORDARG0(&bc[n]) = (short)dt.GetSizeInMemoryDWords();
- }
- }
- else if( c == asBC_RET )
- {
- // Determine the correct amount of DWORDs to pop
- asWORD dw = (asWORD)func->GetSpaceNeededForArguments();
- if( func->DoesReturnOnStack() ) dw += AS_PTR_SIZE;
- if( func->objectType ) dw += AS_PTR_SIZE;
- asBC_WORDARG0(&bc[n]) = dw;
- }
- else if( c == asBC_CALL ||
- c == asBC_CALLINTF ||
- c == asBC_CALLSYS ||
- c == asBC_Thiscall1 )
- {
- // Translate the index to the func id
- int *fid = (int*)&bc[n+1];
- asCScriptFunction *f = FindFunction(*fid);
- if( f )
- *fid = f->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else if( c == asBC_FuncPtr )
- {
- // Translate the index to the func pointer
- asPWORD *fid = (asPWORD*)&bc[n+1];
- *fid = (asPWORD)FindFunction(int(*fid));
- }
- else if( c == asBC_ALLOC )
- {
- // Translate the index to the true object type
- asPWORD *arg = (asPWORD*)&bc[n+1];
- *(asCObjectType**)arg = CastToObjectType(FindType(int(*arg)));
- // The constructor function id must be translated, unless it is zero
- int *fid = (int*)&bc[n+1+AS_PTR_SIZE];
- if( *fid != 0 )
- {
- // Subtract 1 from the id, as it was incremented during the writing
- asCScriptFunction *f = FindFunction(*fid-1);
- if( f )
- *fid = f->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- else if( c == asBC_STR )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- else if( c == asBC_CALLBND )
- {
- // Translate the function id
- asUINT *fid = (asUINT*)&bc[n+1];
- if( *fid < module->m_bindInformations.GetLength() )
- {
- sBindInfo *bi = module->m_bindInformations[*fid];
- if( bi )
- *fid = bi->importedFunctionSignature->id;
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else if( c == asBC_PGA ||
- c == asBC_PshGPtr ||
- c == asBC_LDG ||
- c == asBC_PshG4 ||
- c == asBC_LdGRdR4 ||
- c == asBC_CpyGtoV4 ||
- c == asBC_CpyVtoG4 ||
- c == asBC_SetG4 )
- {
- // Translate the index to pointer
- asPWORD *index = (asPWORD*)&bc[n + 1];
- if ((*index & 1))
- {
- if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength())
- *(void**)index = usedGlobalProperties[asUINT(*index)>>1];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else
- {
- // Only PGA and PshGPtr can hold string constants
- asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
- if ((asUINT(*index)>>1) < usedStringConstants.GetLength())
- *(void**)index = usedStringConstants[asUINT(*index)>>1];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- else if( c == asBC_JMP ||
- c == asBC_JZ ||
- c == asBC_JNZ ||
- c == asBC_JLowZ ||
- c == asBC_JLowNZ ||
- c == asBC_JS ||
- c == asBC_JNS ||
- c == asBC_JP ||
- c == asBC_JNP ) // The JMPP instruction doesn't need modification
- {
- // Get the offset
- int offset = int(bc[n+1]);
- // Count the instruction sizes to the destination instruction
- int size = 0;
- if( offset >= 0 )
- // If moving ahead, then start from next instruction
- for( asUINT num = bcNum+1; offset-- > 0; num++ )
- size += bcSizes[num];
- else
- // If moving backwards, then start at current instruction
- for( asUINT num = bcNum; offset++ < 0; num-- )
- size -= bcSizes[num];
- // The size is dword offset
- bc[n+1] = size;
- }
- else if( c == asBC_AllocMem )
- {
- // The size of the allocated memory is only known after all the elements has been seen.
- // This helper class will collect this information and adjust the size when the
- // corresponding asBC_FREE is encountered
- // The adjuster also needs to know the list type so it can know the type of the elements
- asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n])));
- listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot));
- }
- else if( c == asBC_FREE )
- {
- // Translate the index to the true object type
- asPWORD *pot = (asPWORD*)&bc[n+1];
- *(asCObjectType**)pot = CastToObjectType(FindType(int(*pot)));
- asCObjectType *ot = *(asCObjectType**)pot;
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- if( listAdjusters.GetLength() == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- // Finalize the adjustment of the list buffer that was initiated with asBC_AllocMem
- SListAdjuster *list = listAdjusters.PopLast();
- list->AdjustAllocMem();
- asDELETE(list, SListAdjuster);
- }
- }
- else if( c == asBC_SetListSize )
- {
- // Adjust the offset in the list where the size is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- // Inform the list adjuster how many values will be repeated
- listAdj->SetRepeatCount(bc[n+2]);
- }
- else if( c == asBC_PshListElmnt )
- {
- // Adjust the offset in the list where the size is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- }
- else if( c == asBC_SetListType )
- {
- // Adjust the offset in the list where the typeid is informed
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- bc[n+1] = listAdj->AdjustOffset(bc[n+1]);
- // Translate the type id
- bc[n+2] = FindTypeId(bc[n+2]);
- // Inform the list adjuster the type id of the next element
- listAdj->SetNextType(bc[n+2]);
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- // Calculate the stack adjustments
- CalculateAdjustmentByPos(func);
- // Adjust all variable positions in the bytecode
- bc = func->scriptData->byteCode.AddressOf();
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_wW_W_ARG:
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- case asBCTYPE_rW_DW_DW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_rW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
- asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n]));
- asBC_SWORDARG2(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG2(&bc[n]));
- }
- break;
- default:
- // The other types don't treat variables so won't be modified
- break;
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- // Adjust the space needed for local variables
- func->scriptData->variableSpace = AdjustStackPosition(func->scriptData->variableSpace);
- // Adjust the variable information. This will be used during the adjustment below
- for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
- {
- func->scriptData->variables[n]->declaredAtProgramPos = instructionNbrToPos[func->scriptData->variables[n]->declaredAtProgramPos];
- func->scriptData->variables[n]->stackOffset = AdjustStackPosition(func->scriptData->variables[n]->stackOffset);
- }
- // Adjust the get offsets. This must be done in the second iteration because
- // it relies on the function ids and variable position already being correct in the
- // bytecodes that come after the GET instructions.
- // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions
- // on a stack, and then when a call instruction is found update all of them.
- // This will also make the AdjustGetOffset() function quicker as it can
- // receive the called function directly instead of having to search for it.
- bc = func->scriptData->byteCode.AddressOf();
- for( n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- if( c == asBC_GETREF ||
- c == asBC_GETOBJ ||
- c == asBC_GETOBJREF ||
- c == asBC_ChkNullS )
- {
- asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n);
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- for( n = 0; n < func->scriptData->objVariableInfo.GetLength(); n++ )
- {
- // The program position must be adjusted as it is stored in number of instructions
- func->scriptData->objVariableInfo[n].programPos = instructionNbrToPos[func->scriptData->objVariableInfo[n].programPos];
- func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset);
- }
- for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++)
- {
- func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos];
- func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos];
- }
- // The program position (every even number) needs to be adjusted
- // for the line numbers to be in number of dwords instead of number of instructions
- for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 )
- func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]];
- for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 )
- func->scriptData->sectionIdxs[n] = instructionNbrToPos[func->scriptData->sectionIdxs[n]];
- CalculateStackNeeded(func);
- }
- asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) :
- reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
- {
- asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) );
- // Find the first expected value in the list
- asSListPatternNode *node = patternType->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
- asASSERT( node && node->type == asLPT_START );
- patternNode = node->next;
- }
- int asCReader::SListAdjuster::AdjustOffset(int offset)
- {
- if( offset < lastOffset )
- {
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- // If it is the same offset being accessed again, just return the same adjusted value
- if( lastOffset == offset )
- return lastAdjustedOffset;
- lastOffset = offset;
- lastAdjustedOffset = maxOffset;
- // What is being expected at this position?
- if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
- {
- // Align the offset to 4 bytes boundary
- if( maxOffset & 0x3 )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
- maxOffset += 4;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- else if( patternNode->type == asLPT_TYPE )
- {
- const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
- if( dt.GetTokenType() == ttQuestion )
- {
- if( nextTypeId != -1 )
- {
- if( repeatCount > 0 )
- repeatCount--;
- asCDataType nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId);
- asUINT size;
- if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = nextdt.GetSizeInMemoryBytes();
- // Align the offset to 4 bytes boundary
- if( size >= 4 && (maxOffset & 0x3) )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextTypeId = -1;
- maxOffset += size;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- else
- {
- // Align the offset to 4 bytes boundary
- if( maxOffset & 0x3 )
- {
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- }
- // The first adjustment is for the typeId
- maxOffset += 4;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- }
- else
- {
- // Determine the size of the element
- asUINT size;
- if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = dt.GetSizeInMemoryBytes();
- // If values are skipped, the offset needs to be incremented
- while( nextOffset <= offset )
- {
- if( repeatCount > 0 )
- repeatCount--;
- // Align the offset to 4 bytes boundary
- if( size >= 4 && (maxOffset & 0x3) )
- maxOffset += 4 - (maxOffset & 0x3);
- lastAdjustedOffset = maxOffset;
- nextOffset += 1;
- maxOffset += size;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextOffset = offset+1;
- return lastAdjustedOffset;
- }
- }
- else if( patternNode->type == asLPT_START )
- {
- if( repeatCount > 0 )
- repeatCount--;
- SInfo info = {repeatCount, patternNode};
- stack.PushLast(info);
- repeatCount = 0;
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset);
- }
- else if( patternNode->type == asLPT_END )
- {
- if( stack.GetLength() == 0 )
- {
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- SInfo info = stack.PopLast();
- repeatCount = info.repeatCount;
- if( repeatCount )
- patternNode = info.startNode;
- else
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset);
- }
- else
- {
- // Something is wrong with the pattern list declaration
- reader->Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- UNREACHABLE_RETURN;
- }
- void asCReader::SListAdjuster::SetRepeatCount(asUINT rc)
- {
- // Make sure the list is expecting a repeat at this location
- asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
- // Now move to the next patternNode
- patternNode = patternNode->next;
- repeatCount = rc;
- }
- void asCReader::SListAdjuster::AdjustAllocMem()
- {
- allocMemBC[1] = maxOffset;
- }
- void asCReader::SListAdjuster::SetNextType(int typeId)
- {
- asASSERT( nextTypeId == -1 );
- nextTypeId = typeId;
- }
- void asCReader::CalculateStackNeeded(asCScriptFunction *func)
- {
- asASSERT( func->scriptData );
- int largestStackUsed = 0;
- // Clear the known stack size for each bytecode
- asCArray<int> stackSize;
- stackSize.SetLength(func->scriptData->byteCode.GetLength());
- memset(&stackSize[0], -1, stackSize.GetLength()*4);
- // Add the first instruction to the list of unchecked code
- // paths and set the stack size at that instruction to variableSpace
- asCArray<asUINT> paths;
- paths.PushLast(0);
- stackSize[0] = func->scriptData->variableSpace;
- // Go through each of the code paths
- for( asUINT p = 0; p < paths.GetLength(); ++p )
- {
- asUINT pos = paths[p];
- int currStackSize = stackSize[pos];
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos];
- if( bc == asBC_RET )
- continue;
- // Determine the change in stack size for this instruction
- int stackInc = asBCInfo[bc].stackInc;
- if( stackInc == 0xFFFF )
- {
- // Determine the true delta from the instruction arguments
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLBND ||
- bc == asBC_ALLOC ||
- bc == asBC_CALLINTF ||
- bc == asBC_CallPtr )
- {
- asCScriptFunction *called = func->GetCalledFunction(pos);
- if( called )
- {
- stackInc = -called->GetSpaceNeededForArguments();
- if( called->objectType )
- stackInc -= AS_PTR_SIZE;
- if( called->DoesReturnOnStack() )
- stackInc -= AS_PTR_SIZE;
- }
- else
- {
- // It is an allocation for an object without a constructor
- asASSERT( bc == asBC_ALLOC );
- stackInc = -AS_PTR_SIZE;
- }
- }
- }
- currStackSize += stackInc;
- asASSERT( currStackSize >= 0 );
- if( currStackSize > largestStackUsed )
- largestStackUsed = currStackSize;
- if( bc == asBC_JMP )
- {
- // Find the label that we should jump to
- int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
- pos += 2 + offset;
- // Add the destination as a new path
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- else if( bc == asBC_JZ || bc == asBC_JNZ ||
- bc == asBC_JLowZ || bc == asBC_JLowNZ ||
- bc == asBC_JS || bc == asBC_JNS ||
- bc == asBC_JP || bc == asBC_JNP )
- {
- // Find the label that is being jumped to
- int offset = asBC_INTARG(&func->scriptData->byteCode[pos]);
- // Add both paths to the code paths
- pos += 2;
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- pos += offset;
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- else if( bc == asBC_JMPP )
- {
- pos++;
- // Add all subsequent JMP instructions to the path
- while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP )
- {
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- pos += 2;
- }
- continue;
- }
- else
- {
- // Add next instruction to the paths
- pos += asBCTypeSize[asBCInfo[bc].type];
- if( stackSize[pos] == -1 )
- {
- stackSize[pos] = currStackSize;
- paths.PushLast(pos);
- }
- else
- asASSERT(stackSize[pos] == currStackSize);
- continue;
- }
- }
- func->scriptData->stackNeeded = largestStackUsed;
- }
- void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func)
- {
- // Adjust the offset of all negative variables (parameters) as
- // all pointers have been stored as having a size of 1 dword
- asUINT n;
- asCArray<int> adjustments;
- asUINT offset = 0;
- if( func->objectType )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- if( func->DoesReturnOnStack() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- for( n = 0; n < func->parameterTypes.GetLength(); n++ )
- {
- if( !func->parameterTypes[n].IsPrimitive() ||
- func->parameterTypes[n].IsReference() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += 1;
- }
- else
- {
- asASSERT( func->parameterTypes[n].IsPrimitive() );
- offset += func->parameterTypes[n].GetSizeOnStackDWords();
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustNegativeStackByPos.SetLength(offset);
- memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
- adjustNegativeStackByPos[i] += adjust;
- }
- // The bytecode has been stored as if all object variables take up only 1 dword.
- // It is necessary to adjust to the size according to the current platform.
- adjustments.SetLength(0);
- int highestPos = 0;
- for (n = 0; n < func->scriptData->variables.GetLength(); n++)
- {
- // Skip function parameters as these are adjusted by adjustNegativeStackByPos
- if (func->scriptData->variables[n]->stackOffset <= 0)
- continue;
- asCDataType t = func->scriptData->variables[n]->type;
- if (!t.IsObject() && !t.IsObjectHandle())
- continue;
- // Determing the size of the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- if (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !func->scriptData->variables[n]->onHeap)
- size = t.GetSizeInMemoryDWords();
- // Check if type has a different size than stored
- if (size > 1)
- {
- if (func->scriptData->variables[n]->stackOffset > highestPos)
- highestPos = func->scriptData->variables[n]->stackOffset;
- adjustments.PushLast(func->scriptData->variables[n]->stackOffset);
- adjustments.PushLast(size - 1);
- }
- }
- // Count position 0 too
- adjustByPos.SetLength(highestPos+1);
- memset(adjustByPos.AddressOf(), 0, adjustByPos.GetLength()*sizeof(int));
- // Build look-up table with the adjustments for each stack position
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos; i < adjustByPos.GetLength(); i++ )
- adjustByPos[i] += adjust;
- }
- }
- int asCReader::AdjustStackPosition(int pos)
- {
- if( pos >= (int)adjustByPos.GetLength() )
- {
- // It can be higher for primitives allocated on top of highest object variable
- if( adjustByPos.GetLength() )
- pos += (short)adjustByPos[adjustByPos.GetLength()-1];
- }
- else if( pos >= 0 )
- pos += (short)adjustByPos[pos];
- else if( -pos >= (int)adjustNegativeStackByPos.GetLength() )
- Error(TXT_INVALID_BYTECODE_d);
- else
- pos += (short)adjustNegativeStackByPos[-pos];
- return pos;
- }
- int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
- {
- // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
- // the function can remember where it found the function and check if the programPos is still valid
- // Get offset 0 doesn't need adjustment
- if( offset == 0 ) return 0;
- bool bcAlloc = false;
- // Find out which function that will be called
- // TODO: Can the asCScriptFunction::FindNextFunctionCalled be adapted so it can be reused here (support for asBC_ALLOC, asBC_REFCPY and asBC_COPY)?
- asCScriptFunction *calledFunc = 0;
- int stackDelta = 0;
- for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); )
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLINTF ||
- bc == asBC_ALLOC ||
- bc == asBC_CALLBND ||
- bc == asBC_CallPtr )
- {
- // The alloc instruction allocates the object memory
- // so it doesn't take the this pointer as input
- if (bc == asBC_ALLOC)
- bcAlloc = true;
- calledFunc = func->GetCalledFunction(n);
- break;
- }
- else if( bc == asBC_REFCPY ||
- bc == asBC_COPY )
- {
- // In this case we know there is only 1 pointer on the stack above
- asASSERT( offset == 1 );
- return offset - (1 - AS_PTR_SIZE);
- }
- // Keep track of the stack size between the
- // instruction that needs to be adjusted and the call
- stackDelta += asBCInfo[bc].stackInc;
- n += asBCTypeSize[asBCInfo[bc].type];
- }
- if( calledFunc == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return offset;
- }
- // Count the number of pointers pushed on the stack above the
- // current offset, and then adjust the offset accordingly
- asUINT numPtrs = 0;
- int currOffset = -stackDelta;
- if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- }
- for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
- {
- if( offset <= currOffset ) break;
- if( !calledFunc->parameterTypes[p].IsPrimitive() ||
- calledFunc->parameterTypes[p].IsReference() )
- {
- currOffset++;
- if( currOffset > 0 )
- numPtrs++;
- #if AS_PTR_SIZE == 2
- // For 64bit platforms it is necessary to increment the currOffset by one more
- // DWORD since the stackDelta was counting the full 64bit size of the pointer
- else if( stackDelta )
- currOffset++;
- #endif
- // The variable arg ? has an additiona 32bit integer with the typeid
- if( calledFunc->parameterTypes[p].IsAnyType() )
- currOffset += 1;
- }
- else
- {
- // Enums or built-in primitives are passed by value
- asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
- currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
- }
- }
- return offset - numPtrs * (1 - AS_PTR_SIZE);
- }
- int asCReader::FindTypeId(int idx)
- {
- if( idx >= 0 && idx < (int)usedTypeIds.GetLength() )
- return usedTypeIds[idx];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- }
- asCTypeInfo *asCReader::FindType(int idx)
- {
- if( idx < 0 || idx >= (int)usedTypes.GetLength() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- return usedTypes[idx];
- }
- #ifndef AS_NO_COMPILER
- asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug)
- : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0)
- {
- }
- int asCWriter::Error(const char *msg)
- {
- // Don't write if it has already been reported an error earlier
- if (!error)
- {
- asCString str;
- str.Format(msg, bytesWritten);
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- error = true;
- }
- return asERROR;
- }
- int asCWriter::WriteData(const void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- int ret = 0;
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; ret >= 0 && n < size; n++ )
- ret = stream->Write(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; ret >= 0 && n >= 0; n-- )
- ret = stream->Write(((asBYTE*)data)+n, 1);
- #endif
- if (ret < 0)
- Error(TXT_UNEXPECTED_END_OF_FILE);
- bytesWritten += size;
- return ret;
- }
- int asCWriter::Write()
- {
- TimeIt("asCWriter::Write");
- unsigned long i, count;
- // Store everything in the same order that the builder parses scripts
- // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway
- // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway
- // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway
- // Write the flag as 1byte even on platforms with 4byte booleans
- WriteEncodedInt64(stripDebugInfo ? 1 : 0);
- // Store enums
- {
- TimeIt("store enums");
- count = (asUINT)module->m_enumTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteTypeDeclaration(module->m_enumTypes[i], 1);
- WriteTypeDeclaration(module->m_enumTypes[i], 2);
- }
- }
- // Store type declarations first
- {
- TimeIt("type declarations");
- count = (asUINT)module->m_classTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- // Store only the name of the class/interface types
- WriteTypeDeclaration(module->m_classTypes[i], 1);
- }
- }
- // Store func defs
- {
- TimeIt("func defs");
- count = (asUINT)module->m_funcDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- WriteFunction(module->m_funcDefs[i]->funcdef);
- }
- // Now store all interface methods
- {
- TimeIt("interface methods");
- count = (asUINT)module->m_classTypes.GetLength();
- for( i = 0; i < count; i++ )
- {
- if( module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 2);
- }
- }
- // Then store the class methods and behaviours
- {
- TimeIt("class methods and behaviours");
- for( i = 0; i < count; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 2);
- }
- }
- // Then store the class properties
- {
- TimeIt("class properties");
- for( i = 0; i < count; ++i )
- {
- if( !module->m_classTypes[i]->IsInterface() )
- WriteTypeDeclaration(module->m_classTypes[i], 3);
- }
- }
- // Store typedefs
- {
- TimeIt("type defs");
- count = (asUINT)module->m_typeDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteTypeDeclaration(module->m_typeDefs[i], 1);
- WriteTypeDeclaration(module->m_typeDefs[i], 2);
- }
- }
- // scriptGlobals[]
- {
- TimeIt("script globals");
- count = (asUINT)module->m_scriptGlobals.GetSize();
- WriteEncodedInt64(count);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->m_scriptGlobals.List();
- for( ; it; it++ )
- WriteGlobalProperty(*it);
- }
- // scriptFunctions[]
- {
- TimeIt("scriptFunctions");
- count = 0;
- for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ )
- if( module->m_scriptFunctions[i]->objectType == 0 )
- count++;
- WriteEncodedInt64(count);
- for( i = 0; i < module->m_scriptFunctions.GetLength(); ++i )
- if( module->m_scriptFunctions[i]->objectType == 0 )
- WriteFunction(module->m_scriptFunctions[i]);
- }
- // globalFunctions[]
- {
- TimeIt("globalFunctions");
- count = (int)module->m_globalFunctions.GetSize();
- asCSymbolTable<asCScriptFunction>::iterator funcIt = module->m_globalFunctions.List();
- WriteEncodedInt64(count);
- while( funcIt )
- {
- WriteFunction(*funcIt);
- funcIt++;
- }
- }
- // bindInformations[]
- {
- TimeIt("bindInformations");
- count = (asUINT)module->m_bindInformations.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- {
- WriteFunction(module->m_bindInformations[i]->importedFunctionSignature);
- WriteString(&module->m_bindInformations[i]->importFromModule);
- }
- }
- // usedTypes[]
- {
- TimeIt("usedTypes");
- count = (asUINT)usedTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- WriteTypeInfo(usedTypes[i]);
- }
- // usedTypeIds[]
- WriteUsedTypeIds();
- // usedFunctions[]
- WriteUsedFunctions();
- // usedGlobalProperties[]
- WriteUsedGlobalProps();
- // usedStringConstants[]
- WriteUsedStringConstants();
- // usedObjectProperties[]
- WriteUsedObjectProps();
- return error ? asERROR : asSUCCESS;
- }
- int asCWriter::FindStringConstantIndex(void *str)
- {
- asSMapNode<void*, int> *cursor = 0;
- if (stringToIndexMap.MoveTo(&cursor, str))
- return cursor->value;
- usedStringConstants.PushLast(str);
- int index = int(usedStringConstants.GetLength() - 1);
- stringToIndexMap.Insert(str, index);
- return index;
- }
- void asCWriter::WriteUsedStringConstants()
- {
- TimeIt("asCWriter::WriteUsedStringConstants");
- asUINT count = (asUINT)usedStringConstants.GetLength();
- WriteEncodedInt64(count);
- asCString str;
- for (asUINT i = 0; i < count; ++i)
- {
- asUINT length;
- engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length);
- str.SetLength(length);
- engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length);
- WriteString(&str);
- }
- }
- void asCWriter::WriteUsedFunctions()
- {
- TimeIt("asCWriter::WriteUsedFunctions");
- asUINT count = (asUINT)usedFunctions.GetLength();
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- char c;
- // Write enough data to be able to uniquely identify the function upon load
- asCScriptFunction *func = usedFunctions[n];
- if(func)
- {
- // Is the function from the module or the application?
- c = func->module ? 'm' : 'a';
- // Functions and methods that are shared should be stored as 's' as the bytecode
- // may be imported from other modules (even if the current module have received ownership)
- if (c == 'm' && func->IsShared() )
- c = 's';
- WriteData(&c, 1);
- WriteFunctionSignature(func);
- }
- else
- {
- // null function pointer
- c = 'n';
- WriteData(&c, 1);
- }
- }
- }
- void asCWriter::WriteFunctionSignature(asCScriptFunction *func)
- {
- asUINT i, count;
- WriteString(&func->name);
- if( func->name == DELEGATE_FACTORY )
- {
- // It's not necessary to write anything else
- return;
- }
- WriteDataType(&func->returnType);
- count = (asUINT)func->parameterTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- WriteDataType(&func->parameterTypes[i]);
- // Only write the inout flags if any of them are set
- // If the number of parameters is 0, then no need to save this
- if (func->parameterTypes.GetLength() > 0)
- {
- count = 0;
- for (i = asUINT(func->inOutFlags.GetLength()); i > 0; i--)
- if (func->inOutFlags[i - 1] != asTM_NONE)
- {
- count = i;
- break;
- }
- WriteEncodedInt64(count);
- for (i = 0; i < count; ++i)
- WriteEncodedInt64(func->inOutFlags[i]);
- }
- WriteEncodedInt64(func->funcType);
- // Write the default args, from last to first
- // If the number of parameters is 0, then no need to save this
- if (func->parameterTypes.GetLength() > 0)
- {
- count = 0;
- for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
- if (func->defaultArgs[i])
- count++;
- WriteEncodedInt64(count);
- for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; )
- if (func->defaultArgs[i])
- WriteString(func->defaultArgs[i]);
- }
- WriteTypeInfo(func->objectType);
- if( func->objectType )
- {
- asBYTE b = 0;
- b += func->IsReadOnly() ? 1 : 0;
- b += func->IsPrivate() ? 2 : 0;
- b += func->IsProtected() ? 4 : 0;
- WriteData(&b, 1);
- }
- else
- {
- if (func->funcType == asFUNC_FUNCDEF)
- {
- if (func->nameSpace)
- {
- // This funcdef was declared as global entity
- asBYTE b = 'n';
- WriteData(&b, 1);
- WriteString(&func->nameSpace->name);
- }
- else
- {
- // This funcdef was declared as class member
- asBYTE b = 'o';
- WriteData(&b, 1);
- WriteTypeInfo(func->funcdefType->parentClass);
- }
- }
- else
- WriteString(&func->nameSpace->name);
- }
- }
- void asCWriter::WriteFunction(asCScriptFunction* func)
- {
- char c;
- // If there is no function, then store a null char
- if( func == 0 )
- {
- c = '\0';
- WriteData(&c, 1);
- return;
- }
- // First check if the function has been saved already
- for( asUINT f = 0; f < savedFunctions.GetLength(); f++ )
- {
- if( savedFunctions[f] == func )
- {
- c = 'r';
- WriteData(&c, 1);
- WriteEncodedInt64(f);
- return;
- }
- }
- // Keep a reference to the function in the list
- savedFunctions.PushLast(func);
- c = 'f';
- WriteData(&c, 1);
- asUINT i, count;
- WriteFunctionSignature(func);
- if( func->funcType == asFUNC_SCRIPT )
- {
- // Skip this for external shared entities
- if (module->m_externalTypes.IndexOf(func->objectType) >= 0)
- return;
- char bits = 0;
- bits += func->IsShared() ? 1 : 0;
- bits += func->dontCleanUpOnException ? 2 : 0;
- if (module->m_externalFunctions.IndexOf(func) >= 0)
- bits += 4;
- if (func->scriptData->objVariableInfo.GetLength())
- bits += 8;
- if (func->scriptData->tryCatchInfo.GetLength())
- bits += 16;
- bits += func->IsExplicit() ? 32 : 0;
- WriteData(&bits, 1);
- // For external shared functions the rest is not needed
- if (bits & 4)
- return;
- // Calculate the adjustment by position lookup table
- CalculateAdjustmentByPos(func);
- WriteByteCode(func);
- asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace);
- WriteEncodedInt64(varSpace);
- if (bits & 8)
- {
- WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength());
- for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i)
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]);
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset));
- WriteEncodedInt64(func->scriptData->objVariableInfo[i].option);
- }
- }
- if (bits & 16)
- {
- // Write info on try/catch blocks
- WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength());
- for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i)
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]);
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]);
- }
- }
- // The program position (every even number) needs to be adjusted
- // to be in number of instructions instead of DWORD offset
- if( !stripDebugInfo )
- {
- asUINT length = (asUINT)func->scriptData->lineNumbers.GetLength();
- WriteEncodedInt64(length);
- for( i = 0; i < length; ++i )
- {
- if( (i & 1) == 0 )
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->lineNumbers[i]]);
- else
- WriteEncodedInt64(func->scriptData->lineNumbers[i]);
- }
- // Write the array of script sections
- length = (asUINT)func->scriptData->sectionIdxs.GetLength();
- WriteEncodedInt64(length);
- for( i = 0; i < length; ++i )
- {
- if( (i & 1) == 0 )
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->sectionIdxs[i]]);
- else
- {
- if( func->scriptData->sectionIdxs[i] >= 0 )
- WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]);
- else
- {
- c = 0;
- WriteData(&c, 1);
- }
- }
- }
- }
- // Write the variable information
- // Even without the debug info the type and position of the variables
- // must be stored, as this is used for serializing contexts
- // TODO: Store the type info/position in an intelligent way to avoid duplicating info in objVariablePos & objVariableTypes.
- // TODO: Perhaps objVariablePos & objVariableTypes should be retired now that all variable types must be stored anyway
- WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength());
- for( i = 0; i < func->scriptData->variables.GetLength(); i++ )
- {
- if (!stripDebugInfo)
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]);
- WriteString(&func->scriptData->variables[i]->name);
- }
- // The stack position must be adjusted according to the pointer sizes
- asUINT data = AdjustStackPosition(func->scriptData->variables[i]->stackOffset) << 1;
- // Encode the onHeap flag in the stackOffset to avoid 1 byte increase
- data |= func->scriptData->variables[i]->onHeap & 1;
- WriteEncodedInt64(data);
- WriteDataType(&func->scriptData->variables[i]->type);
- }
- // Store script section name
- if( !stripDebugInfo )
- {
- if( func->scriptData->scriptSectionIdx >= 0 )
- WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]);
- else
- {
- c = 0;
- WriteData(&c, 1);
- }
- WriteEncodedInt64(func->scriptData->declaredAt);
- }
- // Store the parameter names
- if( !stripDebugInfo )
- {
- count = asUINT(func->parameterNames.GetLength());
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < count; n++ )
- WriteString(&func->parameterNames[n]);
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- // TODO: Do we really need to store this? It can probably be reconstructed by the reader
- WriteEncodedInt64(func->vfTableIdx);
- }
- else if( func->funcType == asFUNC_FUNCDEF )
- {
- char bits = 0;
- bits += func->IsShared() ? 1 : 0;
- if (module->m_externalTypes.IndexOf(func->funcdefType) >= 0)
- bits += 2;
- WriteData(&bits,1);
- }
- }
- void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase)
- {
- if( phase == 1 )
- {
- // name
- WriteString(&type->name);
- // flags
- WriteData(&type->flags, 4);
- // size
- // TODO: Do we really need to store this? The reader should be able to
- // determine the correct size from the object type's flags
- if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size > 0 )
- {
- // The size for script objects may vary from platform to platform so
- // only store 1 to diferentiate from interfaces that have size 0.
- WriteEncodedInt64(1);
- }
- else
- {
- // Enums, typedefs, and interfaces have fixed sizes independently
- // of platform so it is safe to serialize the size directly.
- WriteEncodedInt64(type->size);
- }
- // namespace
- WriteString(&type->nameSpace->name);
- // external shared flag
- if ((type->flags & asOBJ_SHARED))
- {
- char c = ' ';
- if (module->m_externalTypes.IndexOf(type) >= 0)
- c = 'e';
- WriteData(&c, 1);
- }
- }
- else if( phase == 2 )
- {
- // external shared types doesn't need to save this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- if(type->flags & asOBJ_ENUM )
- {
- // enumValues[]
- asCEnumType *t = CastToEnumType(type);
- int size = (int)t->enumValues.GetLength();
- WriteEncodedInt64(size);
- for( int n = 0; n < size; n++ )
- {
- WriteString(&t->enumValues[n]->name);
- WriteData(&t->enumValues[n]->value, 4);
- }
- }
- else if(type->flags & asOBJ_TYPEDEF )
- {
- asCTypedefType *td = CastToTypedefType(type);
- eTokenType t = td->aliasForType.GetTokenType();
- WriteEncodedInt64(t);
- }
- else
- {
- asCObjectType *t = CastToObjectType(type);
- WriteTypeInfo(t->derivedFrom);
- // interfaces[] / interfaceVFTOffsets[]
- // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those?
- int size = (asUINT)t->interfaces.GetLength();
- WriteEncodedInt64(size);
- asUINT n;
- asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() );
- for( n = 0; n < t->interfaces.GetLength(); n++ )
- {
- WriteTypeInfo(t->interfaces[n]);
- if( !t->IsInterface() )
- WriteEncodedInt64(t->interfaceVFTOffsets[n]);
- }
- // behaviours
- // TODO: Default behaviours should just be stored as a indicator
- // to avoid storing the actual function object
- if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM )
- {
- WriteFunction(engine->scriptFunctions[t->beh.destruct]);
- size = (int)t->beh.constructors.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < t->beh.constructors.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]);
- WriteFunction(engine->scriptFunctions[t->beh.factories[n]]);
- }
- }
- // methods[]
- // TODO: Avoid storing inherited methods in interfaces, as the reader
- // can add those directly from the base interface
- size = (int)t->methods.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < t->methods.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[t->methods[n]]);
- }
- // virtualFunctionTable[]
- // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader
- size = (int)t->virtualFunctionTable.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < (asUINT)size; n++ )
- {
- WriteFunction(t->virtualFunctionTable[n]);
- }
- }
- }
- else if( phase == 3 )
- {
- // external shared types doesn't need to save this
- if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0)
- return;
- // properties[]
- asCObjectType *t = CastToObjectType(type);
- // This is only done for object types
- asASSERT(t);
- asUINT size = (asUINT)t->properties.GetLength();
- WriteEncodedInt64(size);
- for (asUINT n = 0; n < t->properties.GetLength(); n++)
- {
- WriteObjectProperty(t->properties[n]);
- }
- }
- }
- void asCWriter::WriteEncodedInt64(asINT64 i)
- {
- asBYTE signBit = ( i & asINT64(1)<<63 ) ? 0x80 : 0;
- if( signBit ) i = -i;
- asBYTE b;
- if( i < (1<<6) )
- {
- b = (asBYTE)(signBit + i); WriteData(&b, 1);
- }
- else if( i < (1<<13) )
- {
- b = asBYTE(0x40 + signBit + (i >> 8)); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (1<<20) )
- {
- b = asBYTE(0x60 + signBit + (i >> 16)); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (1<<27) )
- {
- b = asBYTE(0x70 + signBit + (i >> 24)); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<34) )
- {
- b = asBYTE(0x78 + signBit + (i >> 32)); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<41) )
- {
- b = asBYTE(0x7C + signBit + (i >> 40)); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else if( i < (asINT64(1)<<48) )
- {
- b = asBYTE(0x7E + signBit + (i >> 48)); WriteData(&b, 1);
- b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- else
- {
- b = asBYTE(0x7F + signBit); WriteData(&b, 1);
- b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 48) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1);
- b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1);
- b = asBYTE(i & 0xFF); WriteData(&b, 1);
- }
- }
- void asCWriter::WriteString(asCString* str)
- {
- // First check if the string hasn't been saved already
- asSMapNode<asCString, int> *cursor = 0;
- if (stringToIdMap.MoveTo(&cursor, *str))
- {
- // Save a reference to the existing string
- // The lowest bit is set to 1 to indicate a reference
- WriteEncodedInt64(cursor->value*2+1);
- return;
- }
- // Save a new string
- // The lowest bit is set to 0 to indicate a new string
- asUINT len = (asUINT)str->GetLength();
- WriteEncodedInt64(len*2);
- if( len > 0 )
- {
- stream->Write(str->AddressOf(), (asUINT)len);
- bytesWritten += len;
- savedStrings.PushLast(*str);
- stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1);
- }
- }
- void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop)
- {
- // TODO: We might be able to avoid storing the name and type of the global
- // properties twice if we merge this with the WriteUsedGlobalProperties.
- WriteString(&prop->name);
- WriteString(&prop->nameSpace->name);
- WriteDataType(&prop->type);
- // Store the initialization function
- WriteFunction(prop->GetInitFunc());
- }
- void asCWriter::WriteObjectProperty(asCObjectProperty* prop)
- {
- WriteString(&prop->name);
- WriteDataType(&prop->type);
- int flags = 0;
- if( prop->isPrivate ) flags |= 1;
- if( prop->isProtected ) flags |= 2;
- if( prop->isInherited ) flags |= 4;
- WriteEncodedInt64(flags);
- }
- void asCWriter::WriteDataType(const asCDataType *dt)
- {
- // First check if the datatype has already been saved
- for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ )
- {
- if( *dt == savedDataTypes[n] )
- {
- WriteEncodedInt64(n+1);
- return;
- }
- }
- // Indicate a new type with a null byte
- asUINT c = 0;
- WriteEncodedInt64(c);
- // Save the new datatype
- savedDataTypes.PushLast(*dt);
- int t = dt->GetTokenType();
- WriteEncodedInt64(t);
- if( t == ttIdentifier )
- WriteTypeInfo(dt->GetTypeInfo());
- // Endianess safe bitmask
- char bits = 0;
- SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0);
- SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1);
- SAVE_TO_BIT(bits, dt->IsReference(), 2);
- SAVE_TO_BIT(bits, dt->IsReadOnly(), 3);
- WriteData(&bits, 1);
- }
- void asCWriter::WriteTypeInfo(asCTypeInfo* ti)
- {
- char ch;
- if( ti )
- {
- // Check for template instances/specializations
- asCObjectType *ot = CastToObjectType(ti);
- if( ot && ot->templateSubTypes.GetLength() )
- {
- // Check for list pattern type or template type
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- ch = 'l'; // list
- WriteData(&ch, 1);
- WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo());
- }
- else
- {
- ch = 'a'; // array
- WriteData(&ch, 1);
- WriteString(&ot->name);
- WriteString(&ot->nameSpace->name);
- WriteEncodedInt64(ot->templateSubTypes.GetLength());
- for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
- {
- if( !ot->templateSubTypes[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() )
- {
- ch = 's'; // sub type
- WriteData(&ch, 1);
- WriteDataType(&ot->templateSubTypes[n]);
- }
- else
- {
- ch = 't'; // token
- WriteData(&ch, 1);
- eTokenType t = ot->templateSubTypes[n].GetTokenType();
- WriteEncodedInt64(t);
- }
- }
- }
- }
- else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE )
- {
- ch = 's'; // sub type
- WriteData(&ch, 1);
- WriteString(&ti->name);
- }
- else if( !ti->GetParentType() )
- {
- ch = 'o'; // object
- WriteData(&ch, 1);
- WriteString(&ti->name);
- WriteString(&ti->nameSpace->name);
- }
- else
- {
- asASSERT(ti->flags & asOBJ_FUNCDEF);
- ch = 'c'; // child type
- WriteData(&ch, 1);
- WriteString(&ti->name);
- WriteTypeInfo(CastToFuncdefType(ti)->parentClass);
- }
- }
- else
- {
- ch = '\0';
- WriteData(&ch, 1);
- }
- }
- void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func)
- {
- // Adjust the offset of all negative variables (parameters) so all pointers will have a size of 1 dword
- asUINT n;
- asCArray<int> adjustments;
- asUINT offset = 0;
- if( func->objectType )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- if( func->DoesReturnOnStack() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- for( n = 0; n < func->parameterTypes.GetLength(); n++ )
- {
- if( !func->parameterTypes[n].IsPrimitive() ||
- func->parameterTypes[n].IsReference() )
- {
- adjustments.PushLast(offset);
- adjustments.PushLast(1-AS_PTR_SIZE);
- offset += AS_PTR_SIZE;
- }
- else
- {
- asASSERT( func->parameterTypes[n].IsPrimitive() );
- offset += func->parameterTypes[n].GetSizeOnStackDWords();
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustNegativeStackByPos.SetLength(offset);
- memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ )
- adjustNegativeStackByPos[i] += adjust;
- }
- // Adjust the offset of all positive variables so that all object types and handles have a size of 1 dword
- // This is similar to how the adjustment is done in the asCReader::TranslateFunction, only the reverse
- adjustments.SetLength(0);
- for (n = 0; n < func->scriptData->variables.GetLength(); n++)
- {
- // Skip function parameters as these are adjusted by adjustNegativeStackByPos
- if (func->scriptData->variables[n]->stackOffset <= 0)
- continue;
- asCDataType t = func->scriptData->variables[n]->type;
- if (!t.IsObject() && !t.IsObjectHandle())
- continue;
- // Determing the size of the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- if (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !func->scriptData->variables[n]->onHeap)
- size = t.GetSizeInMemoryDWords();
- // If larger than 1 dword, adjust the offsets accordingly
- if (size > 1)
- {
- // How much needs to be adjusted?
- adjustments.PushLast(func->scriptData->variables[n]->stackOffset);
- adjustments.PushLast(-(size - 1));
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustStackByPos.SetLength(func->scriptData->stackNeeded+AS_PTR_SIZE); // Add space for a pointer stored in a temporary variable
- memset(adjustStackByPos.AddressOf(), 0, adjustStackByPos.GetLength()*sizeof(int));
- for( n = 0; n < adjustments.GetLength(); n+=2 )
- {
- int pos = adjustments[n];
- int adjust = adjustments[n+1];
- for( asUINT i = pos; i < adjustStackByPos.GetLength(); i++ )
- adjustStackByPos[i] += adjust;
- }
- // Compute the sequence number of each bytecode instruction in order to update the jump offsets
- asUINT length = func->scriptData->byteCode.GetLength();
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- bytecodeNbrByPos.SetLength(length);
- asUINT num;
- for( offset = 0, num = 0; offset < length; )
- {
- bytecodeNbrByPos[offset] = num;
- offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type];
- num++;
- }
- // Store the number of instructions in the last position of bytecodeNbrByPos,
- // so this can be easily queried in SaveBytecode. Normally this is already done
- // as most functions end with BC_RET, but in some cases the last instruction in
- // the function is not a BC_RET, e.g. when a function has a never ending loop.
- bytecodeNbrByPos[length - 1] = num - 1;
- }
- int asCWriter::AdjustStackPosition(int pos)
- {
- if( pos >= (int)adjustStackByPos.GetLength() )
- {
- // This happens for example if the function only have temporary variables
- // The adjustByPos can also be empty if the function doesn't have any variables at all, but receive a handle by parameter
- if( adjustStackByPos.GetLength() > 0 )
- pos += adjustStackByPos[adjustStackByPos.GetLength()-1];
- }
- else if( pos >= 0 )
- pos += adjustStackByPos[pos];
- else
- {
- asASSERT( -pos < (int)adjustNegativeStackByPos.GetLength() );
- pos -= (short)adjustNegativeStackByPos[-pos];
- }
- return pos;
- }
- int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos)
- {
- // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime
- // the function can remember where it found the function and check if the programPos is still valid
- // Get offset 0 doesn't need adjustment
- if( offset == 0 ) return 0;
- bool bcAlloc = false;
- // Find out which function that will be called
- asCScriptFunction *calledFunc = 0;
- int stackDelta = 0;
- for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); )
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
- if( bc == asBC_CALL ||
- bc == asBC_CALLSYS ||
- bc == asBC_Thiscall1 ||
- bc == asBC_CALLINTF )
- {
- // Find the function from the function id in bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
- calledFunc = engine->scriptFunctions[funcId];
- break;
- }
- else if( bc == asBC_ALLOC )
- {
- // The alloc instruction doesn't take the object pointer on the stack,
- // as the memory will be allocated by the instruction itself
- bcAlloc = true;
- // Find the function from the function id in the bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]);
- calledFunc = engine->scriptFunctions[funcId];
- break;
- }
- else if( bc == asBC_CALLBND )
- {
- // Find the function from the engine's bind array
- int funcId = asBC_INTARG(&func->scriptData->byteCode[n]);
- calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
- break;
- }
- else if( bc == asBC_CallPtr )
- {
- int var = asBC_SWORDARG0(&func->scriptData->byteCode[n]);
- asUINT v;
- // Find the funcdef from the local variable
- for (v = 0; v < func->scriptData->variables.GetLength(); v++)
- {
- if (func->scriptData->variables[v]->stackOffset == var)
- {
- asASSERT(func->scriptData->variables[v]->type.GetTypeInfo());
- calledFunc = CastToFuncdefType(func->scriptData->variables[v]->type.GetTypeInfo())->funcdef;
- break;
- }
- }
- if( !calledFunc )
- {
- // Look in parameters
- int paramPos = 0;
- if( func->objectType )
- paramPos -= AS_PTR_SIZE;
- if( func->DoesReturnOnStack() )
- paramPos -= AS_PTR_SIZE;
- for( v = 0; v < func->parameterTypes.GetLength(); v++ )
- {
- if( var == paramPos )
- {
- calledFunc = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
- break;
- }
- paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
- }
- }
- break;
- }
- else if( bc == asBC_REFCPY ||
- bc == asBC_COPY )
- {
- // In this case we know there is only 1 pointer on the stack above
- asASSERT( offset == AS_PTR_SIZE );
- return offset + (1 - AS_PTR_SIZE);
- }
- // Keep track of the stack size between the
- // instruction that needs to be adjusted and the call
- stackDelta += asBCInfo[bc].stackInc;
- n += asBCTypeSize[asBCInfo[bc].type];
- }
- asASSERT( calledFunc );
- // Count the number of pointers pushed on the stack above the
- // current offset, and then adjust the offset accordingly
- asUINT numPtrs = 0;
- int currOffset = -stackDelta;
- if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc )
- {
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- }
- for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
- {
- if( offset <= currOffset ) break;
- if( !calledFunc->parameterTypes[p].IsPrimitive() ||
- calledFunc->parameterTypes[p].IsReference() )
- {
- // objects and references are passed by pointer
- currOffset += AS_PTR_SIZE;
- if( currOffset > 0 )
- numPtrs++;
- // The variable arg ? has an additional 32bit int with the typeid
- if( calledFunc->parameterTypes[p].IsAnyType() )
- currOffset += 1;
- }
- else
- {
- // built-in primitives or enums are passed by value
- asASSERT( calledFunc->parameterTypes[p].IsPrimitive() );
- currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords();
- }
- }
- // The get offset must match one of the parameter offsets
- asASSERT( offset == currOffset );
- return offset + numPtrs * (1 - AS_PTR_SIZE);
- }
- void asCWriter::WriteByteCode(asCScriptFunction *func)
- {
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- size_t length = func->scriptData->byteCode.GetLength();
- // The length cannot be stored, because it is platform dependent,
- // instead we store the number of instructions
- asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1;
- WriteEncodedInt64(count);
- asDWORD *startBC = bc;
- while( length )
- {
- asDWORD tmpBC[4]; // The biggest instructions take up 4 DWORDs
- asDWORD c = *(asBYTE*)bc;
- // Copy the instruction to a temp buffer so we can work on it before saving
- memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD));
- if( c == asBC_ALLOC ) // PTR_DW_ARG
- {
- // Translate the object type
- asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
- // Translate the constructor func id, unless it is 0
- if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 )
- {
- // Increment 1 to the translated function id, as 0 will be reserved for no function
- *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[1+AS_PTR_SIZE]]);
- }
- }
- else if( c == asBC_REFCPY || // PTR_ARG
- c == asBC_RefCpyV || // wW_PTR_ARG
- c == asBC_OBJTYPE ) // PTR_ARG
- {
- // Translate object type pointers into indices
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1));
- }
- else if( c == asBC_JitEntry ) // PTR_ARG
- {
- // We don't store the JIT argument
- *(asPWORD*)(tmpBC+1) = 0;
- }
- else if( c == asBC_TYPEID || // DW_ARG
- c == asBC_Cast ) // DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- }
- else if( c == asBC_ADDSi || // W_DW_ARG
- c == asBC_LoadThisR ) // W_DW_ARG
- {
- // Translate property offsets into indices
- *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc);
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- }
- else if( c == asBC_LoadRObjR || // rW_W_DW_ARG
- c == asBC_LoadVObjR ) // rW_W_DW_ARG
- {
- asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2));
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- // List patterns have a different way of translating the offsets
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot);
- }
- else
- {
- // Translate property offsets into indices
- *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc);
- }
- // Translate type ids into indices
- *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2));
- }
- else if( c == asBC_COPY ) // W_DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1));
- // Update the WORDARG0 to 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmpBC) = 0;
- }
- else if( c == asBC_RET ) // W_ARG
- {
- // Save with arg 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmpBC) = 0;
- }
- else if( c == asBC_CALL || // DW_ARG
- c == asBC_CALLINTF || // DW_ARG
- c == asBC_CALLSYS || // DW_ARG
- c == asBC_Thiscall1 ) // DW_ARG
- {
- // Translate the function id
- *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]);
- }
- else if( c == asBC_FuncPtr ) // PTR_ARG
- {
- // Translate the function pointer
- *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1));
- }
- else if( c == asBC_CALLBND ) // DW_ARG
- {
- // Translate the function id
- int funcId = tmpBC[1];
- for( asUINT n = 0; n < module->m_bindInformations.GetLength(); n++ )
- if( module->m_bindInformations[n]->importedFunctionSignature->id == funcId )
- {
- funcId = n;
- break;
- }
- tmpBC[1] = funcId;
- }
- else if( c == asBC_PGA || // PTR_ARG
- c == asBC_PshGPtr || // PTR_ARG
- c == asBC_LDG || // PTR_ARG
- c == asBC_PshG4 || // PTR_ARG
- c == asBC_LdGRdR4 || // wW_PTR_ARG
- c == asBC_CpyGtoV4 || // wW_PTR_ARG
- c == asBC_CpyVtoG4 || // rW_PTR_ARG
- c == asBC_SetG4 ) // PTR_DW_ARG
- {
- // Check if the address is a global property or a string constant
- void *ptr = *(void**)(tmpBC + 1);
- if (engine->varAddressMap.MoveTo(0, ptr))
- {
- // Translate global variable pointers into indices
- // Flag the first bit to signal global property
- *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1;
- }
- else
- {
- // Only PGA and PshGPtr can hold string constants
- asASSERT(c == asBC_PGA || c == asBC_PshGPtr);
- // Translate string constants into indices
- // Leave the first bit clear to signal string constant
- *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1;
- }
- }
- else if( c == asBC_JMP || // DW_ARG
- c == asBC_JZ ||
- c == asBC_JNZ ||
- c == asBC_JLowZ ||
- c == asBC_JLowNZ ||
- c == asBC_JS ||
- c == asBC_JNS ||
- c == asBC_JP ||
- c == asBC_JNP ) // The JMPP instruction doesn't need modification
- {
- // Get the DWORD offset from arg
- int offset = *(int*)(tmpBC+1);
- // Determine instruction number for next instruction and destination
- int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1;
- asDWORD *targetBC = bc + 2 + offset;
- int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)];
- // Set the offset in number of instructions
- *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum;
- }
- else if( c == asBC_GETOBJ || // W_ARG
- c == asBC_GETOBJREF ||
- c == asBC_GETREF ||
- c == asBC_ChkNullS )
- {
- // Adjust the offset according to the function call that comes after
- asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC));
- }
- else if( c == asBC_AllocMem )
- {
- // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader
- asBC_DWORDARG(tmpBC) = 0;
- // Determine the type of the list pattern from the variable
- short var = asBC_WORDARG0(tmpBC);
- asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var));
- // Create this helper object to adjust the offset of the elements accessed in the buffer
- listAdjusters.PushLast(asNEW(SListAdjuster)(ot));
- }
- else if( c == asBC_FREE ) // wW_PTR_ARG
- {
- // Translate object type pointers into indices
- asCObjectType *ot = *(asCObjectType**)(tmpBC+1);
- *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot);
- // Pop and destroy the list adjuster helper that was created with asBC_AllocMem
- if( ot && (ot->flags & asOBJ_LIST_PATTERN) )
- {
- SListAdjuster *list = listAdjusters.PopLast();
- asDELETE(list, SListAdjuster);
- }
- }
- else if( c == asBC_SetListSize )
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- // Tell the adjuster how many repeated values there are
- listAdj->SetRepeatCount(tmpBC[2]);
- }
- else if( c == asBC_PshListElmnt ) // W_DW_ARG
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- }
- else if( c == asBC_SetListType )
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType);
- // Inform the adjuster of the type id of the next element
- listAdj->SetNextType(tmpBC[2]);
- // Translate the type id
- tmpBC[2] = FindTypeIdIdx(tmpBC[2]);
- }
- // Adjust the variable offsets
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_QW_ARG:
- case asBCTYPE_rW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_wW_W_ARG:
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- case asBCTYPE_rW_DW_DW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC));
- asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC));
- asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC));
- }
- break;
- default:
- // The other types don't treat variables so won't be modified
- break;
- }
- // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform.
- // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values
- // Now store the instruction in the smallest possible way
- switch( asBCInfo[c].type )
- {
- case asBCTYPE_NO_ARG:
- {
- // Just write 1 byte
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- }
- break;
- case asBCTYPE_W_ARG:
- case asBCTYPE_wW_ARG:
- case asBCTYPE_rW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_rW_DW_ARG:
- case asBCTYPE_wW_DW_ARG:
- case asBCTYPE_W_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the word argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- }
- break;
- case asBCTYPE_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- WriteEncodedInt64((int)tmpBC[1]);
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[2]);
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- w = *(((short*)tmpBC)+3);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_rW_rW_ARG:
- case asBCTYPE_wW_W_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- }
- break;
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_W_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmpBC)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- int dw = tmpBC[2];
- WriteEncodedInt64(dw);
- }
- break;
- case asBCTYPE_QW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- }
- break;
- case asBCTYPE_QW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- // Write the second argument
- int dw = tmpBC[3];
- WriteEncodedInt64(dw);
- }
- break;
- case asBCTYPE_rW_QW_ARG:
- case asBCTYPE_wW_QW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the first argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmpBC[1];
- WriteEncodedInt64(qw);
- }
- break;
- case asBCTYPE_rW_DW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the short argument
- short w = *(((short*)tmpBC)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmpBC[2]);
- }
- break;
- default:
- {
- // This should never happen
- asASSERT(false);
- // Store the bc as is
- for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ )
- WriteData(&tmpBC[n], 4);
- }
- }
- // Move to the next instruction
- bc += asBCTypeSize[asBCInfo[c].type];
- length -= asBCTypeSize[asBCInfo[c].type];
- }
- }
- asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1)
- {
- asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) );
- // Find the first expected value in the list
- asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
- asASSERT( node && node->type == asLPT_START );
- patternNode = node->next;
- }
- int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatternType)
- {
- // TODO: cleanup: The listPatternType parameter is not needed
- asASSERT( patternType == listPatternType );
- UNUSED_VAR(listPatternType);
- asASSERT( offset >= lastOffset );
- // If it is the same offset being accessed again, just return the same adjusted value
- if( offset == lastOffset )
- return entries-1;
- asASSERT( offset >= nextOffset );
- // Update last offset for next call
- lastOffset = offset;
- // What is being expected at this position?
- if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
- {
- // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too
- nextOffset = offset + 4;
- return entries++;
- }
- else if( patternNode->type == asLPT_TYPE )
- {
- const asCDataType &dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
- if( dt.GetTokenType() == ttQuestion )
- {
- // The bytecode need to inform the type that will
- // come next and then adjust that position too before
- // we can move to the next node
- if( nextTypeId != -1 )
- {
- nextOffset = offset + 4;
- if( repeatCount > 0 )
- repeatCount--;
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- nextTypeId = -1;
- }
- }
- else
- {
- if( repeatCount > 0 )
- {
- // Was any value skipped?
- asUINT size;
- if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = dt.GetSizeInMemoryBytes();
- int count = 0;
- while( nextOffset <= offset )
- {
- count++;
- nextOffset += size;
- // Align the offset on 4 byte boundaries
- if( size >= 4 && (nextOffset & 0x3) )
- nextOffset += 4 - (nextOffset & 0x3);
- }
- if( --count > 0 )
- {
- // Skip these values
- repeatCount -= count;
- entries += count;
- }
- nextOffset = offset + size;
- repeatCount--;
- }
- // Only move the patternNode if we're not expecting any more repeated entries
- if( repeatCount == 0 )
- patternNode = patternNode->next;
- }
- return entries++;
- }
- else if( patternNode->type == asLPT_START )
- {
- if( repeatCount > 0 )
- repeatCount--;
- SInfo info = {repeatCount, patternNode};
- stack.PushLast(info);
- repeatCount = 0;
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset, listPatternType);
- }
- else if( patternNode->type == asLPT_END )
- {
- SInfo info = stack.PopLast();
- repeatCount = info.repeatCount;
- if( repeatCount )
- patternNode = info.startNode;
- else
- patternNode = patternNode->next;
- lastOffset--;
- return AdjustOffset(offset, listPatternType);
- }
- else
- {
- // Something is wrong with the pattern list declaration
- asASSERT( false );
- }
- return 0;
- }
- void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc)
- {
- // Make sure the list is expecting a repeat at this location
- asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME );
- // Now move to the next patternNode
- patternNode = patternNode->next;
- repeatCount = rc;
- }
- void asCWriter::SListAdjuster::SetNextType(int typeId)
- {
- // Make sure the list is expecting a type at this location
- asASSERT( patternNode->type == asLPT_TYPE &&
- reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
- // Inform the type id for the next adjustment
- nextTypeId = typeId;
- }
- void asCWriter::WriteUsedTypeIds()
- {
- TimeIt("asCWriter::WriteUsedTypeIds");
- asUINT count = (asUINT)usedTypeIds.GetLength();
- WriteEncodedInt64(count);
- for( asUINT n = 0; n < count; n++ )
- {
- asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]);
- WriteDataType(&dt);
- }
- }
- int asCWriter::FindGlobalPropPtrIndex(void *ptr)
- {
- int i = usedGlobalProperties.IndexOf(ptr);
- if( i >= 0 ) return i;
- usedGlobalProperties.PushLast(ptr);
- return (int)usedGlobalProperties.GetLength()-1;
- }
- void asCWriter::WriteUsedGlobalProps()
- {
- TimeIt("asCWriter::WriteUsedGlobalProps");
- int c = (int)usedGlobalProperties.GetLength();
- WriteEncodedInt64(c);
- for( int n = 0; n < c; n++ )
- {
- asPWORD *p = (asPWORD*)usedGlobalProperties[n];
- // Find the property descriptor from the address
- asCGlobalProperty *prop = 0;
- asSMapNode<void*, asCGlobalProperty*> *cursor;
- if( engine->varAddressMap.MoveTo(&cursor, p) )
- {
- prop = engine->varAddressMap.GetValue(cursor);
- }
- asASSERT(prop);
- // Store the name and type of the property so we can find it again on loading
- WriteString(&prop->name);
- WriteString(&prop->nameSpace->name);
- WriteDataType(&prop->type);
- // Also store whether the property is a module property or a registered property
- char moduleProp = 0;
- if( prop->realAddress == 0 )
- moduleProp = 1;
- WriteData(&moduleProp, 1);
- }
- }
- void asCWriter::WriteUsedObjectProps()
- {
- TimeIt("asCWriter::WriteUsedObjectProps");
- int c = (int)usedObjectProperties.GetLength();
- WriteEncodedInt64(c);
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- WriteTypeInfo(usedObjectProperties[n].objType);
- WriteString(&usedObjectProperties[n].prop->name);
- }
- }
- int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc)
- {
- // If the last property was a composite property, then just return 0, because it won't be translated
- static bool lastWasComposite = false;
- if (lastWasComposite)
- {
- lastWasComposite = false;
- return 0;
- }
-
- asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId);
- asCObjectProperty *objProp = 0;
- // Look for composite properties first
- for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
- {
- // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property.
- // That would also allow me to remove the typeId from the bytecode instruction itself
- // Or perhaps a new bytecode instruction all together for accessing composite properties
- // One that would do both offsets and indirection in a single go.
- // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too
- if (objType->properties[n]->compositeOffset == offset)
- {
- // This is a potential composite property. Need to check the following instructions to be sure
- objProp = objType->properties[n];
- asDWORD *bcTemp = bc;
- bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
- if (objProp->isCompositeIndirect)
- {
- // The next instruction would be a asBC_RDSPtr
- if ((*(asBYTE*)bcTemp) != asBC_RDSPtr)
- {
- objProp = 0;
- continue;
- }
- bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type];
- }
- // The next instruction would be asBC_ADDSi
- if ((*(asBYTE*)bcTemp) != asBC_ADDSi)
- {
- objProp = 0;
- continue;
- }
- // Make sure the offset is the expected one
- if (*(((short*)bcTemp) + 1) != objProp->byteOffset)
- {
- objProp = 0;
- continue;
- }
- }
- }
- // If none of the composite properties matched, then look for ordinary property
- for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++)
- {
- if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect))
- objProp = objType->properties[n];
- }
- asASSERT(objProp);
- // Remember if this is a composite property as the next call will then be for the same property
- if (objProp->compositeOffset || objProp->isCompositeIndirect)
- lastWasComposite = true;
- // Now check if the same property has already been accessed
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- if( usedObjectProperties[n].objType == objType &&
- usedObjectProperties[n].prop == objProp )
- return n;
- }
- // Insert the new property
- SObjProp prop = {objType, objProp};
- usedObjectProperties.PushLast(prop);
- return (int)usedObjectProperties.GetLength() - 1;
- }
- int asCWriter::FindFunctionIndex(asCScriptFunction *func)
- {
- for( asUINT n = 0; n < usedFunctions.GetLength(); n++ )
- {
- if( usedFunctions[n] == func )
- return n;
- }
- usedFunctions.PushLast(func);
- return (int)usedFunctions.GetLength() - 1;
- }
- int asCWriter::FindTypeIdIdx(int typeId)
- {
- asUINT n;
- for( n = 0; n < usedTypeIds.GetLength(); n++ )
- {
- if( usedTypeIds[n] == typeId )
- return n;
- }
- usedTypeIds.PushLast(typeId);
- return (int)usedTypeIds.GetLength() - 1;
- }
- int asCWriter::FindTypeInfoIdx(asCTypeInfo *obj)
- {
- asUINT n;
- for( n = 0; n < usedTypes.GetLength(); n++ )
- {
- if( usedTypes[n] == obj )
- return n;
- }
- usedTypes.PushLast(obj);
- return (int)usedTypes.GetLength() - 1;
- }
- #endif // AS_NO_COMPILER
- END_AS_NAMESPACE
|