| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2014 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"
- BEGIN_AS_NAMESPACE
- asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine)
- : module(_module), stream(_stream), engine(_engine)
- {
- error = false;
- bytesRead = 0;
- }
- void asCReader::ReadData(void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; n < size; n++ )
- stream->Read(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; n >= 0; n-- )
- stream->Read(((asBYTE*)data)+n, 1);
- #endif
- bytesRead += size;
- }
- int asCReader::Read(bool *wasDebugInfoStripped)
- {
- // 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->scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) )
- if( module->scriptFunctions[i]->scriptData )
- module->scriptFunctions[i]->scriptData->byteCode.SetLength(0);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->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;
- }
- 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 -1;
- }
- int 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;
- ReadData(&noDebugInfo, 1);
- // Read enums
- count = ReadEncodedUInt();
- module->enumTypes.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCObjectType *ot = asNEW(asCObjectType)(engine);
- if( ot == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- ReadObjectTypeDeclaration(ot, 1);
- // 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->classTypes.GetLength(); n++ )
- {
- asCObjectType *t = engine->classTypes[n];
- if( t &&
- t->IsShared() &&
- t->name == ot->name &&
- t->nameSpace == ot->nameSpace &&
- (t->flags & asOBJ_ENUM) )
- {
- asDELETE(ot, asCObjectType);
- ot = t;
- sharedExists = true;
- break;
- }
- }
- }
- if( sharedExists )
- existingShared.Insert(ot, true);
- else
- engine->classTypes.PushLast(ot);
- module->enumTypes.PushLast(ot);
- ot->AddRef();
- ReadObjectTypeDeclaration(ot, 2);
- }
- if( error ) return asERROR;
- // classTypes[]
- // First restore the structure names, then the properties
- count = ReadEncodedUInt();
- module->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;
- }
- ReadObjectTypeDeclaration(ot, 1);
- // 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->classTypes.GetLength(); n++ )
- {
- asCObjectType *t = engine->classTypes[n];
- if( t &&
- t->IsShared() &&
- t->name == ot->name &&
- t->nameSpace == ot->nameSpace &&
- t->IsInterface() == ot->IsInterface() )
- {
- asDELETE(ot, asCObjectType);
- ot = t;
- sharedExists = true;
- break;
- }
- }
- }
- if( sharedExists )
- existingShared.Insert(ot, true);
- else
- {
- engine->classTypes.PushLast(ot);
- // Set this module as the owner
- ot->module = module;
- }
- module->classTypes.PushLast(ot);
- ot->AddRef();
- }
- if( error ) return asERROR;
- // Read func defs
- count = ReadEncodedUInt();
- module->funcDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- bool isNew;
- asCScriptFunction *func = ReadFunction(isNew, false, true);
- if( func )
- {
- module->funcDefs.PushLast(func);
- engine->funcDefs.PushLast(func);
- // 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
- for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
- {
- asCScriptFunction *f2 = engine->funcDefs[n];
- if( f2 == 0 || func == f2 )
- continue;
- if( f2->name == func->name &&
- f2->nameSpace == func->nameSpace &&
- f2->IsSignatureExceptNameEqual(func) )
- {
- // Replace our funcdef for the existing one
- module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
- f2->AddRef();
- engine->funcDefs.RemoveValue(func);
- savedFunctions[savedFunctions.IndexOf(func)] = f2;
- func->Release();
- // Funcdefs aren't deleted when the ref count reaches zero so we must manually delete it here
- asDELETE(func,asCScriptFunction);
- break;
- }
- }
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- // Read interface methods
- for( i = 0; i < module->classTypes.GetLength() && !error; i++ )
- {
- if( module->classTypes[i]->IsInterface() )
- ReadObjectTypeDeclaration(module->classTypes[i], 2);
- }
- // Read class methods and behaviours
- for( i = 0; i < module->classTypes.GetLength() && !error; ++i )
- {
- if( !module->classTypes[i]->IsInterface() )
- ReadObjectTypeDeclaration(module->classTypes[i], 2);
- }
- // Read class properties
- for( i = 0; i < module->classTypes.GetLength() && !error; ++i )
- {
- if( !module->classTypes[i]->IsInterface() )
- ReadObjectTypeDeclaration(module->classTypes[i], 3);
- }
- if( error ) return asERROR;
- // Read typedefs
- count = ReadEncodedUInt();
- module->typeDefs.Allocate(count, false);
- for( i = 0; i < count && !error; i++ )
- {
- asCObjectType *ot = asNEW(asCObjectType)(engine);
- if( ot == 0 )
- {
- error = true;
- return asOUT_OF_MEMORY;
- }
- ReadObjectTypeDeclaration(ot, 1);
- engine->classTypes.PushLast(ot);
- module->typeDefs.PushLast(ot);
- ot->AddRef();
- ReadObjectTypeDeclaration(ot, 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->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->scriptFunctions.GetLength();
- bool isNew;
- func = ReadFunction(isNew);
- if( func == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
-
- // Is the function shared and was it created now?
- if( func->isShared && len != module->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->IsSignatureEqual(func) )
- {
- // Replace the recently created function with the pre-existing function
- module->scriptFunctions[module->scriptFunctions.GetLength()-1] = realFunc;
- realFunc->AddRef();
- savedFunctions[savedFunctions.GetLength()-1] = realFunc;
- engine->FreeScriptFunctionId(func->id);
- // Insert the function in the dontTranslate array
- dontTranslate.Insert(realFunc, true);
- // Release the function, but make sure nothing else is released
- func->id = 0;
- func->scriptData->byteCode.SetLength(0);
- func->Release();
- break;
- }
- }
- }
- }
- // 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 refernces to know which goes into the globalFunctions array
- asASSERT( !isNew );
- module->globalFunctions.Put(func);
- func->AddRef();
- }
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- if( error ) return asERROR;
- // bindInformations[]
- count = ReadEncodedUInt();
- module->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->bindInformations.PushLast(info);
- }
- if( error ) return asERROR;
- // usedTypes[]
- count = ReadEncodedUInt();
- usedTypes.Allocate(count, false);
- for( i = 0; i < count && !error; ++i )
- {
- asCObjectType *ot = ReadObjectType();
- usedTypes.PushLast(ot);
- }
- // 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++ )
- {
- if( !(usedTypes[i]->flags & asOBJ_TEMPLATE) ||
- !usedTypes[i]->beh.templateCallback )
- continue;
-
- bool dontGarbageCollect = false;
- asCScriptFunction *callback = engine->scriptFunctions[usedTypes[i]->beh.templateCallback];
- if( !engine->CallGlobalFunctionRetBool(usedTypes[i], &dontGarbageCollect, callback->sysFuncIntf, callback) )
- {
- asCString sub = usedTypes[i]->templateSubTypes[0].Format();
- for( asUINT n = 1; n < usedTypes[i]->templateSubTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += usedTypes[i]->templateSubTypes[n].Format();
- }
- asCString str;
- str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, usedTypes[i]->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 )
- usedTypes[i]->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->scriptFunctions.GetLength() && !error; i++ )
- if( module->scriptFunctions[i]->funcType == asFUNC_SCRIPT )
- TranslateFunction(module->scriptFunctions[i]);
- asCSymbolTable<asCGlobalProperty>::iterator globIt = module->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->scriptFunctions.GetLength(); i++ )
- if( !dontTranslate.MoveTo(0, module->scriptFunctions[i]) )
- module->scriptFunctions[i]->AddReferences();
- globIt = module->scriptGlobals.List();
- while( globIt )
- {
- asCScriptFunction *initFunc = (*globIt)->GetInitFunc();
- if( initFunc )
- initFunc->AddReferences();
- globIt++;
- }
- return error ? asERROR : asSUCCESS;
- }
- void asCReader::ReadUsedStringConstants()
- {
- asCString str;
- asUINT count;
- count = ReadEncodedUInt();
- usedStringConstants.Allocate(count, false);
- for( asUINT i = 0; i < count; ++i )
- {
- ReadString(&str);
- usedStringConstants.PushLast(engine->AddConstantString(str.AddressOf(), str.GetLength()));
- }
- }
- void 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);
- ReadFunctionSignature(&func);
- if( error )
- {
- func.funcType = asFUNC_DUMMY;
- return;
- }
- // Find the correct function
- if( c == 'm' )
- {
- for( asUINT i = 0; i < module->scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = module->scriptFunctions[i];
- if( !func.IsSignatureEqual(f) ||
- func.objectType != f->objectType ||
- func.funcType != f->funcType ||
- func.nameSpace != f->nameSpace )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- else
- {
- for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
- {
- asCScriptFunction *f = engine->scriptFunctions[i];
- if( f == 0 ||
- !func.IsSignatureEqual(f) ||
- func.objectType != f->objectType ||
- func.nameSpace != f->nameSpace )
- continue;
- usedFunctions[n] = f;
- break;
- }
- }
- // 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)
- {
- 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());
- 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
- 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 = ReadObjectType();
- if( func->objectType )
- {
- asBYTE b;
- ReadData(&b, 1);
- func->isReadOnly = (b & 1) ? true : false;
- func->isPrivate = (b & 2) ? true : false;
- func->nameSpace = engine->nameSpaces[0];
- }
- else
- {
- asCString ns;
- ReadString(&ns);
- func->nameSpace = engine->AddNameSpace(ns.AddressOf());
- }
- }
- asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC)
- {
- isNew = 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;
- ReadFunctionSignature(func);
- if( error )
- {
- asDELETE(func, asCScriptFunction);
- return 0;
- }
- if( func->funcType == asFUNC_SCRIPT )
- {
- func->AllocateScriptFunctionData();
- if( func->scriptData == 0 )
- {
- // Out of memory
- error = true;
- asDELETE(func, asCScriptFunction);
- return 0;
- }
- if( addToGC && !addToModule )
- engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours);
-
- ReadByteCode(func);
- func->scriptData->variableSpace = ReadEncodedUInt();
- count = ReadEncodedUInt();
- func->scriptData->objVariablePos.Allocate(count, false);
- func->scriptData->objVariableTypes.Allocate(count, false);
- func->scriptData->funcVariableTypes.Allocate(count, false);
- for( i = 0; i < count; ++i )
- {
- func->scriptData->objVariableTypes.PushLast(ReadObjectType());
- asUINT idx = ReadEncodedUInt();
- func->scriptData->funcVariableTypes.PushLast((asCScriptFunction*)(asPWORD)idx);
- num = ReadEncodedUInt();
- func->scriptData->objVariablePos.PushLast(num);
- }
- if( count > 0 )
- func->scriptData->objVariablesOnHeap = ReadEncodedUInt();
- else
- func->scriptData->objVariablesOnHeap = 0;
- 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();
- func->scriptData->objVariableInfo[i].option = ReadEncodedUInt();
- }
- if( !noDebugInfo )
- {
- length = ReadEncodedUInt();
- func->scriptData->lineNumbers.SetLength(length);
- if( int(func->scriptData->lineNumbers.GetLength()) != length )
- {
- // Out of memory
- error = true;
- asDELETE(func, asCScriptFunction);
- 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;
- asDELETE(func, asCScriptFunction);
- 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 )
- {
- 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;
- asDELETE(func, asCScriptFunction);
- return 0;
- }
- func->scriptData->variables.PushLast(var);
- var->declaredAtProgramPos = ReadEncodedUInt();
- var->stackOffset = ReadEncodedUInt();
- ReadString(&var->name);
- ReadDataType(&var->type);
- }
- }
- char bits;
- ReadData(&bits, 1);
- func->isShared = bits & 1 ? true : false;
- func->dontCleanUpOnException = bits & 2 ? true : false;
- // 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 count = asUINT(ReadEncodedUInt64());
- if( count > func->parameterTypes.GetLength() )
- {
- error = true;
- asDELETE(func, asCScriptFunction);
- return 0;
- }
- func->parameterNames.SetLength(count);
- for( asUINT n = 0; n < count; n++ )
- ReadString(&func->parameterNames[n]);
- }
- }
- else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE )
- {
- func->vfTableIdx = ReadEncodedUInt();
- }
- if( addToModule )
- {
- // The refCount is already 1
- module->scriptFunctions.PushLast(func);
- func->module = module;
- }
- if( addToEngine )
- {
- func->id = engine->GetNextScriptFunctionId();
- engine->SetScriptFunction(func);
- }
- if( func->objectType )
- func->ComputeSignatureId();
- return func;
- }
- void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase)
- {
- if( phase == 1 )
- {
- // Read the initial attributes
- ReadString(&ot->name);
- ReadData(&ot->flags, 4);
- ot->size = ReadEncodedUInt();
- asCString ns;
- ReadString(&ns);
- ot->nameSpace = engine->AddNameSpace(ns.AddressOf());
- // Reset the size of script classes, since it will be recalculated as properties are added
- if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size != 0 )
- ot->size = sizeof(asCScriptObject);
- // 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]->AddRef();
- engine->scriptFunctions[ot->beh.release]->AddRef();
- engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRef();
- engine->scriptFunctions[ot->beh.gcGetFlag]->AddRef();
- engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRef();
- engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRef();
- engine->scriptFunctions[ot->beh.gcSetFlag]->AddRef();
- engine->scriptFunctions[ot->beh.copy]->AddRef();
- // TODO: weak: Should not do this if the class has been declared with 'noweak'
- engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRef();
- for( asUINT i = 1; i < ot->beh.operators.GetLength(); i += 2 )
- engine->scriptFunctions[ot->beh.operators[i]]->AddRef();
- }
- else if( phase == 2 )
- {
- if( ot->flags & asOBJ_ENUM )
- {
- int count = ReadEncodedUInt();
- bool sharedExists = existingShared.MoveTo(0, ot);
- if( !sharedExists )
- {
- ot->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
- ot->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 < ot->enumValues.GetLength(); e++ )
- {
- if( ot->enumValues[e]->name == name &&
- ot->enumValues[e]->value == value )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( ot->flags & asOBJ_TYPEDEF )
- {
- eTokenType t = (eTokenType)ReadEncodedUInt();
- ot->templateSubTypes.PushLast(asCDataType::CreatePrimitive(t, false));
- }
- else
- {
- // If the type is shared and pre-existing, we should just
- // validate that the loaded methods match the original
- bool sharedExists = existingShared.MoveTo(0, ot);
- if( sharedExists )
- {
- asCObjectType *dt = ReadObjectType();
- if( ot->derivedFrom != dt )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- else
- {
- ot->derivedFrom = ReadObjectType();
- if( ot->derivedFrom )
- ot->derivedFrom->AddRef();
- }
- // interfaces[] / interfaceVFTOffsets[]
- int size = ReadEncodedUInt();
- if( sharedExists )
- {
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = ReadObjectType();
- ReadEncodedUInt();
- if( !ot->Implements(intf) )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName());
- engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- else
- {
- ot->interfaces.Allocate(size, false);
- ot->interfaceVFTOffsets.Allocate(size, false);
- for( int n = 0; n < size; n++ )
- {
- asCObjectType *intf = ReadObjectType();
- ot->interfaces.PushLast(intf);
- asUINT offset = ReadEncodedUInt();
- ot->interfaceVFTOffsets.PushLast(offset);
- }
- }
- // behaviours
- if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->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, ot->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->Release();
- }
- module->scriptFunctions.PushLast(realFunc);
- realFunc->AddRef();
- dontTranslate.Insert(realFunc, true);
- }
- }
- else
- {
- if( func )
- {
- ot->beh.destruct = func->id;
- func->AddRef();
- }
- else
- ot->beh.destruct = 0;
- }
- size = ReadEncodedUInt();
- for( int 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 n = 0; n < ot->beh.constructors.GetLength(); n++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[n]);
- 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;
- module->scriptFunctions.PushLast(realFunc);
- realFunc->AddRef();
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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->Release();
- }
- }
- else
- {
- ot->beh.constructors.PushLast(func->id);
- func->AddRef();
- 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 n = 0; n < ot->beh.factories.GetLength(); n++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[n]);
- 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;
- module->scriptFunctions.PushLast(realFunc);
- realFunc->AddRef();
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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->Release();
- }
- }
- else
- {
- ot->beh.factories.PushLast(func->id);
- func->AddRef();
- 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 n = 0; n < ot->methods.GetLength(); n++ )
- {
- asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[n]);
- 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;
- module->scriptFunctions.PushLast(realFunc);
- realFunc->AddRef();
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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->Release();
- }
- }
- 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].GetObjectType() == func->objectType &&
- (func->inOutFlags[0] & asTM_INREF) )
- {
- engine->scriptFunctions[ot->beh.copy]->Release();
- ot->beh.copy = func->id;
- func->AddRef();
- }
-
- ot->methods.PushLast(func->id);
- func->AddRef();
- }
- }
- 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 n = 0; n < ot->virtualFunctionTable.GetLength(); n++ )
- {
- asCScriptFunction *realFunc = ot->virtualFunctionTable[n];
- 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;
- module->scriptFunctions.PushLast(realFunc);
- realFunc->AddRef();
- dontTranslate.Insert(realFunc, true);
- break;
- }
- }
- if( !found )
- {
- asCString str;
- str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->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->Release();
- }
- }
- else
- {
- ot->virtualFunctionTable.PushLast(func);
- func->AddRef();
- }
- }
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- }
- }
- else if( phase == 3 )
- {
- // 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)
- {
- char b;
- ReadData(&b, 1);
- if( b == '\0' )
- {
- str->SetLength(0);
- }
- else if( b == 'n' )
- {
- asUINT len = ReadEncodedUInt();
- str->SetLength(len);
- stream->Read(str->AddressOf(), len);
- savedStrings.PushLast(*str);
- }
- else
- {
- asUINT n = ReadEncodedUInt();
- if( n < savedStrings.GetLength() )
- *str = savedStrings[n];
- else
- Error(TXT_INVALID_BYTECODE_d);
- }
- }
- 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->Release();
- }
- }
- void asCReader::ReadObjectProperty(asCObjectType *ot)
- {
- asCString name;
- ReadString(&name);
- asCDataType dt;
- ReadDataType(&dt);
- bool isPrivate;
- ReadData(&isPrivate, 1);
- // 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);
- }
- void asCReader::ReadDataType(asCDataType *dt)
- {
- // Check if this is a previously used type
- asUINT n = ReadEncodedUInt();
- if( n != 0 )
- {
- // Get the datatype from the cache
- *dt = savedDataTypes[n-1];
- return;
- }
- // Read the type definition
- eTokenType tokenType = (eTokenType)ReadEncodedUInt();
- // Reserve a spot in the savedDataTypes
- size_t saveSlot = savedDataTypes.GetLength();
- savedDataTypes.PushLast(asCDataType());
- // Read the datatype for the first time
- asCObjectType *objType = 0;
- if( tokenType == ttIdentifier )
- objType = ReadObjectType();
- struct
- {
- char isObjectHandle :1;
- char isHandleToConst:1;
- char isReference :1;
- char isReadOnly :1;
- } bits = {0};
- asASSERT( sizeof(bits) == 1 );
- ReadData(&bits, 1);
- asCScriptFunction *funcDef = 0;
- if( tokenType == ttIdentifier && objType && objType->name == "_builtin_function_" )
- {
- asCScriptFunction func(engine, module, asFUNC_DUMMY);
- ReadFunctionSignature(&func);
- if( error ) return;
- for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ )
- {
- // TODO: access: Only return the definitions that the module has access to
- if( engine->registeredFuncDefs[n]->name == func.name &&
- engine->registeredFuncDefs[n]->nameSpace == func.nameSpace )
- {
- funcDef = engine->registeredFuncDefs[n];
- break;
- }
- }
- if( !funcDef && module )
- {
- for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ )
- {
- if( module->funcDefs[n]->name == func.name &&
- module->funcDefs[n]->nameSpace == func.nameSpace )
- {
- funcDef = module->funcDefs[n];
- break;
- }
- }
- }
- // Set to dummy to avoid unwanted release of resources
- func.funcType = asFUNC_DUMMY;
- }
- if( funcDef )
- *dt = asCDataType::CreateFuncDef(funcDef);
- else if( tokenType == ttIdentifier )
- *dt = asCDataType::CreateObject(objType, false);
- else
- *dt = asCDataType::CreatePrimitive(tokenType, false);
- if( bits.isObjectHandle )
- {
- dt->MakeReadOnly(bits.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(bits.isReadOnly ? true : false);
- dt->MakeReference(bits.isReference ? true : false);
- // Update the previously saved slot
- savedDataTypes[saveSlot] = *dt;
- }
- asCObjectType* asCReader::ReadObjectType()
- {
- asCObjectType *ot = 0;
- char ch;
- ReadData(&ch, 1);
- if( ch == 'a' )
- {
- // Read the name of the template type
- asCString typeName;
- ReadString(&typeName);
- asCObjectType *tmpl = engine->GetRegisteredObjectType(typeName.AddressOf(), engine->nameSpaces[0]);
- 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);
- }
- if( ot == 0 )
- {
- // Show all subtypes in error message
- asCString sub = subTypes[0].Format();
- for( asUINT n = 1; n < subTypes.GetLength(); n++ )
- {
- sub += ",";
- sub += subTypes[n].Format();
- }
- 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 = ReadObjectType();
- 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 != "_builtin_object_" && typeName != "_builtin_function_" )
- {
- // Find the object type
- ot = module->GetObjectType(typeName.AddressOf(), nameSpace);
- if( !ot )
- ot = engine->GetRegisteredObjectType(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 == "_builtin_object_" )
- {
- ot = &engine->scriptTypeBehaviours;
- }
- else if( typeName == "_builtin_function_" )
- {
- ot = &engine->functionBehaviours;
- }
- else
- asASSERT( false );
- }
- else
- {
- // No object type
- asASSERT( ch == '\0' );
- 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()
- {
- 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()
- {
- 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->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()
- {
- asUINT c = ReadEncodedUInt();
- usedObjectProperties.SetLength(c);
- for( asUINT n = 0; n < c; n++ )
- {
- asCObjectType *objType = ReadObjectType();
- if( objType == 0 )
- {
- Error(TXT_INVALID_BYTECODE_d);
- break;
- }
- asCString name;
- ReadString(&name);
- // Find the property offset
- bool found = false;
- for( asUINT p = 0; p < objType->properties.GetLength(); p++ )
- {
- if( objType->properties[p]->name == name )
- {
- usedObjectProperties[n].objType = objType;
- usedObjectProperties[n].offset = objType->properties[p]->byteOffset;
- found = true;
- break;
- }
- }
- if( !found )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- }
- short asCReader::FindObjectPropOffset(asWORD index)
- {
- if( index >= usedObjectProperties.GetLength() )
- {
- Error(TXT_INVALID_BYTECODE_d);
- return 0;
- }
- return (short)usedObjectProperties[index].offset;
- }
- 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 = FindObjectType(*(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 )
- {
- // 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 = FindObjectType(*(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 )
- {
- // Translate the index to the true string id
- asWORD *arg = ((asWORD*)&bc[n])+1;
- if( *arg < usedStringConstants.GetLength() )
- *arg = (asWORD)usedStringConstants[*arg];
- else
- {
- Error(TXT_INVALID_BYTECODE_d);
- return;
- }
- }
- else if( c == asBC_CALLBND )
- {
- // Translate the function id
- asUINT *fid = (asUINT*)&bc[n+1];
- if( *fid < module->bindInformations.GetLength() )
- {
- sBindInfo *bi = module->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 global var index to pointer
- asPWORD *index = (asPWORD*)&bc[n+1];
- if( *(asUINT*)index < usedGlobalProperties.GetLength() )
- *(void**)index = usedGlobalProperties[*(asUINT*)index];
- 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 = func->GetObjectTypeOfLocalVar(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 = FindObjectType(*(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]);
- func->scriptData->funcVariableTypes[n] = FindFunction((int)(asPWORD)func->scriptData->funcVariableTypes[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 )
- {
- 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);
- }
- // 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 dt = patternType->engine->GetDataTypeFromTypeId(nextTypeId);
- asUINT size;
- if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_REF)) )
- size = AS_PTR_SIZE*4;
- else
- size = dt.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;
- asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
- if( dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->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_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++ )
- {
- if( func->scriptData->objVariableTypes[n] )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- if( (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_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 func->scriptData->funcVariableTypes[v];
- // 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 )
- return func->parameterTypes[v].GetFuncDef();
- 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;
- // Find out which function that will be called
- asCScriptFunction *calledFunc = 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_CALLINTF ||
- bc == asBC_ALLOC ||
- bc == asBC_CALLBND ||
- bc == asBC_CallPtr )
- {
- 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);
- }
- 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 = 0;
- if( offset > currOffset && calledFunc->GetObjectType() )
- {
- numPtrs++;
- currOffset++;
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- numPtrs++;
- currOffset++;
- }
- for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
- {
- if( offset <= currOffset ) break;
- if( !calledFunc->parameterTypes[p].IsPrimitive() ||
- calledFunc->parameterTypes[p].IsReference() )
- {
- numPtrs++;
- currOffset++;
- // 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;
- }
- }
- asCObjectType *asCReader::FindObjectType(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)
- {
- }
- void asCWriter::WriteData(const void *data, asUINT size)
- {
- asASSERT(size == 1 || size == 2 || size == 4 || size == 8);
- #if defined(AS_BIG_ENDIAN)
- for( asUINT n = 0; n < size; n++ )
- stream->Write(((asBYTE*)data)+n, 1);
- #else
- for( int n = size-1; n >= 0; n-- )
- stream->Write(((asBYTE*)data)+n, 1);
- #endif
- }
- int 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
- WriteData(&stripDebugInfo, sizeof(stripDebugInfo));
- // Store enums
- count = (asUINT)module->enumTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteObjectTypeDeclaration(module->enumTypes[i], 1);
- WriteObjectTypeDeclaration(module->enumTypes[i], 2);
- }
- // Store type declarations first
- count = (asUINT)module->classTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- // Store only the name of the class/interface types
- WriteObjectTypeDeclaration(module->classTypes[i], 1);
- }
- // Store func defs
- count = (asUINT)module->funcDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- WriteFunction(module->funcDefs[i]);
- // Now store all interface methods
- count = (asUINT)module->classTypes.GetLength();
- for( i = 0; i < count; i++ )
- {
- if( module->classTypes[i]->IsInterface() )
- WriteObjectTypeDeclaration(module->classTypes[i], 2);
- }
- // Then store the class methods and behaviours
- for( i = 0; i < count; ++i )
- {
- if( !module->classTypes[i]->IsInterface() )
- WriteObjectTypeDeclaration(module->classTypes[i], 2);
- }
- // Then store the class properties
- for( i = 0; i < count; ++i )
- {
- if( !module->classTypes[i]->IsInterface() )
- WriteObjectTypeDeclaration(module->classTypes[i], 3);
- }
- // Store typedefs
- count = (asUINT)module->typeDefs.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; i++ )
- {
- WriteObjectTypeDeclaration(module->typeDefs[i], 1);
- WriteObjectTypeDeclaration(module->typeDefs[i], 2);
- }
- // scriptGlobals[]
- count = (asUINT)module->scriptGlobals.GetSize();
- WriteEncodedInt64(count);
- asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
- for( ; it; it++ )
- WriteGlobalProperty(*it);
- // scriptFunctions[]
- count = 0;
- for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
- if( module->scriptFunctions[i]->objectType == 0 )
- count++;
- WriteEncodedInt64(count);
- for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
- if( module->scriptFunctions[i]->objectType == 0 )
- WriteFunction(module->scriptFunctions[i]);
- // globalFunctions[]
- count = (int)module->globalFunctions.GetSize();
- asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
- WriteEncodedInt64(count);
- while( funcIt )
- {
- WriteFunction(*funcIt);
- funcIt++;
- }
- // bindInformations[]
- count = (asUINT)module->bindInformations.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- {
- WriteFunction(module->bindInformations[i]->importedFunctionSignature);
- WriteString(&module->bindInformations[i]->importFromModule);
- }
- // usedTypes[]
- count = (asUINT)usedTypes.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- WriteObjectType(usedTypes[i]);
- // usedTypeIds[]
- WriteUsedTypeIds();
- // usedFunctions[]
- WriteUsedFunctions();
- // usedGlobalProperties[]
- WriteUsedGlobalProps();
- // usedStringConstants[]
- WriteUsedStringConstants();
- // usedObjectProperties[]
- WriteUsedObjectProps();
- return asSUCCESS;
- }
- int asCWriter::FindStringConstantIndex(int id)
- {
- asSMapNode<int,int> *cursor = 0;
- if (stringIdToIndexMap.MoveTo(&cursor, id))
- return cursor->value;
- usedStringConstants.PushLast(id);
- int index = int(usedStringConstants.GetLength() - 1);
- stringIdToIndexMap.Insert(id, index);
- return index;
- }
- void asCWriter::WriteUsedStringConstants()
- {
- asUINT count = (asUINT)usedStringConstants.GetLength();
- WriteEncodedInt64(count);
- for( asUINT i = 0; i < count; ++i )
- WriteString(engine->stringConstants[usedStringConstants[i]]);
- }
- void 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
- if( usedFunctions[n] )
- {
- // Is the function from the module or the application?
- c = usedFunctions[n]->module ? 'm' : 'a';
- WriteData(&c, 1);
- WriteFunctionSignature(usedFunctions[n]);
- }
- 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
- 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
- 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]);
- WriteObjectType(func->objectType);
- if( func->objectType )
- {
- asBYTE b = 0;
- b += func->isReadOnly ? 1 : 0;
- b += func->isPrivate ? 2 : 0;
- WriteData(&b, 1);
- }
- 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 )
- {
- // Calculate the adjustment by position lookup table
- CalculateAdjustmentByPos(func);
- WriteByteCode(func);
- asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace);
- WriteEncodedInt64(varSpace);
- count = (asUINT)func->scriptData->objVariablePos.GetLength();
- WriteEncodedInt64(count);
- for( i = 0; i < count; ++i )
- {
- WriteObjectType(func->scriptData->objVariableTypes[i]);
- // TODO: Only write this if the object type is the builtin function type
- WriteEncodedInt64(FindFunctionIndex(func->scriptData->funcVariableTypes[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);
- }
- // 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
- {
- char 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);
- }
- }
- char bits = 0;
- bits += func->isShared ? 1 : 0;
- bits += func->dontCleanUpOnException ? 2 : 0;
- WriteData(&bits,1);
- // Store script section name
- if( !stripDebugInfo )
- {
- if( func->scriptData->scriptSectionIdx >= 0 )
- WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]);
- else
- {
- char c = 0;
- WriteData(&c, 1);
- }
- WriteEncodedInt64(func->scriptData->declaredAt);
- }
- // Store the parameter names
- if( !stripDebugInfo )
- {
- asUINT 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);
- }
- }
- void asCWriter::WriteObjectTypeDeclaration(asCObjectType *ot, int phase)
- {
- if( phase == 1 )
- {
- // name
- WriteString(&ot->name);
- // flags
- WriteData(&ot->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( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->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(ot->size);
- }
- // namespace
- WriteString(&ot->nameSpace->name);
- }
- else if( phase == 2 )
- {
- if( ot->flags & asOBJ_ENUM )
- {
- // enumValues[]
- int size = (int)ot->enumValues.GetLength();
- WriteEncodedInt64(size);
- for( int n = 0; n < size; n++ )
- {
- WriteString(&ot->enumValues[n]->name);
- WriteData(&ot->enumValues[n]->value, 4);
- }
- }
- else if( ot->flags & asOBJ_TYPEDEF )
- {
- eTokenType t = ot->templateSubTypes[0].GetTokenType();
- WriteEncodedInt64(t);
- }
- else
- {
- WriteObjectType(ot->derivedFrom);
- // interfaces[] / interfaceVFTOffsets[]
- // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those?
- int size = (asUINT)ot->interfaces.GetLength();
- WriteEncodedInt64(size);
- asUINT n;
- asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() );
- for( n = 0; n < ot->interfaces.GetLength(); n++ )
- {
- WriteObjectType(ot->interfaces[n]);
- WriteEncodedInt64(ot->interfaceVFTOffsets[n]);
- }
- // behaviours
- // TODO: Default behaviours should just be stored as a indicator
- // to avoid storing the actual function object
- if( !ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM )
- {
- WriteFunction(engine->scriptFunctions[ot->beh.destruct]);
- size = (int)ot->beh.constructors.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[ot->beh.constructors[n]]);
- WriteFunction(engine->scriptFunctions[ot->beh.factories[n]]);
- }
- }
- // methods[]
- // TODO: Avoid storing inherited methods in interfaces, as the reader
- // can add those directly from the base interface
- size = (int)ot->methods.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < ot->methods.GetLength(); n++ )
- {
- WriteFunction(engine->scriptFunctions[ot->methods[n]]);
- }
- // virtualFunctionTable[]
- // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader
- size = (int)ot->virtualFunctionTable.GetLength();
- WriteEncodedInt64(size);
- for( n = 0; n < (asUINT)size; n++ )
- {
- WriteFunction(ot->virtualFunctionTable[n]);
- }
- }
- }
- else if( phase == 3 )
- {
- // properties[]
- asUINT size = (asUINT)ot->properties.GetLength();
- WriteEncodedInt64(size);
- for( asUINT n = 0; n < ot->properties.GetLength(); n++ )
- {
- WriteObjectProperty(ot->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)
- {
- // TODO: All strings should be stored in a separate section, and when
- // they are used an offset into that section should be stored.
- // This will make it unnecessary to store the extra byte to
- // identify new versus old strings.
- if( str->GetLength() == 0 )
- {
- char z = '\0';
- WriteData(&z, 1);
- return;
- }
- // First check if the string hasn't been saved already
- asSMapNode<asCStringPointer, int> *cursor = 0;
- if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str)))
- {
- // Save a reference to the existing string
- char b = 'r';
- WriteData(&b, 1);
- WriteEncodedInt64(cursor->value);
- return;
- }
- // Save a new string
- char b = 'n';
- WriteData(&b, 1);
- asUINT len = (asUINT)str->GetLength();
- WriteEncodedInt64(len);
- stream->Write(str->AddressOf(), (asUINT)len);
- savedStrings.PushLast(*str);
- stringToIdMap.Insert(asCStringPointer(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);
- WriteData(&prop->isPrivate, 1);
- }
- 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 )
- WriteObjectType(dt->GetObjectType());
- struct
- {
- char isObjectHandle :1;
- char isHandleToConst:1;
- char isReference :1;
- char isReadOnly :1;
- } bits = {0};
- bits.isObjectHandle = dt->IsObjectHandle();
- bits.isHandleToConst = dt->IsHandleToConst();
- bits.isReference = dt->IsReference();
- bits.isReadOnly = dt->IsReadOnly();
- WriteData(&bits, 1);
- if( t == ttIdentifier && dt->GetObjectType()->name == "_builtin_function_" )
- {
- WriteFunctionSignature(dt->GetFuncDef());
- }
- }
- void asCWriter::WriteObjectType(asCObjectType* ot)
- {
- char ch;
- if( ot )
- {
- // Check for template instances/specializations
- if( ot->templateSubTypes.GetLength() )
- {
- // Check for list pattern type or template type
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- ch = 'l';
- WriteData(&ch, 1);
- WriteObjectType(ot->templateSubTypes[0].GetObjectType());
- }
- else
- {
- ch = 'a';
- WriteData(&ch, 1);
- WriteString(&ot->name);
- WriteEncodedInt64(ot->templateSubTypes.GetLength());
- for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
- {
- if( ot->templateSubTypes[0].IsObject() || ot->templateSubTypes[0].IsEnumType() )
- {
- ch = 's';
- WriteData(&ch, 1);
- WriteDataType(&ot->templateSubTypes[0]);
- }
- else
- {
- ch = 't';
- WriteData(&ch, 1);
- eTokenType t = ot->templateSubTypes[0].GetTokenType();
- WriteEncodedInt64(t);
- }
- }
- }
- }
- else if( ot->flags & asOBJ_TEMPLATE_SUBTYPE )
- {
- ch = 's';
- WriteData(&ch, 1);
- WriteString(&ot->name);
- }
- else
- {
- ch = 'o';
- WriteData(&ch, 1);
- WriteString(&ot->name);
- WriteString(&ot->nameSpace->name);
- }
- }
- 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++ )
- {
- if( func->scriptData->objVariableTypes[n] )
- {
- // Determine the size the variable currently occupies on the stack
- int size = AS_PTR_SIZE;
- if( (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
- size_t 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++;
- }
- // The last instruction is always a BC_RET. This make it possible to query
- // the number of instructions by checking the last entry in bytecodeNbrByPos
- asASSERT(*(asBYTE*)(bc+length-1) == asBC_RET);
- }
- 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;
- // Find out which function that will be called
- asCScriptFunction *calledFunc = 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_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 )
- {
- // 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 = func->scriptData->funcVariableTypes[v];
- 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 = func->parameterTypes[v].GetFuncDef();
- 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);
- }
- 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 = 0;
- if( offset > currOffset && calledFunc->GetObjectType() )
- {
- numPtrs++;
- currOffset += AS_PTR_SIZE;
- }
- if( offset > currOffset && calledFunc->DoesReturnOnStack() )
- {
- numPtrs++;
- currOffset += AS_PTR_SIZE;
- }
- 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
- numPtrs++;
- currOffset += AS_PTR_SIZE;
- // 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 tmp[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(tmp, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD));
- if( c == asBC_ALLOC ) // PTR_DW_ARG
- {
- // Translate the object type
- asCObjectType *ot = *(asCObjectType**)(tmp+1);
- *(asPWORD*)(tmp+1) = FindObjectTypeIdx(ot);
- // Translate the constructor func id, unless it is 0
- if( *(int*)&tmp[1+AS_PTR_SIZE] != 0 )
- {
- // Increment 1 to the translated function id, as 0 will be reserved for no function
- *(int*)&tmp[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmp[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*)(tmp+1) = FindObjectTypeIdx(*(asCObjectType**)(tmp+1));
- }
- else if( c == asBC_JitEntry ) // PTR_ARG
- {
- // We don't store the JIT argument
- *(asPWORD*)(tmp+1) = 0;
- }
- else if( c == asBC_TYPEID || // DW_ARG
- c == asBC_Cast ) // DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1));
- }
- else if( c == asBC_ADDSi || // W_DW_ARG
- c == asBC_LoadThisR ) // W_DW_ARG
- {
- // Translate property offsets into indices
- *(((short*)tmp)+1) = (short)FindObjectPropIndex(*(((short*)tmp)+1), *(int*)(tmp+1));
- // Translate type ids into indices
- *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1));
- }
- else if( c == asBC_LoadRObjR || // rW_W_DW_ARG
- c == asBC_LoadVObjR ) // rW_W_DW_ARG
- {
- asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmp+2));
- if( ot->flags & asOBJ_LIST_PATTERN )
- {
- // List patterns have a different way of translating the offsets
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- *(((short*)tmp)+2) = (short)listAdj->AdjustOffset(*(((short*)tmp)+2), ot);
- }
- else
- {
- // Translate property offsets into indices
- // TODO: optimize: Pass the object type directly to the method instead of the type id
- *(((short*)tmp)+2) = (short)FindObjectPropIndex(*(((short*)tmp)+2), *(int*)(tmp+2));
- }
- // Translate type ids into indices
- *(int*)(tmp+2) = FindTypeIdIdx(*(int*)(tmp+2));
- }
- else if( c == asBC_COPY ) // W_DW_ARG
- {
- // Translate type ids into indices
- *(int*)(tmp+1) = FindTypeIdIdx(*(int*)(tmp+1));
- // Update the WORDARG0 to 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmp) = 0;
- }
- else if( c == asBC_RET ) // W_ARG
- {
- // Save with arg 0, as this will be recalculated on the target platform
- asBC_WORDARG0(tmp) = 0;
- }
- else if( c == asBC_CALL || // DW_ARG
- c == asBC_CALLINTF || // DW_ARG
- c == asBC_CALLSYS ) // DW_ARG
- {
- // Translate the function id
- *(int*)(tmp+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmp+1)]);
- }
- else if( c == asBC_FuncPtr ) // PTR_ARG
- {
- // Translate the function pointer
- *(asPWORD*)(tmp+1) = FindFunctionIndex(*(asCScriptFunction**)(tmp+1));
- }
- else if( c == asBC_STR ) // W_ARG
- {
- // Translate the string constant id
- asWORD *arg = ((asWORD*)tmp)+1;
- *arg = (asWORD)FindStringConstantIndex(*arg);
- }
- else if( c == asBC_CALLBND ) // DW_ARG
- {
- // Translate the function id
- int funcId = tmp[1];
- for( asUINT n = 0; n < module->bindInformations.GetLength(); n++ )
- if( module->bindInformations[n]->importedFunctionSignature->id == funcId )
- {
- funcId = n;
- break;
- }
- tmp[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
- {
- // Translate global variable pointers into indices
- *(asPWORD*)(tmp+1) = FindGlobalPropPtrIndex(*(void**)(tmp+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*)(tmp+1);
- // Determine instruction number for next instruction and destination
- int bcSeqNum = bytecodeNbrByPos[bc - startBC] + 1;
- asDWORD *targetBC = bc + 2 + offset;
- int targetBcSeqNum = bytecodeNbrByPos[targetBC - startBC];
- // Set the offset in number of instructions
- *(int*)(tmp+1) = targetBcSeqNum - bcSeqNum;
- }
- else if( c == asBC_GETOBJ || // W_ARG
- c == asBC_GETOBJREF ||
- c == asBC_GETREF )
- {
- // Adjust the offset according to the function call that comes after
- asBC_WORDARG0(tmp) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmp), 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(tmp) = 0;
- // Determine the type of the list pattern from the variable
- short var = asBC_WORDARG0(tmp);
- asCObjectType *ot = func->GetObjectTypeOfLocalVar(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**)(tmp+1);
- *(asPWORD*)(tmp+1) = FindObjectTypeIdx(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];
- tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType);
- // Tell the adjuster how many repeated values there are
- listAdj->SetRepeatCount(tmp[2]);
- }
- else if( c == asBC_PshListElmnt ) // W_DW_ARG
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType);
- }
- else if( c == asBC_SetListType )
- {
- // Adjust the offset in the initialization list
- SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1];
- tmp[1] = listAdj->AdjustOffset(tmp[1], listAdj->patternType);
- // Inform the adjuster of the type id of the next element
- listAdj->SetNextType(tmp[2]);
- // Translate the type id
- tmp[2] = FindTypeIdIdx(tmp[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(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp));
- }
- break;
- case asBCTYPE_wW_rW_ARG:
- case asBCTYPE_wW_rW_DW_ARG:
- case asBCTYPE_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp));
- asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp));
- }
- break;
- case asBCTYPE_wW_rW_rW_ARG:
- {
- asBC_SWORDARG0(tmp) = (short)AdjustStackPosition(asBC_SWORDARG0(tmp));
- asBC_SWORDARG1(tmp) = (short)AdjustStackPosition(asBC_SWORDARG1(tmp));
- asBC_SWORDARG2(tmp) = (short)AdjustStackPosition(asBC_SWORDARG2(tmp));
- }
- 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*)tmp)+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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmp[1]);
- }
- break;
- case asBCTYPE_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the argument
- WriteEncodedInt64((int)tmp[1]);
- }
- break;
- case asBCTYPE_DW_DW_ARG:
- {
- // Write the instruction code
- asBYTE b = (asBYTE)c;
- WriteData(&b, 1);
- // Write the dword argument
- WriteEncodedInt64((int)tmp[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmp[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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmp)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- w = *(((short*)tmp)+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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmp)+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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the second argument
- w = *(((short*)tmp)+2);
- WriteEncodedInt64(w);
- // Write the third argument
- int dw = tmp[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*)&tmp[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*)&tmp[1];
- WriteEncodedInt64(qw);
- // Write the second argument
- int dw = tmp[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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the argument
- asQWORD qw = *(asQWORD*)&tmp[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*)tmp)+1);
- WriteEncodedInt64(w);
- // Write the dword argument
- WriteEncodedInt64((int)tmp[1]);
- // Write the dword argument
- WriteEncodedInt64((int)tmp[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(&tmp[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.GetObjectType() && (dt.GetObjectType()->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()
- {
- 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()
- {
- int c = (int)usedGlobalProperties.GetLength();
- WriteEncodedInt64(c);
- for( int n = 0; n < c; n++ )
- {
- asPWORD *p = (asPWORD*)usedGlobalProperties[n];
-
- // First search for the global in the module
- char moduleProp = 0;
- asCGlobalProperty *prop = 0;
- asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
- for( ; it; it++ )
- {
- if( p == (*it)->GetAddressOfValue() )
- {
- prop = (*it);
- moduleProp = 1;
- break;
- }
- }
- // If it is not in the module, it must be an application registered property
- if( !prop )
- {
- asCSymbolTable<asCGlobalProperty>::iterator it = engine->registeredGlobalProps.List();
- for( ; it; it++ )
- {
- if( it->GetAddressOfValue() == p )
- {
- prop = *it;
- break;
- }
- }
- }
- 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
- WriteData(&moduleProp, 1);
- }
- }
- void asCWriter::WriteUsedObjectProps()
- {
- int c = (int)usedObjectProperties.GetLength();
- WriteEncodedInt64(c);
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- asCObjectType *objType = usedObjectProperties[n].objType;
- WriteObjectType(objType);
- // Find the property name
- for( asUINT p = 0; p < objType->properties.GetLength(); p++ )
- {
- if( objType->properties[p]->byteOffset == usedObjectProperties[n].offset )
- {
- WriteString(&objType->properties[p]->name);
- break;
- }
- }
- }
- }
- int asCWriter::FindObjectPropIndex(short offset, int typeId)
- {
- asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId);
- for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ )
- {
- if( usedObjectProperties[n].objType == objType &&
- usedObjectProperties[n].offset == offset )
- return n;
- }
- SObjProp prop = {objType, offset};
- 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::FindObjectTypeIdx(asCObjectType *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
|