| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2020 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- if( count > 256 )
- {
- // Too many arguments, must be something wrong in the file
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- 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, count;
- asCDataType dt;
- int num;
- 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 = ReadEncodedUInt();
- func->scriptData->objVariablesOnHeap = 0;
- if (bits & 8)
- {
- count = ReadEncodedUInt();
- func->scriptData->objVariablePos.Allocate(count, false);
- func->scriptData->objVariableTypes.Allocate(count, false);
- for (i = 0; i < count; ++i)
- {
- func->scriptData->objVariableTypes.PushLast(ReadTypeInfo());
- num = ReadEncodedUInt();
- func->scriptData->objVariablePos.PushLast(num);
- if (error)
- {
- // No need to continue (the error has already been reported before)
- func->DestroyHalfCreated();
- return 0;
- }
- }
- if (count > 0)
- func->scriptData->objVariablesOnHeap = ReadEncodedUInt();
- int length = ReadEncodedUInt();
- func->scriptData->objVariableInfo.SetLength(length);
- for (i = 0; i < length; ++i)
- {
- func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt();
- func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt();
- }
- }
- if (!noDebugInfo)
- {
- int length = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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
- if (!noDebugInfo)
- {
- int length = ReadEncodedUInt();
- 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);
- var->declaredAtProgramPos = ReadEncodedUInt();
- var->stackOffset = ReadEncodedUInt();
- ReadString(&var->name);
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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);
- }
- asQWORD asCReader::ReadEncodedUInt64()
- {
- asQWORD i = 0;
- asBYTE b;
- 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;
- }
- void asCReader::ReadString(asCString* str)
- {
- asUINT len = ReadEncodedUInt();
- 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);
- // 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- // 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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 = ReadEncodedUInt();
- 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);
- }
- // objVariablePos
- for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
- func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]);
- // 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 = GetCalledFunction(func, 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->objVariableTypes.GetLength(); n++ )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- // objVariableTypes is null if the type is a null pointer
- if( func->scriptData->objVariableTypes[n] &&
- (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
- n >= func->scriptData->objVariablesOnHeap )
- {
- size = func->scriptData->objVariableTypes[n]->GetSize();
- if( size < 4 )
- size = 1;
- else
- size /= 4;
- }
- // Check if type has a different size than stored
- if( size > 1 )
- {
- if( func->scriptData->objVariablePos[n] > highestPos )
- highestPos = func->scriptData->objVariablePos[n];
- adjustments.PushLast(func->scriptData->objVariablePos[n]);
- 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;
- }
- asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD programPos)
- {
- asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos];
- 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[programPos]);
- return engine->scriptFunctions[funcId];
- }
- else if( bc == asBC_ALLOC )
- {
- // Find the function from the function id in the bytecode
- int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos+AS_PTR_SIZE]);
- return engine->scriptFunctions[funcId];
- }
- else if( bc == asBC_CALLBND )
- {
- // Find the function from the engine's bind array
- int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]);
- return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
- }
- else if( bc == asBC_CallPtr )
- {
- asUINT v;
- int var = asBC_SWORDARG0(&func->scriptData->byteCode[programPos]);
- // Find the funcdef from the local variable
- for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
- if( func->scriptData->objVariablePos[v] == var )
- return CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef;
- // 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)
- {
- if (func->parameterTypes[v].IsFuncdef())
- return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef;
- else
- {
- error = true;
- return 0;
- }
- }
- paramPos -= func->parameterTypes[v].GetSizeOnStackDWords();
- }
- }
- return 0;
- }
- 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
- 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 = GetCalledFunction(func, 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->objVariablePos.GetLength() || 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)
- {
- count = (asUINT)func->scriptData->objVariablePos.GetLength();
- WriteEncodedInt64(count);
- for (i = 0; i < count; ++i)
- {
- WriteTypeInfo(func->scriptData->objVariableTypes[i]);
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i]));
- }
- if (count > 0)
- WriteEncodedInt64(func->scriptData->objVariablesOnHeap);
- 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
- if( !stripDebugInfo )
- {
- WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength());
- for( i = 0; i < func->scriptData->variables.GetLength(); i++ )
- {
- // The program position must be adjusted to be in number of instructions
- WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]);
- // The stack position must be adjusted according to the pointer sizes
- WriteEncodedInt64(AdjustStackPosition(func->scriptData->variables[i]->stackOffset));
- WriteString(&func->scriptData->variables[i]->name);
- 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->objVariableTypes.GetLength(); n++ )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- // objVariableTypes is null if the variable type is a null pointer
- if( func->scriptData->objVariableTypes[n] &&
- (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
- n >= func->scriptData->objVariablesOnHeap )
- {
- size = func->scriptData->objVariableTypes[n]->GetSize();
- if( size < 4 )
- size = 1;
- else
- size /= 4;
- }
- // If larger than 1 dword, adjust the offsets accordingly
- if (size > 1)
- {
- // How much needs to be adjusted?
- adjustments.PushLast(func->scriptData->objVariablePos[n]);
- adjustments.PushLast(-(size - 1));
- }
- }
- // Build look-up table with the adjustments for each stack position
- adjustStackByPos.SetLength(func->scriptData->stackNeeded);
- 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->objVariablePos.GetLength(); v++ )
- {
- if( func->scriptData->objVariablePos[v] == var )
- {
- calledFunc = CastToFuncdefType(func->scriptData->objVariableTypes[v])->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
|