| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeByteCodePch.h"
- #include "RegexCommon.h"
- #include "RegexPattern.h"
- #include "Library\RegexHelper.h"
- #include "DataStructures\Option.h"
- #include "DataStructures\ImmutableList.h"
- #include "DataStructures\BufferBuilder.h"
- #include "ByteCode\OpCodeUtilAsmJs.h"
- #include "ByteCode\ByteCodeSerializer.h"
- #include "Language\AsmJSModule.h"
- #include "Library\ES5Array.h"
- void ChakraBinaryBuildDateTimeHash(DWORD * buildDateHash, DWORD * buildTimeHash);
- namespace Js
- {
- const int magicConstant = *(int*)"ChBc";
- const int majorVersionConstant = 1;
- const int minorVersionConstant = 1;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- // These magic constants can be enabled to bracket and check different sections of the serialization
- // file. Turn on BYTE_CODE_MAGIC_CONSTANTS in ByteCodeSerializer.h to enable this.
- const int magicStartOfFunctionBody = *(int*)"fun[";
- const int magicEndOfFunctionBody = *(int*)"]fun";
- const int magicStartOfConstantTable = *(int*)"con[";
- const int magicEndOfConstantTable = *(int*)"]con";
- const int magicStartStringConstant = *(int*)"str[";
- const int magicEndStringConstant = *(int*)"]str";
- const int magicStartOfCacheIdToPropIdMap = *(int*)"cid[";
- const int magicEndOfCacheIdToPropIdMap = *(int*)"]cid";
- const int magicStartOfReferencedPropIdMap = *(int*)"rid[";
- const int magicEndOfReferencedPropIdMap = *(int*)"]rid";
- const int magicStartOfPropertyIdsForScopeSlotArray = *(int*)"scope[";
- const int magicEndOfPropertyIdsForScopeSlotArray = *(int*)"]scope";
- const int magicStartOfDebuggerScopes = *(int*)"dbgscope[";
- const int magicEndOfDebuggerScopes = *(int*)"]dbgscope";
- const int magicStartOfDebuggerScopeProperties = *(int*)"dbgscopeprop[";
- const int magicEndOfDebuggerScopeProperties = *(int*)"]dbgscopeprop";
- const int magicStartOfAux = *(int*)"aux[";
- const int magicEndOfAux = *(int*)"]aux";
- const int magicStartOfAuxVarArray = *(int*)"ava[";
- const int magicEndOfAuxVarArray = *(int*)"]ava";
- const int magicStartOfAuxIntArray = *(int*)"aia[";
- const int magicEndOfAuxIntArray = *(int*)"]aia";
- const int magicStartOfAuxFltArray = *(int*)"afa[";
- const int magicEndOfAuxFltArray = *(int*)"]afa";
- const int magicStartOfAuxPropIdArray = *(int*)"api[";
- const int magicEndOfAuxPropIdArray = *(int*)"]api";
- const int magicStartOfAuxFuncInfoArray = *(int*)"afi[";
- const int magicEndOfAuxFuncInfoArray = *(int*)"]afi";
- const int magicStartOfAsmJsFuncInfo = *(int*)"asmfuncinfo[";
- const int magicEndOfAsmJsFuncInfo = *(int*)"]asmfuncinfo";
- const int magicStartOfAsmJsModuleInfo = *(int*)"asmmodinfo[";
- const int magicEndOfAsmJsModuleInfo = *(int*)"]asmmodinfo";
- #endif
- // Serialized files are architecture specific
- #ifndef VALIDATE_SERIALIZED_BYTECODE
- #if _M_AMD64
- const byte magicArchitecture = 64;
- #else
- const byte magicArchitecture = 32;
- #endif
- #else
- #if _M_AMD64
- const int magicArchitecture = *(int*)"amd";
- #elif _M_IA64
- const int magicArchitecture = *(int*)"ia64";
- #elif _M_ARM
- const int magicArchitecture = *(int*)"arm";
- #elif _M_ARM_64
- const int magicArchitecture = *(int*)"arm64";
- #else
- const int magicArchitecture = *(int*)"x86";
- #endif
- #endif
- // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Byte Code Serializer Versioning scheme
- // Version number is a GUID (128 bits). There are two versioning modes--Engineering and Release. Engineering mode is for day-to-day development. Every time chakra.dll is built a
- // fresh new version is generated by hashing the build date and time. This means that a byte code file saved to disk is exactly tied to the binary that generated it. This works
- // well for QA test runs and buddy tests because there is no chance of effects between runs.
- //
- // Release mode is used when chakra.dll is close to public release where there are actual changes to chakra. The GUID is a fixed number from build-to-build. This number will stay
- // the same for releases where there is no change to chakra.dll. The reason for this is that we don't want to invalidate compatible byte code that has already been cached.
- enum FileVersionScheme : byte
- {
- // Currently Chakra and ChakraCore versioning scheme is different.
- // Same version number for Chakra and ChakraCore doesn't mean they are the same.
- // Give the versioning scheme different value, so that byte code generate from one won't be use in the other.
- #ifdef NTBUILD
- EngineeringVersioningScheme = 10,
- ReleaseVersioningScheme = 20,
- #else
- EngineeringVersioningScheme = 11,
- ReleaseVersioningScheme = 21,
- #endif
- #if (defined(NTBUILD) && CHAKRA_VERSION_RELEASE) || (!defined(NTBUILD) && CHAKRA_CORE_VERSION_RELEASE)
- CurrentFileVersionScheme = ReleaseVersioningScheme
- #else
- CurrentFileVersionScheme = EngineeringVersioningScheme
- #endif
- };
- // it should be in separate file for testing
- #include "byteCodeCacheReleaseFileVersion.h"
- // Used for selective serialization of Function Body fields to make the representation compact
- #define DECLARE_SERIALIZABLE_FIELD(type, name, serializableType) bool has_##name : 1
- #define DECLARE_MANUAL_SERIALIZABLE_FIELD(type, name, serializableType, deserializeHere) bool has_##name: 1
- #define DEFINE_ALL_FIELDS
- struct SerializedFieldList {
- #include "SerializableFunctionFields.h"
- bool has_m_lineNumber: 1;
- bool has_m_columnNumber: 1;
- };
- C_ASSERT(sizeof(GUID)==sizeof(DWORD)*4);
- // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Holds a buffer and size for use by the serializer
- struct ByteBuffer
- {
- uint32 byteCount;
- union
- {
- void * pv;
- const wchar_t * s16;
- const char * s8;
- };
- public:
- ByteBuffer(uint32 byteCount, void * pv)
- : byteCount(byteCount), pv(pv)
- { }
- };
- template<>
- struct DefaultComparer<ByteBuffer*>
- {
- static bool Equals(ByteBuffer const * str1, ByteBuffer const * str2)
- {
- if (str1->byteCount != str2->byteCount)
- {
- return false;
- }
- return memcmp(str1->pv, str2->pv, str1->byteCount)==0;
- }
- static hash_t GetHashCode(ByteBuffer const * str)
- {
- return JsUtil::CharacterBuffer<char>::StaticGetHashCode(str->s8, str->byteCount);
- }
- };
- struct IndexEntry
- {
- BufferBuilderByte* isPropertyRecord;
- int id;
- };
- #pragma pack(push, 1)
- struct StringIndexRecord
- {
- int offset;
- bool isPropertyRecord;
- };
- #pragma pack(pop)
- typedef JsUtil::BaseDictionary<ByteBuffer*, IndexEntry, ArenaAllocator, PrimeSizePolicy, DefaultComparer> TString16ToId;
- // Boolean flags on the FunctionBody
- enum FunctionFlags
- {
- ffIsDeclaration = 0x0001,
- ffHasImplicitArgsIn = 0x0002,
- ffIsAccessor = 0x0004,
- ffIsGlobalFunc = 0x0008,
- ffDontInline = 0x0010,
- ffIsFuncRegistered = 0x0020,
- ffIsStaticNameFunction = 0x0040,
- ffIsStrictMode = 0x0080,
- ffDoBackendArgumentsOptimization = 0x0100,
- ffIsEval = 0x0200,
- ffIsDynamicFunction = 0x0400,
- ffhasAllNonLocalReferenced = 0x0800,
- ffhasSetIsObject = 0x1000,
- ffhasSetCallsEval = 0x2000,
- ffIsNameIdentifierRef = 0x4000,
- ffChildCallsEval = 0x8000,
- ffHasReferenceableBuiltInArguments = 0x10000,
- ffIsNamedFunctionExpression = 0x20000,
- ffIsAsmJsMode = 0x40000,
- ffIsAsmJsFunction = 0x80000
- };
- // Kinds of constant
- enum ConstantType : byte
- {
- ctInt = 1,
- ctString16 = 2,
- ctNull = 3,
- ctUndefined = 4,
- ctNumber = 5,
- ctNullDisplay = 6,
- ctStrictNullDisplay = 7,
- ctTrue = 8,
- ctFalse = 9,
- ctStringTemplateCallsite = 10
- };
- // Try to convert from size_t to uint32. May overflow (and return false) on 64-bit.
- bool TryConvertToUInt32(size_t size, uint32 * out)
- {
- *out = (uint32)size;
- if (sizeof(size) == sizeof(uint32))
- {
- return true;
- }
- Assert(sizeof(size_t) == sizeof(uint64));
- if((uint64)(*out) == size)
- {
- return true;
- }
- AssertMsg(false, "Is it really an offset greater than 32 bits?"); // More likely a bug somewhere.
- return false;
- }
- #if VARIABLE_INT_ENCODING
- template <typename T>
- static const byte * ReadVariableInt(const byte * buffer, size_t remainingBytes, T * value)
- {
- Assert(remainingBytes >= sizeof(byte));
- byte firstByte = *(byte*) buffer;
- if (firstByte >= MIN_SENTINEL)
- {
- Assert(remainingBytes >= sizeof(uint16));
- const byte* locationOfValue = buffer + 1;
- if (firstByte == TWO_BYTE_SENTINEL)
- {
- uint16 twoByteValue = *((serialization_alignment uint16*) locationOfValue);
- Assert(twoByteValue > ONE_BYTE_MAX);
- *value = twoByteValue;
- PHASE_PRINT_TESTTRACE1(Js::VariableIntEncodingPhase, L"TestTrace: VariableIntEncoding (decode)- 2 bytes, value %u\n", *value);
- return buffer + sizeof(uint16) +SENTINEL_BYTE_COUNT;
- }
- else
- {
- Assert(remainingBytes >= sizeof(T));
- Assert(firstByte == FOUR_BYTE_SENTINEL);
- *value = *((serialization_alignment T*) locationOfValue);
- Assert(*value > TWO_BYTE_MAX || *value <= 0);
- PHASE_PRINT_TESTTRACE1(Js::VariableIntEncodingPhase, L"TestTrace: VariableIntEncoding (decode) - 4 bytes, value %u\n", *value);
- return buffer + sizeof(T) +SENTINEL_BYTE_COUNT;
- }
- }
- else
- {
- *value = (T) firstByte;
- PHASE_PRINT_TESTTRACE1(Js::VariableIntEncodingPhase, L"TestTrace: VariableIntEncoding (decode) - 1 byte, value %u\n", *value);
- return buffer + sizeof(byte);
- }
- }
- #endif
- // Compile-time-check some invariants that the file format depends on
- C_ASSERT(sizeof(PropertyId)==sizeof(int32));
- // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Byte Code File Header Layout
- // Offset Size Name Value
- // 0 4 Magic Number "ChBc"
- // 4 4 Total File Size
- // 8 1 File Version Scheme 10 for engineering 20 for release
- // 9 4 Version DWORD 1 jscript minor version GUID quad part 1
- // 13 4 Version DWORD 2 jscript major version GUID quad part 2
- // 17 4 Version DWORD 3 hash of __DATE__ GUID quad part 3
- // 21 4 Version DWORD 4 hash of __TIME__ GUID quad part 4
- // 25 4 Expected Architecture "amd"0, "ia64", "arm"0 or "x86"0
- // 29 4 Expected Function Body Size
- // 33 4 Expected Built In PropertyCount
- // 37 4 Expected Op Code Count
- // 41 4 Size of Original Source Code
- // 45 4 Count of Auxiliary Structures
- // 49 4 Smallest Literal Object ID
- // 53 4 Largest Literal Object ID
- // 57 4 Offset from start of this file
- // to Strings Table
- // 61 4 Offset to Source Spans
- // 65 4 Count of Functions
- // 69 4 Offset to Functions
- // 73 4 Offset to Auxiliary Structures
- // 77 4 Count of Strings
- // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // This is the serializer
- class ByteCodeBufferBuilder
- {
- // Begin File Layout -------------------------------
- ConstantSizedBufferBuilderOf<int32> magic;
- ConstantSizedBufferBuilderOf<int32> totalSize; // The size is unknown when the offsets are calculated so just reserve 4 bytes for this for now to avoid doing two passes to calculate the offsets
- BufferBuilderByte fileVersionKind; // Engineering or Release
- ConstantSizedBufferBuilderOf<int32> V1; // V1-V4 are the parts of the version. It is a fixed version GUID or a per-build version.
- ConstantSizedBufferBuilderOf<int32> V2;
- ConstantSizedBufferBuilderOf<int32> V3;
- ConstantSizedBufferBuilderOf<int32> V4;
- BufferBuilderInt32 architecture;
- BufferBuilderInt32 expectedFunctionBodySize;
- BufferBuilderInt32 expectedBuildInPropertyCount;
- BufferBuilderInt32 expectedOpCodeCount;
- BufferBuilderInt32 originalSourceSize;
- BufferBuilderInt32 originalCharLength;
- BufferBuilderRelativeOffset string16sOffset;
- BufferBuilderRelativeOffset sourceSpansOffset;
- BufferBuilderRelativeOffset lineInfoCacheOffset;
- BufferBuilderRelativeOffset functionsOffset;
- BufferBuilderInt32 string16Count;
- BufferBuilderList string16IndexTable;
- BufferBuilderList string16Table;
- BufferBuilderAligned alignedString16Table;
- BufferBuilderList sourceSpans;
- BufferBuilderInt32 lineInfoCacheCount;
- BufferBuilderRaw lineInfoCache;
- BufferBuilderInt32 functionCount;
- BufferBuilderList functionsTable;
- // End File Layout ---------------------------------
- ArenaAllocator * alloc;
- TString16ToId * string16ToId;
- int nextString16Id;
- int topFunctionId;
- LPCUTF8 utf8Source;
- ScriptContext * scriptContext;
- BufferBuilder * startOfCachedScopeAuxBlock;
- DWORD dwFlags;
- DWORD dwFunctionTableLength;
- BYTE *functionTable;
- //Instead of referencing TotalNumberOfBuiltInProperties directly; or PropertyIds::_countJSOnlyProperty we use this.
- //For library code this will be set to _countJSOnlyProperty and for normal bytecode this will be TotalNumberOfBuiltInProperties
- int builtInPropertyCount;
- bool GenerateLibraryByteCode() const
- {
- return (dwFlags & GENERATE_BYTE_CODE_BUFFER_LIBRARY) != 0;
- }
- bool OmitFunction(int serializationIndex) const
- {
- return functionTable && ((serializationIndex >= (int)dwFunctionTableLength) || !functionTable[serializationIndex]);
- }
- bool GenerateByteCodeForNative(int serializationIndex) const
- {
- return (dwFlags & GENERATE_BYTE_CODE_FOR_NATIVE) != 0;
- }
- public:
- ByteCodeBufferBuilder(uint32 sourceSize, uint32 sourceCharLength, LPCUTF8 utf8Source, DWORD dwFunctionTableLength, BYTE * functionTable, Utf8SourceInfo* sourceInfo, ScriptContext * scriptContext, ArenaAllocator * alloc, DWORD dwFlags, int builtInPropertyCount)
- : magic(L"Magic", magicConstant),
- totalSize(L"Total Size", 0),
- fileVersionKind(L"FileVersionKind", 0),
- V1(L"V1", 0),
- V2(L"V2", 0),
- V3(L"V3", 0),
- V4(L"V4", 0),
- architecture(L"Expected Architecture", magicArchitecture),
- expectedFunctionBodySize(L"Expected Function Body Size", sizeof(unaligned FunctionBody)),
- expectedBuildInPropertyCount(L"Expected Built-in Properties", builtInPropertyCount),
- expectedOpCodeCount(L"Expected Number of OpCodes", (int)OpCode::Count),
- originalSourceSize(L"Source Size", sourceSize),
- originalCharLength(L"Source Char Length", sourceCharLength),
- string16sOffset(L"Offset of String16s", &string16Count),
- sourceSpansOffset(L"Offset of Source Spans", &sourceSpans),
- lineInfoCacheOffset(L"Offset of Source Spans", &lineInfoCacheCount),
- functionCount(L"Function Count", 0),
- functionsOffset(L"Offset of Functions", &functionCount),
- string16Count(L"String16 Count", 0),
- string16IndexTable(L"String16 Indexes"),
- string16Table(L"String16 Table"),
- alignedString16Table(L"Alignment for String16 Table", &string16Table, sizeof(wchar_t)),
- sourceSpans(L"Source Spans"),
- lineInfoCacheCount(L"Line Info Cache", sourceInfo->GetLineOffsetCache()->GetLineCount()),
- lineInfoCache(L"Line Info Cache", lineInfoCacheCount.value * sizeof(JsUtil::LineOffsetCache<Recycler>::LineOffsetCacheItem), (byte *)sourceInfo->GetLineOffsetCache()->GetItems()),
- functionsTable(L"Functions"),
- nextString16Id(builtInPropertyCount), // Reserve the built-in property ids
- topFunctionId(0),
- utf8Source(utf8Source),
- scriptContext(scriptContext),
- startOfCachedScopeAuxBlock(nullptr),
- alloc(alloc),
- dwFlags(dwFlags),
- builtInPropertyCount(builtInPropertyCount),
- dwFunctionTableLength(dwFunctionTableLength),
- functionTable(functionTable)
- {
- if (GenerateLibraryByteCode())
- {
- expectedFunctionBodySize.value = 0;
- expectedOpCodeCount.value = 0;
- }
- // library alaways use the release versioning scheme
- byte actualFileVersionScheme = GenerateLibraryByteCode()? ReleaseVersioningScheme : CurrentFileVersionScheme;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.ForceSerializedBytecodeVersionSchema)
- {
- actualFileVersionScheme = (byte)Js::Configuration::Global.flags.ForceSerializedBytecodeVersionSchema;
- }
- #endif
- fileVersionKind.value = actualFileVersionScheme;
- if (actualFileVersionScheme != ReleaseVersioningScheme)
- {
- Assert(!GenerateLibraryByteCode());
- Assert(actualFileVersionScheme == EngineeringVersioningScheme);
- DWORD jscriptMajor, jscriptMinor, buildDateHash, buildTimeHash;
- Js::VerifyOkCatastrophic(AutoSystemInfo::GetJscriptFileVersion(&jscriptMajor, &jscriptMinor, &buildDateHash, &buildTimeHash));
- V1.value = jscriptMajor;
- V2.value = jscriptMinor;
- V3.value = buildDateHash;
- V4.value = buildTimeHash;
- }
- else
- {
- auto guidDWORDs = (DWORD*)(&byteCodeCacheReleaseFileVersion);
- V1.value = guidDWORDs[0];
- V2.value = guidDWORDs[1];
- V3.value = guidDWORDs[2];
- V4.value = guidDWORDs[3];
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.ForceSerializedBytecodeMajorVersion)
- {
- V1.value = Js::Configuration::Global.flags.ForceSerializedBytecodeMajorVersion;
- V2.value = 0;
- V3.value = 0;
- V4.value = 0;
- }
- #endif
- string16ToId = Anew(alloc, TString16ToId, alloc);
- }
- HRESULT Create(bool allocateBuffer, byte ** buffer, DWORD * bufferBytes)
- {
- BufferBuilderList all(L"Final");
- // Reverse the lists
- string16IndexTable.list = string16IndexTable.list->ReverseCurrentList();
- string16Table.list = string16Table.list->ReverseCurrentList();
- // Prepend all sections (in reverse order because of prepend)
- all.list = all.list->Prepend(&functionsTable, alloc);
- all.list = all.list->Prepend(&functionCount, alloc);
- all.list = all.list->Prepend(&lineInfoCache, alloc);
- all.list = all.list->Prepend(&lineInfoCacheCount, alloc);
- all.list = all.list->Prepend(&alignedString16Table, alloc);
- all.list = all.list->Prepend(&string16IndexTable, alloc);
- all.list = all.list->Prepend(&string16Count, alloc);
- all.list = all.list->Prepend(&functionsOffset, alloc);
- all.list = all.list->Prepend(&sourceSpansOffset, alloc);
- all.list = all.list->Prepend(&lineInfoCacheOffset, alloc);
- all.list = all.list->Prepend(&string16sOffset, alloc);
- all.list = all.list->Prepend(&originalCharLength, alloc);
- all.list = all.list->Prepend(&originalSourceSize, alloc);
- all.list = all.list->Prepend(&expectedOpCodeCount, alloc);
- all.list = all.list->Prepend(&expectedBuildInPropertyCount, alloc);
- all.list = all.list->Prepend(&expectedFunctionBodySize, alloc);
- all.list = all.list->Prepend(&architecture, alloc);
- all.list = all.list->Prepend(&V4, alloc);
- all.list = all.list->Prepend(&V3, alloc);
- all.list = all.list->Prepend(&V2, alloc);
- all.list = all.list->Prepend(&V1, alloc);
- all.list = all.list->Prepend(&fileVersionKind, alloc);
- all.list = all.list->Prepend(&totalSize, alloc);
- all.list = all.list->Prepend(&magic, alloc);
- // Get the string count.
- string16Count.value = nextString16Id - this->builtInPropertyCount;
- // Figure out the size and set all individual offsets
- DWORD size = all.FixOffset(0);
- totalSize.value = size;
- // Allocate the bytes
- if (allocateBuffer)
- {
- *bufferBytes = size;
- *buffer = (byte*)CoTaskMemAlloc(*bufferBytes);
- if (*buffer == nullptr)
- {
- return E_OUTOFMEMORY;
- }
- }
- if (size > *bufferBytes)
- {
- *bufferBytes = size;
- return *buffer == nullptr ? S_OK : E_INVALIDARG;
- }
- else
- {
- // Write into the buffer
- all.Write(*buffer, *bufferBytes);
- *bufferBytes = size;
- DebugOnly(Output::Flush()); // Flush trace
- return S_OK;
- }
- }
- bool isBuiltinProperty(PropertyId pid) {
- if (pid < this->builtInPropertyCount || pid==/*nil*/0xffffffff)
- {
- return true;
- }
- return false;
- };
- PropertyId encodeNonBuiltinPropertyId(PropertyId id) {
- const PropertyRecord * propertyValue = nullptr;
- Assert(id >= this->builtInPropertyCount); // Shouldn't have gotten a builtin property id
- propertyValue = scriptContext->GetPropertyName(id);
- id = GetIdOfPropertyRecord(propertyValue) - this->builtInPropertyCount;
- return id ^ SERIALIZER_OBSCURE_NONBUILTIN_PROPERTY_ID;
- };
- PropertyId encodePossiblyBuiltInPropertyId(PropertyId id) {
- const PropertyRecord * propertyValue = nullptr;
- if(id >= this->builtInPropertyCount)
- {
- propertyValue = scriptContext->GetPropertyName(id);
- id = GetIdOfPropertyRecord(propertyValue);
- }
- return id ^ SERIALIZER_OBSCURE_PROPERTY_ID;
- };
- int GetString16Id(ByteBuffer * bb, bool isPropertyRecord = false)
- {
- IndexEntry indexEntry;
- if (!string16ToId->TryGetValue(bb, &indexEntry))
- {
- auto sizeInBytes = bb->byteCount;
- auto stringEntry = Anew(alloc, BufferBuilderRaw, L"String16", sizeInBytes, (const byte *)bb->pv); // Writing the terminator even though it is computable so that this memory can be used as-is when deserialized
- string16Table.list = string16Table.list->Prepend(stringEntry, alloc);
- if (string16IndexTable.list == nullptr)
- {
- // First item in the list is the first string.
- auto stringIndexEntry = Anew(alloc, BufferBuilderRelativeOffset, L"First String16 Index", stringEntry);
- string16IndexTable.list = string16IndexTable.list->Prepend(stringIndexEntry, alloc);
- PrependByte(string16IndexTable, L"isPropertyRecord", (BYTE)isPropertyRecord);
- }
- // Get a pointer to the previous entry of isPropertyRecord
- indexEntry.isPropertyRecord = static_cast<BufferBuilderByte*>(string16IndexTable.list->First());
- // Subsequent strings indexes point one past the end. This way, the size is always computable by subtracting indexes.
- auto stringIndexEntry = Anew(alloc, BufferBuilderRelativeOffset, L"String16 Index", stringEntry, sizeInBytes);
- string16IndexTable.list = string16IndexTable.list->Prepend(stringIndexEntry, alloc);
- // By default, mark the next string to be not a property record.
- PrependByte(string16IndexTable, L"isPropertyRecord", (BYTE)false);
- indexEntry.id = nextString16Id;
- string16ToId->Add(bb, indexEntry);
- ++nextString16Id;
- }
- // A string might start off as not being a property record and later becoming one. Hence,
- // we set only if the transition is from false => true. Once it is a property record, it cannot go back.
- if(isPropertyRecord)
- {
- indexEntry.isPropertyRecord->value = isPropertyRecord;
- }
- return indexEntry.id;
- }
- uint32 PrependRelativeOffset(BufferBuilderList & builder, LPCWSTR clue, BufferBuilder * pointedTo)
- {
- auto entry = Anew(alloc, BufferBuilderRelativeOffset, clue, pointedTo, 0);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(int32);
- }
- uint32 PrependInt16(BufferBuilderList & builder, LPCWSTR clue, int16 value, BufferBuilderInt16 ** entryOut = nullptr)
- {
- auto entry = Anew(alloc, BufferBuilderInt16, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- if (entryOut)
- {
- *entryOut = entry;
- }
- return sizeof(int16);
- }
- uint32 PrependInt32(BufferBuilderList & builder, LPCWSTR clue, int value, BufferBuilderInt32 ** entryOut = nullptr)
- {
- auto entry = Anew(alloc, BufferBuilderInt32, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- if (entryOut)
- {
- *entryOut = entry;
- }
- return sizeof(int32);
- }
- uint32 PrependConstantInt16(BufferBuilderList & builder, LPCWSTR clue, int16 value, ConstantSizedBufferBuilderOf<int16> ** entryOut = nullptr)
- {
- auto entry = Anew(alloc, ConstantSizedBufferBuilderOf<int16>, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- if (entryOut)
- {
- *entryOut = entry;
- }
- return sizeof(int16);
- }
- uint32 PrependConstantInt32(BufferBuilderList & builder, LPCWSTR clue, int value, ConstantSizedBufferBuilderOf<int> ** entryOut = nullptr)
- {
- auto entry = Anew(alloc, ConstantSizedBufferBuilderOf<int>, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- if (entryOut)
- {
- *entryOut = entry;
- }
- return sizeof(int32);
- }
- uint32 PrependConstantInt64(BufferBuilderList & builder, LPCWSTR clue, int64 value, ConstantSizedBufferBuilderOf<int64> ** entryOut = nullptr)
- {
- auto entry = Anew(alloc, ConstantSizedBufferBuilderOf<int64>, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- if (entryOut)
- {
- *entryOut = entry;
- }
- return sizeof(int64);
- }
- uint32 PrependByte(BufferBuilderList & builder, LPCWSTR clue, byte value)
- {
- auto entry = Anew(alloc, BufferBuilderByte, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(byte);
- }
- uint32 PrependFunctionBodyFlags(BufferBuilderList & builder, LPCWSTR clue, FunctionBody::FunctionBodyFlags value)
- {
- return PrependByte(builder, clue, (byte) value);
- }
- uint32 PrependBool(BufferBuilderList & builder, LPCWSTR clue, bool value)
- {
- return PrependByte(builder, clue, (byte) value);
- }
- uint32 PrependFloat(BufferBuilderList & builder, LPCWSTR clue, float value)
- {
- auto entry = Anew(alloc, BufferBuilderFloat, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(float);
- }
- uint32 PrependDouble(BufferBuilderList & builder, LPCWSTR clue, double value)
- {
- auto entry = Anew(alloc, BufferBuilderDouble, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(double);
- }
- uint32 PrependSIMDValue(BufferBuilderList & builder, LPCWSTR clue, SIMDValue value)
- {
- auto entry = Anew(alloc, BufferBuilderSIMD, clue, value);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(SIMDValue);
- }
- uint32 PrependString16(__in BufferBuilderList & builder, __in_nz LPCWSTR clue, __in_bcount_opt(byteLength) LPCWSTR sz, __in uint32 byteLength)
- {
- if (sz != nullptr)
- {
- auto bb = Anew(alloc, ByteBuffer, byteLength, (void*)sz); // Includes trailing null
- return PrependInt32(builder, clue, GetString16Id(bb));
- }
- else
- {
- return PrependInt32(builder, clue, 0xffffffff);
- }
- }
- uint32 PrependByteBuffer(BufferBuilderList & builder, LPCWSTR clue, ByteBuffer * bb)
- {
- auto id = GetString16Id(bb);
- return PrependInt32(builder, clue, id);
- }
- int GetIdOfPropertyRecord(const PropertyRecord * propertyRecord)
- {
- AssertMsg(!propertyRecord->IsSymbol(), "bytecode serializer does not currently handle non-built-in symbol PropertyRecords");
- size_t byteCount = ((size_t)propertyRecord->GetLength() + 1) * sizeof(wchar_t);
- if (byteCount > UINT_MAX)
- {
- // We should never see property record that big
- Js::Throw::InternalError();
- }
- auto buffer = propertyRecord->GetBuffer();
- #if DBG
- const PropertyRecord * propertyRecordCheck;
- scriptContext->FindPropertyRecord(buffer, propertyRecord->GetLength(), &propertyRecordCheck);
- Assert(propertyRecordCheck == propertyRecord);
- #endif
- auto bb = Anew(alloc, ByteBuffer, (uint32)byteCount, (void*)buffer);
- return GetString16Id(bb, /*isPropertyRecord=*/ true);
- }
- template<typename TLayout>
- unaligned TLayout * DuplicateLayout(unaligned const TLayout * in)
- {
- auto sizeOfLayout = sizeof(unaligned TLayout);
- auto newLayout = AnewArray(alloc, byte, sizeOfLayout);
- js_memcpy_s(newLayout, sizeOfLayout, in, sizeOfLayout);
- return (unaligned TLayout * )newLayout;
- }
- template<typename T>
- uint32 Prepend(BufferBuilderList & builder, LPCWSTR clue, T * t)
- {
- auto block = Anew(alloc, BufferBuilderRaw, clue, sizeof(serialization_alignment T), (const byte*)t);
- builder.list = builder.list->Prepend(block, alloc);
- return sizeof(serialization_alignment T);
- }
- struct AuxRecord
- {
- SerializedAuxiliaryKind kind;
- uint offset;
- };
- #ifndef TEMP_DISABLE_ASMJS
- HRESULT RewriteAsmJsByteCodesInto(BufferBuilderList & builder, LPCWSTR clue, FunctionBody * function, ByteBlock * byteBlock)
- {
- SListCounted<AuxRecord> auxRecords(alloc);
- Assert(!OmitFunction(function->GetSerializationIndex()));
- auto finalSize = Anew(alloc, BufferBuilderInt32, L"Final Byte Code Size", 0); // Initially set to zero
- builder.list = builder.list->Prepend(finalSize, alloc);
- ByteCodeReader reader;
- reader.Create(function);
- uint32 size = 0;
- const byte * opStart = nullptr;
- bool cantGenerate = false;
- auto saveBlock = [&]() {
- uint32 byteCount;
- if (TryConvertToUInt32(reader.GetIP() - opStart, &byteCount))
- {
- if (!GenerateByteCodeForNative(function->GetSerializationIndex()))
- {
- auto block = Anew(alloc, BufferBuilderRaw, clue, byteCount, (const byte*)opStart);
- builder.list = builder.list->Prepend(block, alloc);
- size += byteCount;
- }
- }
- else
- {
- AssertMsg(false, "Unlikely: byte code size overflows 32 bits");
- cantGenerate = true;
- }
- };
- Assert(!function->HasCachedScopePropIds());
- while (!cantGenerate)
- {
- opStart = reader.GetIP();
- opStart; // For prefast. It can't figure out that opStart is captured in saveBlock above.
- LayoutSize layoutSize;
- OpCodeAsmJs op = (OpCodeAsmJs)reader.ReadOp(layoutSize);
- if (op == OpCodeAsmJs::EndOfBlock)
- {
- saveBlock();
- break;
- }
- OpLayoutTypeAsmJs layoutType = OpCodeUtilAsmJs::GetOpCodeLayout(op);
- switch (layoutType)
- {
- #define DEFAULT_LAYOUT(op) \
- case OpLayoutTypeAsmJs::##op: { \
- Assert(layoutSize == SmallLayout); \
- reader.##op(); \
- saveBlock(); \
- break; }
- #define DEFAULT_LAYOUT_WITH_ONEBYTE(op) \
- case OpLayoutTypeAsmJs::##op: { \
- switch (layoutSize) \
- { \
- case SmallLayout: \
- reader.##op##_Small(); \
- break; \
- case MediumLayout: \
- reader.##op##_Medium(); \
- break; \
- case LargeLayout: \
- reader.##op##_Large(); \
- break; \
- default: \
- Assume(UNREACHED); \
- } \
- saveBlock(); \
- break; }
- DEFAULT_LAYOUT(Empty);
- DEFAULT_LAYOUT(StartCall);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementSlot);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmTypedArr);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmCall);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg5);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg6);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg7);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmReg2IntConst1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Double1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Double1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Double1Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Double1Reg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float1Reg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Reg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Double1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Double2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Float2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Const1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Double2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float1Double1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Double3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmUnsigned1);
- DEFAULT_LAYOUT(AsmBr);
- DEFAULT_LAYOUT_WITH_ONEBYTE(BrInt1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(BrInt2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_1Float4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_2Int4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_3Int4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_1Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_2Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_1Float64x2_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_1Int32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_1Int32x4_1Float32x4_2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Float32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Float32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_1Int4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_2Int4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_3Int4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_2Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_2Int2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Int32x4_1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float32x4_2Int1Float1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float1Float32x4_1Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Int32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_1Float64x2_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int32x4_1Float32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Int32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_1Double2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_1Double1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_2Double1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_2Int2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_3Int2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_1Float32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_1Int32x4_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Float64x2_1Int32x4_1Float64x2_2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1Float64x2_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Int1Float64x2_1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(AsmSimdTypedArr);
- #undef DEFAULT_LAYOUT
- #undef DEFAULT_LAYOUT_WITH_ONEBYTE
- default:
- AssertMsg(false, "Unknown OpLayout");
- cantGenerate = true;
- break;
- }
- }
- if (cantGenerate)
- {
- return ByteCodeSerializer::CantGenerate;
- }
- if (size != byteBlock->GetLength() && !GenerateByteCodeForNative(function->GetSerializationIndex()))
- {
- Assert(size == byteBlock->GetLength());
- return ByteCodeSerializer::CantGenerate;
- }
- finalSize->value = size;
- RewriteAuxiliaryInto(builder, auxRecords, reader, function);
- return S_OK;
- }
- #endif
- HRESULT RewriteByteCodesInto(BufferBuilderList & builder, LPCWSTR clue, FunctionBody * function, ByteBlock * byteBlock)
- {
- SListCounted<AuxRecord> auxRecords(alloc);
- Assert(!OmitFunction(function->GetSerializationIndex()));
- auto finalSize = Anew(alloc, BufferBuilderInt32, L"Final Byte Code Size", 0); // Initially set to zero
- builder.list = builder.list->Prepend(finalSize, alloc);
- ByteCodeReader reader;
- reader.Create(function);
- uint32 size = 0;
- const byte * opStart = nullptr;
- bool cantGenerate = false;
- auto saveBlock = [&]() {
- uint32 byteCount;
- if (TryConvertToUInt32(reader.GetIP()-opStart, &byteCount))
- {
- if (!GenerateByteCodeForNative(function->GetSerializationIndex()))
- {
- auto block = Anew(alloc, BufferBuilderRaw, clue, byteCount, (const byte*) opStart);
- builder.list = builder.list->Prepend(block, alloc);
- size += byteCount;
- }
- }
- else
- {
- AssertMsg(false, "Unlikely: byte code size overflows 32 bits");
- cantGenerate = true;
- }
- };
- if (function->HasCachedScopePropIds())
- {
- AuxRecord record = { sakPropertyIdArrayForCachedScope, 0 };
- auxRecords.Prepend(record);
- }
- while(!cantGenerate)
- {
- opStart = reader.GetIP();
- opStart; // For prefast. It can't figure out that opStart is captured in saveBlock above.
- LayoutSize layoutSize;
- OpCode op = reader.ReadOp(layoutSize);
- if (op == OpCode::EndOfBlock)
- {
- saveBlock();
- break;
- }
- OpLayoutType layoutType = OpCodeUtil::GetOpCodeLayout(op);
- switch (layoutType)
- {
- #define DEFAULT_LAYOUT(op) \
- case OpLayoutType::##op: { \
- Assert(layoutSize == SmallLayout); \
- reader.##op(); \
- saveBlock(); \
- break; }
- #define DEFAULT_LAYOUT_WITH_ONEBYTE(op) \
- case OpLayoutType::##op: { \
- switch (layoutSize) \
- { \
- case SmallLayout: \
- reader.##op##_Small(); \
- break; \
- case MediumLayout: \
- reader.##op##_Medium(); \
- break; \
- case LargeLayout: \
- reader.##op##_Large(); \
- break; \
- default: \
- Assert(false); \
- __assume(false); \
- } \
- saveBlock(); \
- break; }
- #define DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(op) \
- DEFAULT_LAYOUT_WITH_ONEBYTE(op); \
- DEFAULT_LAYOUT_WITH_ONEBYTE(Profiled##op)
- DEFAULT_LAYOUT(Empty);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(Reg2);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(Reg2WithICIndex);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(Reg3);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg4);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg5);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg3C);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(Arg);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ArgNoSrc);
- DEFAULT_LAYOUT(Br);
- #ifdef BYTECODE_BRANCH_ISLAND
- DEFAULT_LAYOUT(BrLong);
- #endif
- DEFAULT_LAYOUT(BrS);
- DEFAULT_LAYOUT_WITH_ONEBYTE(BrReg1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(BrReg2);
- DEFAULT_LAYOUT(StartCall);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Profiled2CallI);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(CallI);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(CallIFlags);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(CallIWithICIndex);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(CallIFlagsWithICIndex);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(ElementI);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementUnsigned1);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(ElementSlot);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(ElementSlotI1);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(ElementSlotI2);
- DEFAULT_LAYOUT(W1);
- DEFAULT_LAYOUT(Reg1Int2);
- DEFAULT_LAYOUT_WITH_ONEBYTE_AND_PROFILED(Reg1Unsigned1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg2Int1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Unsigned1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementCP);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementRootCP);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementP);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementPIndexed);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg2B1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Reg3B1);
- DEFAULT_LAYOUT_WITH_ONEBYTE(Class);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementU);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementRootU);
- DEFAULT_LAYOUT(BrProperty);
- DEFAULT_LAYOUT(BrEnvProperty);
- DEFAULT_LAYOUT(BrLocalProperty);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementC2);
- DEFAULT_LAYOUT_WITH_ONEBYTE(ElementC);
- #undef DEFAULT_LAYOUT
- #undef DEFAULT_LAYOUT_WITH_ONEBYTE
- case OpLayoutType::AuxNoReg:
- switch (op)
- {
- case OpCode::InitCachedFuncs:
- {
- auto layout = reader.AuxNoReg();
- AuxRecord record = { sakFuncInfoArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::CommitScope:
- {
- // The propertyId array should be saved by the InitCacheScope
- auto layout = reader.AuxNoReg();
- Assert(layout);
- saveBlock();
- break;
- }
- default:
- AssertMsg(false, "Unknown OpCode for OpLayoutType::AuxNoReg");
- cantGenerate = true;
- break;
- }
- break;
- case OpLayoutType::Auxiliary:
- switch (op)
- {
- case OpCode::NewScObjectLiteral:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakPropertyIdArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::LdPropIds:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakPropertyIdArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::StArrSegItem_A:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakVarArrayIntCount, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::NewScObject_A:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakVarArrayVarCount, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::NewScIntArray:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakIntArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::NewScFltArray:
- {
- auto layout = reader.Auxiliary();
- AuxRecord record = { sakFloatArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- default:
- AssertMsg(false, "Unknown OpCode for OpLayoutType::Auxiliary");
- cantGenerate = true;
- break;
- }
- break;
- case OpLayoutType::ProfiledAuxiliary:
- switch (op)
- {
- case OpCode::ProfiledNewScIntArray:
- {
- auto layout = reader.ProfiledAuxiliary();
- AuxRecord record = { sakIntArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- case OpCode::ProfiledNewScFltArray:
- {
- auto layout = reader.ProfiledAuxiliary();
- AuxRecord record = { sakFloatArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- default:
- AssertMsg(false, "Unknown OpCode for OpLayoutType::ProfiledAuxiliary");
- cantGenerate = true;
- break;
- }
- break;
- case OpLayoutType::Reg2Aux:
- switch (op)
- {
- case OpCode::SpreadArrayLiteral:
- {
- auto layout = reader.Reg2Aux();
- AuxRecord record = { sakIntArray, layout->Offset };
- auxRecords.Prepend(record);
- saveBlock();
- break;
- }
- default:
- AssertMsg(false, "Unknown OpCode for OpLayoutType::Reg2Aux");
- cantGenerate = true;
- break;
- }
- break;
- #define STORE_SPREAD_AUX_ARGS \
- if (!(layout->Options & CallIExtended_SpreadArgs)) \
- { \
- break; \
- } \
- AuxRecord record = { sakIntArray, layout->SpreadAuxOffset }; \
- auxRecords.Prepend(record)
- #define CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(op) \
- case OpLayoutType::##op: \
- { \
- switch (layoutSize) \
- { \
- case SmallLayout: \
- { \
- auto layout = reader.##op##_Small(); \
- STORE_SPREAD_AUX_ARGS; \
- break; \
- } \
- case MediumLayout: \
- { \
- auto layout = reader.##op##_Medium(); \
- STORE_SPREAD_AUX_ARGS; \
- break; \
- } \
- case LargeLayout: \
- { \
- auto layout = reader.##op##_Large(); \
- STORE_SPREAD_AUX_ARGS; \
- break; \
- } \
- default: \
- Assert(false); \
- __assume(false); \
- } \
- saveBlock(); \
- break; \
- }
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(CallIExtended)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(CallIExtendedFlags)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(ProfiledCallIExtended)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(ProfiledCallIExtendedFlags)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(Profiled2CallIExtended)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(ProfiledCallIExtendedWithICIndex)
- CALLIEXTENDED_LAYOUT_WITH_ONEBYTE(ProfiledCallIExtendedFlagsWithICIndex)
- default:
- AssertMsg(false, "Unknown OpLayout");
- cantGenerate = true;
- break;
- }
- }
- if (cantGenerate)
- {
- return ByteCodeSerializer::CantGenerate;
- }
- if (size != byteBlock->GetLength() && !GenerateByteCodeForNative(function->GetSerializationIndex()))
- {
- Assert(size == byteBlock->GetLength());
- return ByteCodeSerializer::CantGenerate;
- }
- finalSize->value = size;
- RewriteAuxiliaryInto(builder, auxRecords, reader, function);
- return S_OK;
- }
- void RewriteAuxiliaryInto(BufferBuilderList& builder, SListCounted<AuxRecord> const& auxRecordList,
- ByteCodeReader& reader, FunctionBody * functionBody)
- {
- uint count = auxRecordList.Count();
- PrependInt32(builder, L"Auxiliary Structure Count", count);
- if (count == 0)
- {
- return;
- }
- auto writeAuxVarArray = [&](uint offset, bool isVarCount, int count, const Var * elements) {
- typedef serialization_alignment SerializedVarArray T;
- T header(offset, isVarCount, count);
- auto block = Anew(alloc, ConstantSizedBufferBuilderOf<T>, L"Var Array", header);
- builder.list = builder.list->Prepend(block, alloc);
- for (int i=0;i<count; i++)
- {
- auto var = elements[i];
- PrependVarConstant(builder, var);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Magic end of aux var array", magicEndOfAuxVarArray);
- PrependInt32(builder, L"Magic end of aux", magicEndOfAux);
- #endif
- };
- auto writeAuxVarArrayIntCount = [&](uint offset) {
- const AuxArray<Var> * varArray = reader.ReadAuxArray<Var>(offset, functionBody);
- int count = varArray->count;
- const Var * elements = varArray->elements;
- writeAuxVarArray(offset, false, count, elements);
- };
- auto writeAuxVarArrayVarCount = [&](uint offset) {
- const VarArrayVarCount * varArray = reader.ReadVarArrayVarCount(offset, functionBody);
- int count = Js::TaggedInt::ToInt32(varArray->count);
- const Var * elements = varArray->elements;
- writeAuxVarArray(offset, true, count, elements);
- };
- auto writeAuxIntArray = [&](uint offset) -> BufferBuilder* {
- const AuxArray<int32> *ints = reader.ReadAuxArray<int32>(offset, functionBody);
- int count = ints->count;
- const int32 * elements = ints->elements;
- typedef serialization_alignment SerializedIntArray T;
- T header(offset, count);
- auto block = Anew(alloc, ConstantSizedBufferBuilderOf<T>, L"Int Array", header);
- builder.list = builder.list->Prepend(block, alloc);
- for (int i=0;i<count; i++)
- {
- auto value = elements[i];
- PrependConstantInt32(builder, L"Integer Constant Value", value);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Magic end of aux int array", magicEndOfAuxIntArray);
- PrependInt32(builder, L"Magic end of aux", magicEndOfAux);
- #endif
- return block;
- };
- auto writeAuxFloatArray = [&](uint offset) -> BufferBuilder* {
- const AuxArray<double> *doubles = reader.ReadAuxArray<double>(offset, functionBody);
- int count = doubles->count;
- const double * elements = doubles->elements;
- typedef serialization_alignment SerializedFloatArray T;
- T header(offset, count);
- auto block = Anew(alloc, ConstantSizedBufferBuilderOf<T>, L"Float Array", header);
- builder.list = builder.list->Prepend(block, alloc);
- for (int i=0;i<count; i++)
- {
- auto value = elements[i];
- PrependDouble(builder, L"Number Constant Value", value);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Magic end of aux float array", magicEndOfAuxFltArray);
- PrependInt32(builder, L"Magic end of aux", magicEndOfAux);
- #endif
- return block;
- };
- auto writeAuxPropertyIdArray = [&](uint offset, uint32 extraSlots) -> BufferBuilder* {
- const PropertyIdArray * propIds = reader.ReadPropertyIdArray(offset, functionBody, extraSlots);
- typedef serialization_alignment SerializedPropertyIdArray T;
- T header(offset, propIds->count, extraSlots, propIds->hadDuplicates, propIds->has__proto__);
- auto block = Anew(alloc, ConstantSizedBufferBuilderOf<T>, L"Property Id Array", header);
- builder.list = builder.list->Prepend(block, alloc);
- for (uint32 i=0; i<propIds->count; i++)
- {
- auto original = propIds->elements[i];
- auto encoded = encodePossiblyBuiltInPropertyId(original);
- PrependConstantInt32(builder, L"Encoded Property Id", encoded);
- }
- auto slots = propIds->elements + propIds->count;
- for(uint32 i=0; i<extraSlots; i++)
- {
- PrependConstantInt32(builder, L"Extra Slot", slots[i]);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Magic end of aux section", magicEndOfAuxPropIdArray);
- PrependInt32(builder, L"Magic end of aux", magicEndOfAux);
- #endif
- return block;
- };
- auto writeAuxFuncInfoArray = [&](uint offset) -> BufferBuilder* {
- const FuncInfoArray * funcInfos = reader.ReadAuxArray<FuncInfoEntry>(offset, functionBody);
- typedef serialization_alignment SerializedFuncInfoArray T;
- T header(offset, funcInfos->count);
- auto block = Anew(alloc, ConstantSizedBufferBuilderOf<T>, L"Funcinfo Array", header);
- builder.list = builder.list->Prepend(block, alloc);
- for (uint32 i=0; i<funcInfos->count; i++)
- {
- auto funcInfo = funcInfos->elements[i];
- PrependConstantInt32(builder, L"FuncInfo nestedIndex", funcInfo.nestedIndex);
- PrependConstantInt32(builder, L"FuncInfo scopeSlot", funcInfo.scopeSlot);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Magic end of aux section", magicEndOfAuxFuncInfoArray);
- PrependInt32(builder, L"Magic end of aux", magicEndOfAux);
- #endif
- return block;
- };
- PrependInt32(builder, L"Auxiliary Size",
- functionBody->GetAuxiliaryData()? functionBody->GetAuxiliaryData()->GetLength() : 0);
- PrependInt32(builder, L"Auxiliary Context Size",
- functionBody->GetAuxiliaryContextData()? functionBody->GetAuxiliaryContextData()->GetLength() : 0);
- auxRecordList.Map([&](AuxRecord const& auxRecord)
- {
- switch (auxRecord.kind)
- {
- default:
- AssertMsg(false, "Unexpected auxiliary kind");
- Throw::FatalInternalError();
- break;
- case sakVarArrayIntCount:
- writeAuxVarArrayIntCount(auxRecord.offset);
- break;
- case sakVarArrayVarCount:
- writeAuxVarArrayVarCount(auxRecord.offset);
- break;
- case sakIntArray:
- writeAuxIntArray(auxRecord.offset);
- break;
- case sakFloatArray:
- writeAuxFloatArray(auxRecord.offset);
- break;
- case sakPropertyIdArray:
- writeAuxPropertyIdArray(auxRecord.offset, 0);
- break;
- case sakPropertyIdArrayForCachedScope:
- writeAuxPropertyIdArray(auxRecord.offset, ActivationObjectEx::ExtraSlotCount());
- break;
- case sakFuncInfoArray:
- writeAuxFuncInfoArray(auxRecord.offset);
- break;
- };
- });
- }
- uint32 PrependStringConstant(BufferBuilderList & builder, Var var)
- {
- auto str = JavascriptString::FromVar(var);
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start String Constant", magicStartStringConstant);
- #endif
- auto bb = Anew(alloc, ByteBuffer, (str->GetLength() + 1) * sizeof(wchar_t), (void*)str->GetSz());
- size += PrependByteBuffer(builder, L"String Constant 16 Value", bb);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End String Constant", magicEndStringConstant);
- #endif
- return size;
- }
- uint32 PrependStringTemplateCallsiteConstant(BufferBuilderList & builder, Var var)
- {
- ES5Array* callsite = ES5Array::FromVar(var);
- Var element = nullptr;
- auto size = PrependInt32(builder, L"String Template Callsite Constant String Count", (int)callsite->GetLength());
- for (uint32 i = 0; i < callsite->GetLength(); i++)
- {
- callsite->DirectGetItemAt(i, &element);
- size += PrependStringConstant(builder, element);
- }
- Var rawVar = JavascriptOperators::OP_GetProperty(callsite, Js::PropertyIds::raw, callsite->GetScriptContext());
- ES5Array* rawArray = ES5Array::FromVar(rawVar);
- for (uint32 i = 0; i < rawArray->GetLength(); i++)
- {
- rawArray->DirectGetItemAt(i, &element);
- size += PrependStringConstant(builder, element);
- }
- return size;
- }
- uint32 PrependVarConstant(BufferBuilderList & builder, Var var)
- {
- if (var == (Js::Var)&Js::NullFrameDisplay)
- {
- return PrependByte(builder, L"Null Frame Display", ctNullDisplay);
- }
- else if (var == (Js::Var)&Js::StrictNullFrameDisplay)
- {
- return PrependByte(builder, L"Strict Null Frame Display", ctStrictNullDisplay);
- }
- auto typeId = JavascriptOperators::GetTypeId(var);
- switch (typeId)
- {
- case TypeIds_Undefined:
- return PrependByte(builder, L"Undefined Constant", ctUndefined);
- case TypeIds_Null:
- return PrependByte(builder, L"Null Constant", ctNull);
- case TypeIds_Boolean:
- return PrependByte(builder, L"Boolean Constant", JavascriptBoolean::FromVar(var)->GetValue()? ctTrue : ctFalse);
- case TypeIds_Number:
- {
- auto size = PrependByte(builder, L"Number Constant", ctNumber);
- return size + PrependDouble(builder, L"Number Constant Value", JavascriptNumber::GetValue(var));
- }
- case TypeIds_Integer:
- {
- auto size = PrependByte(builder, L"Integer Constant", ctInt);
- return size + PrependConstantInt32(builder, L"Integer Constant Value", TaggedInt::ToInt32(var));
- }
- case TypeIds_String:
- {
- auto size = PrependByte(builder, L"String Constant 16", ctString16);
- return size + PrependStringConstant(builder, var);
- }
- case TypeIds_ES5Array:
- {
- // ES5Array objects in the constant table are always string template callsite objects.
- // If we later put other ES5Array objects in the constant table, we'll need another way
- // to decide the constant type.
- auto size = PrependByte(builder, L"String Template Callsite Constant", ctStringTemplateCallsite);
- return size + PrependStringTemplateCallsiteConstant(builder, var);
- }
- default:
- AssertMsg(UNREACHED, "Unexpected object type in AddConstantTable");
- Throw::FatalInternalError();
- }
- }
- #ifndef TEMP_DISABLE_ASMJS
- uint32 AddAsmJsConstantTable(BufferBuilderList & builder, FunctionBody * function)
- {
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start Constant Table", magicStartOfConstantTable);
- #endif
- uint32 intConstCount = function->GetAsmJsFunctionInfo()->GetIntConstCount();
- uint32 floatConstCount = function->GetAsmJsFunctionInfo()->GetFloatConstCount();
- uint32 doubleConstCount = function->GetAsmJsFunctionInfo()->GetDoubleConstCount();
- Js::Var * constTable = static_cast<Js::Var *>(function->GetConstTable());
- int * intConstTable = reinterpret_cast<int *>(constTable + Js::AsmJsFunctionMemory::RequiredVarConstants - 1);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < intConstCount; ++reg)
- {
- PrependConstantInt32(builder, L"Integer Constant Value", intConstTable[reg]);
- }
- float * floatConstTable = reinterpret_cast<float *>(intConstTable + intConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < floatConstCount; ++reg)
- {
- PrependFloat(builder, L"Float Constant Value", floatConstTable[reg]);
- }
- double * doubleConstTable = reinterpret_cast<double *>(floatConstTable + floatConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < doubleConstCount; ++reg)
- {
- PrependDouble(builder, L"Double Constant Value", doubleConstTable[reg]);
- }
- uint32 simdConstCount = function->GetAsmJsFunctionInfo()->GetSimdConstCount();
- AsmJsSIMDValue *simdConstTable = reinterpret_cast<AsmJsSIMDValue *>(doubleConstTable + doubleConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < simdConstCount; ++reg)
- {
- PrependSIMDValue(builder, L"SIMD Constant Value", simdConstTable[reg]);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End Constant Table", magicEndOfConstantTable);
- #endif
- return size;
- }
- #endif
- uint32 AddConstantTable(BufferBuilderList & builder, FunctionBody * function)
- {
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start Constant Table", magicStartOfConstantTable);
- #endif
- for (auto reg = FunctionBody::FirstRegSlot + 1; reg < function->m_constCount; reg++) // Ignore first slot, it is always global object or module root object
- {
- auto var = function->GetConstantVar(reg);
- Assert(var != nullptr);
- size += PrependVarConstant(builder, var);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End Constant Table", magicEndOfConstantTable);
- #endif
- return size;
- }
- uint32 AddPropertyIdsForScopeSlotArray(BufferBuilderList & builder, FunctionBody * function)
- {
- if (function->scopeSlotArraySize == 0)
- {
- return 0;
- }
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start PropertyIdsForScopeSlotsArray", magicStartOfPropertyIdsForScopeSlotArray);
- #endif
- for (uint i = 0; i < function->scopeSlotArraySize; i++)
- {
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(function->propertyIdsForScopeSlotArray[i]);
- size += PrependInt32(builder, L"PropertyIdsForScopeSlots", propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End PropertyIdsForScopeSlotsArray", magicEndOfPropertyIdsForScopeSlotArray);
- #endif
- return size;
- }
- // Gets the number of debugger slot array scopes there are in the function body's scope chain list.
- uint32 GetDebuggerScopeSlotArrayCount(FunctionBody * function)
- {
- Assert(function);
- uint debuggerScopeSlotArraySize = 0;
- if (function->GetScopeObjectChain())
- {
- debuggerScopeSlotArraySize = function->GetScopeObjectChain()->pScopeChain->CountWhere([&](DebuggerScope* scope)
- {
- return scope->IsSlotScope();
- });
- }
- return debuggerScopeSlotArraySize;
- }
- // Adds the debugger scopes that are slot array type to the serialized bytecode.
- // This is to ensure that block scope slot array properties are captured along with
- // function level slot array properties.
- uint32 AddSlotArrayDebuggerScopeProperties(BufferBuilderList & builder, DebuggerScope* debuggerScope, uint propertiesCount)
- {
- Assert(debuggerScope);
- if (propertiesCount == 0)
- {
- return 0u;
- }
- uint32 size = 0u;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start SlotArrayDebuggerScopeProperties", magicStartOfDebuggerScopeProperties);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- AssertMsg(debuggerScope->HasProperties(), "Properties should exist.");
- Assert(debuggerScope->scopeProperties->Count() >= 0);
- AssertMsg((uint)debuggerScope->scopeProperties->Count() == propertiesCount, "Property counts should match.");
- for (uint i = 0u; i < propertiesCount; ++i)
- {
- DebuggerScopeProperty scopeProperty = debuggerScope->scopeProperties->Item(i);
- size += PrependInt32(builder, L"SlotIndexesForDebuggerScopeSlots", scopeProperty.location);
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(scopeProperty.propId);
- size += PrependInt32(builder, L"PropertyIdsForDebuggerScopeSlots", propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End SlotArrayDebuggerScopeProperties", magicEndOfDebuggerScopeProperties);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- return size;
- }
- // Adds the debugger scopes that are slot array type to the serialized bytecode.
- // This is to ensure that block scope slot array properties are captured along with
- // function level slot array properties.
- uint32 AddSlotArrayDebuggerScopes(BufferBuilderList & builder, FunctionBody* function, uint debuggerScopeSlotArraySize)
- {
- Assert(function);
- if (function->GetScopeObjectChain() == nullptr || debuggerScopeSlotArraySize == 0)
- {
- return 0u;
- }
- uint32 size = 0u;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"Start SlotArrayDebuggerScopes", magicStartOfDebuggerScopes);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- uint slotArrayCount = 0;
- for (uint i = 0u; i < static_cast<uint>(function->GetScopeObjectChain()->pScopeChain->Count()); ++i)
- {
- DebuggerScope* debuggerScope = function->GetScopeObjectChain()->pScopeChain->Item(i);
- if (debuggerScope->IsSlotScope())
- {
- // Only add slot scope debugger scopes (store the index of the scope).
- size += PrependInt32(builder, L"SlotArrayDebuggerScope", i);
- // Store the count of properties for the scope.
- int propertiesCount = debuggerScope->HasProperties() ? debuggerScope->scopeProperties->Count() : 0u;
- size += PrependInt32(builder, L"Debugger Scope Slot Array Property Count", propertiesCount);
- size += AddSlotArrayDebuggerScopeProperties(builder, debuggerScope, propertiesCount);
- slotArrayCount++;
- }
- }
- Assert(debuggerScopeSlotArraySize == slotArrayCount);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End SlotArrayDebuggerScopes", magicEndOfDebuggerScopes);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- return size;
- }
- uint32 AddCacheIdToPropertyIdMap(BufferBuilderList & builder, FunctionBody * function)
- {
- uint count = function->GetInlineCacheCount();
- if (count == 0)
- {
- return 0;
- }
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Start CacheId-to-PropertyId map", magicStartOfCacheIdToPropIdMap);
- #endif
- for (uint i = 0; i < count; i++)
- {
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(function->GetPropertyIdFromCacheId(i));
- size += PrependInt32(builder, L"CacheIdToPropertyId", propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End CacheId-to-PropertyId map", magicEndOfCacheIdToPropIdMap);
- #endif
- return size;
- }
- uint32 AddReferencedPropertyIdMap(BufferBuilderList & builder, FunctionBody * function)
- {
- uint count = function->GetReferencedPropertyIdCount();
- if (count == 0)
- {
- return 0;
- }
- uint32 size = 0;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Start Referenced-PropertyId map", magicStartOfReferencedPropIdMap);
- #endif
- for (uint i = 0; i < count; i++)
- {
- PropertyId propertyId = encodeNonBuiltinPropertyId(function->GetReferencedPropertyIdWithMapIndex(i));
- size += PrependInt32(builder, L"ReferencedPropertyId", propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End Referenced-PropertyId map", magicEndOfReferencedPropIdMap);
- #endif
- return size;
- }
- uint32 PrependByteArray(BufferBuilderList & builder, int length, byte * buffer)
- {
- int size = 0;
- for (int i = 0; i<length; ++i)
- {
- size += PrependByte(builder, L"Byte Array Element", buffer[i]);
- }
- return size;
- }
- uint32 PrependUInt32Array(BufferBuilderList & builder, int length, uint32 * buffer)
- {
- int size = 0;
- for(int i=0;i<length;++i)
- {
- size += PrependConstantInt32(builder, L"UInt32 Array Element", buffer[i]);
- }
- return size;
- }
- uint32 PrependGrowingUint32Array(BufferBuilderList & builder, LPCWSTR clue, JsUtil::GrowingUint32HeapArray * arr)
- {
- if (arr == nullptr || arr->Count() == 0 || arr->GetLength() == 0 || arr->GetBuffer() == nullptr)
- {
- return PrependInt32(builder, clue, 0);
- }
- auto size = PrependInt32(builder, clue, arr->Count());
- size += PrependUInt32Array(builder, arr->Count(), arr->GetBuffer());
- return size;
- }
- uint32 PrependSmallSpanSequence(BufferBuilderList & builder, LPCWSTR clue, SmallSpanSequence * spanSequence)
- {
- auto size = PrependInt32(builder, clue, spanSequence->baseValue);
- size += PrependGrowingUint32Array(builder, L"Statement Buffer", spanSequence->pStatementBuffer);
- size += PrependGrowingUint32Array(builder, L"Actual Offset List", spanSequence->pActualOffsetList);
- return size;
- }
- template <typename TStructType>
- uint32 PrependStruct(BufferBuilderList & builder, LPWSTR clue, TStructType * value)
- {
- auto entry = Anew(alloc, ConstantSizedBufferBuilderOf<TStructType>, clue, *value);
- builder.list = builder.list->Prepend(entry, alloc);
- return sizeof(serialization_alignment TStructType);
- }
- #ifndef TEMP_DISABLE_ASMJS
- uint32 AddAsmJsFunctionInfo(BufferBuilderList & builder, FunctionBody * function)
- {
- uint32 size = 0;
- AsmJsFunctionInfo* funcInfo = function->GetAsmJsFunctionInfo();
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Start Asm.js Function Info", magicStartOfAsmJsFuncInfo);
- #endif
- size += PrependInt32(builder, L"ReturnType", funcInfo->GetReturnType().which());
- size += PrependInt32(builder, L"IntConstCount", funcInfo->GetIntConstCount());
- size += PrependInt32(builder, L"DoubleConstCount", funcInfo->GetDoubleConstCount());
- size += PrependInt32(builder, L"FloatConstCount", funcInfo->GetFloatConstCount());
- size += PrependInt16(builder, L"ArgCount", funcInfo->GetArgCount());
- size += PrependInt16(builder, L"ArgSize", funcInfo->GetArgByteSize());
- size += PrependInt32(builder, L"IntVarCount", funcInfo->GetIntVarCount());
- size += PrependInt32(builder, L"DoubleVarCount", funcInfo->GetDoubleVarCount());
- size += PrependInt32(builder, L"FloatVarCount", funcInfo->GetFloatVarCount());
- size += PrependInt32(builder, L"IntTmpCount", funcInfo->GetIntTmpCount());
- size += PrependInt32(builder, L"DoubleTmpCount", funcInfo->GetDoubleTmpCount());
- size += PrependInt32(builder, L"FloatTmpCount", funcInfo->GetFloatTmpCount());
- size += PrependInt16(builder, L"ArgSizeArrayLength", funcInfo->GetArgSizeArrayLength());
- size += PrependUInt32Array(builder, funcInfo->GetArgSizeArrayLength(), funcInfo->GetArgsSizesArray());
- size += PrependByteArray(builder, funcInfo->GetArgCount(), (byte*)funcInfo->GetArgTypeArray());
- size += PrependInt32(builder, L"IntByteOffset", funcInfo->GetIntByteOffset());
- size += PrependInt32(builder, L"DoubleByteOffset", funcInfo->GetDoubleByteOffset());
- size += PrependInt32(builder, L"FloatByteOffset", funcInfo->GetFloatByteOffset());
- size += PrependByte(builder, L"IsHeapBufferConst", funcInfo->IsHeapBufferConst());
- size += PrependByte(builder, L"UsesHeapBuffer", funcInfo->UsesHeapBuffer());
- size += PrependInt32(builder, L"SIMDConstCount", funcInfo->GetSimdConstCount());
- size += PrependInt32(builder, L"SIMDVarCount", funcInfo->GetSimdVarCount());
- size += PrependInt32(builder, L"SIMDTmpCount", funcInfo->GetSimdTmpCount());
- size += PrependInt32(builder, L"SIMDByteOffset", funcInfo->GetSimdByteOffset());
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End Asm.js Function Info", magicEndOfAsmJsFuncInfo);
- #endif
- return size;
- }
- uint32 AddAsmJsModuleInfo(BufferBuilderList & builder, FunctionBody * function)
- {
- uint32 size = 0;
- AsmJsModuleInfo * moduleInfo = function->GetAsmJsModuleInfo();
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Start Asm.js Module Info", magicStartOfAsmJsModuleInfo);
- #endif
- size += PrependInt32(builder, L"ArgInCount", moduleInfo->GetArgInCount());
- size += PrependInt32(builder, L"ExportsCount", moduleInfo->GetExportsCount());
- size += PrependInt32(builder, L"SlotsCount", moduleInfo->GetSlotsCount());
- size += PrependInt32(builder, L"SIMDRegCount", moduleInfo->GetSimdRegCount());
- if (moduleInfo->GetExportsCount() > 0)
- {
- PropertyIdArray * propArray = moduleInfo->GetExportsIdArray();
- size += PrependByte(builder, L"ExportsIdArrayDups", propArray->hadDuplicates);
- size += PrependByte(builder, L"ExportsIdArray__proto__", propArray->has__proto__);
- size += PrependInt32(builder, L"ExportsIdArrayLength", propArray->count);
- for (uint i = 0; i < propArray->count; i++)
- {
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(propArray->elements[i]);
- size += PrependInt32(builder, L"ExportsIdArrayElem", propertyId);
- }
- size += PrependUInt32Array(builder, moduleInfo->GetExportsCount(), moduleInfo->GetExportsFunctionLocation());
- }
- size += PrependInt32(builder, L"ExportFunctionIndex", moduleInfo->GetExportFunctionIndex());
- size += PrependInt32(builder, L"VarCount", moduleInfo->GetVarCount());
- for (int i = 0; i < moduleInfo->GetVarCount(); i++)
- {
- size += PrependStruct(builder, L"ModuleVar", &moduleInfo->GetVar(i));
- }
- size += PrependInt32(builder, L"VarImportCount", moduleInfo->GetVarImportCount());
- for (int i = 0; i < moduleInfo->GetVarImportCount(); i++)
- {
- auto import = moduleInfo->GetVarImport(i);
- size += PrependInt32(builder, L"ImportLocation", import.location);
- size += PrependByte(builder, L"ImportType", import.type);
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(import.field);
- size += PrependInt32(builder, L"ImportId", propertyId);
- }
- size += PrependInt32(builder, L"FunctionImportCount", moduleInfo->GetFunctionImportCount());
- for (int i = 0; i < moduleInfo->GetFunctionImportCount(); i++)
- {
- auto import = moduleInfo->GetFunctionImport(i);
- size += PrependInt32(builder, L"ImportLocation", import.location);
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(import.field);
- size += PrependInt32(builder, L"ImportId", propertyId);
- }
- size += PrependInt32(builder, L"FunctionCount", moduleInfo->GetFunctionCount());
- for (int i = 0; i < moduleInfo->GetFunctionCount(); i++)
- {
- auto func = moduleInfo->GetFunction(i);
- size += PrependInt32(builder, L"FuncLocation", func.location);
- }
- size += PrependInt32(builder, L"FunctionTableCount", moduleInfo->GetFunctionTableCount());
- for (int i = 0; i < moduleInfo->GetFunctionTableCount(); i++)
- {
- auto table = moduleInfo->GetFunctionTable(i);
- size += PrependInt32(builder, L"FuncTableSize", table.size);
- PrependUInt32Array(builder, table.size, table.moduleFunctionIndex);
- }
- size += PrependStruct<AsmJsModuleMemory>(builder, L"ModuleMemory", &moduleInfo->GetModuleMemory());
- size += PrependInt32(builder, L"AsmJsSlotMapCount", moduleInfo->GetAsmJsSlotMap()->Count());
- auto slotIter = moduleInfo->GetAsmJsSlotMap()->GetIterator();
- while (slotIter.IsValid())
- {
- PropertyId propertyId = encodePossiblyBuiltInPropertyId(slotIter.CurrentKey());
- size += PrependInt32(builder, L"AsmJsSlotPropId", propertyId);
- size += PrependStruct(builder, L"AsmJsSlotValue", slotIter.CurrentValue());
- slotIter.MoveNext();
- }
- size += PrependStruct(builder, L"MathBuiltinBV", &moduleInfo->GetAsmMathBuiltinUsed());
- size += PrependStruct(builder, L"ArrayBuiltinBV", &moduleInfo->GetAsmArrayBuiltinUsed());
- size += PrependStruct(builder, L"SIMDBuiltinBV", &moduleInfo->GetAsmSimdBuiltinUsed());
- size += PrependInt32(builder, L"MaxHeapAccess", moduleInfo->GetMaxHeapAccess());
- size += PrependByte(builder, L"UsesChangeHeap", moduleInfo->GetUsesChangeHeap());
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- size += PrependInt32(builder, L"End Asm.js Module Info", magicEndOfAsmJsModuleInfo);
- #endif
- return size;
- }
- #endif
- HRESULT AddFunctionBody(BufferBuilderList & builder, FunctionBody * function, SRCINFO const * srcInfo, int *serializationIndex)
- {
- SerializedFieldList definedFields = { 0 };
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"Start Function Table", magicStartOfFunctionBody);
- #endif
- function->SetSerializationIndex((*serializationIndex)++);
- uint32 sourceDiff = 0;
- if (!TryConvertToUInt32(function->StartOffset(), &sourceDiff))
- {
- Assert(0); // Likely a bug
- return ByteCodeSerializer::CantGenerate;
- }
- PrependString16(builder, L"Display Name", function->m_displayName, (function->m_displayNameLength +1)* sizeof(wchar_t));
- if (function->m_lineNumber != 0)
- {
- definedFields.has_m_lineNumber = true;
- PrependInt32(builder, L"Line Number", function->m_lineNumber);
- }
- if (function->m_columnNumber != 0)
- {
- definedFields.has_m_columnNumber = true;
- PrependInt32(builder, L"Column Number", function->m_columnNumber);
- }
- // FunctionBody Details
- DWORD bitFlags =
- (function->m_isDeclaration ? ffIsDeclaration : 0)
- | (function->m_hasImplicitArgIns ? ffHasImplicitArgsIn : 0)
- | (function->m_isAccessor ? ffIsAccessor : 0)
- | (function->m_isStaticNameFunction ? ffIsStaticNameFunction : 0)
- | (function->m_isNamedFunctionExpression ? ffIsNamedFunctionExpression : 0)
- | (function->m_isNameIdentifierRef ? ffIsNameIdentifierRef : 0)
- | (function->m_isGlobalFunc ? ffIsGlobalFunc : 0)
- | (function->m_dontInline ? ffDontInline : 0)
- | (function->m_isFuncRegistered ? ffIsFuncRegistered : 0)
- | (function->m_isStrictMode ? ffIsStrictMode : 0)
- | (function->m_doBackendArgumentsOptimization ? ffDoBackendArgumentsOptimization : 0)
- | (function->m_isEval ? ffIsEval : 0)
- | (function->m_isDynamicFunction ? ffIsDynamicFunction : 0)
- | (function->m_hasAllNonLocalReferenced ? ffhasAllNonLocalReferenced : 0)
- | (function->m_hasSetIsObject ? ffhasSetIsObject : 0)
- | (function->m_CallsEval ? ffhasSetCallsEval : 0)
- | (function->m_ChildCallsEval ? ffChildCallsEval : 0)
- | (function->m_hasReferenceableBuiltInArguments ? ffHasReferenceableBuiltInArguments : 0)
- #ifndef TEMP_DISABLE_ASMJS
- | (function->m_isAsmjsMode ? ffIsAsmJsMode : 0)
- | (function->m_isAsmJsFunction ? ffIsAsmJsFunction : 0)
- #endif
- ;
- PrependInt32(builder, L"BitFlags", bitFlags);
- PrependInt32(builder, L"Relative Function ID", function->functionId - topFunctionId); // Serialized function ids are relative to the top function ID
- PrependInt32(builder, L"Serialization ID", function->GetSerializationIndex());
- PrependInt32(builder, L"Attributes", function->GetAttributes());
- AssertMsg((function->GetAttributes() &
- ~(FunctionInfo::Attributes::ErrorOnNew
- | FunctionInfo::Attributes::SuperReference
- | FunctionInfo::Attributes::Lambda
- | FunctionInfo::Attributes::Async
- | FunctionInfo::Attributes::CapturesThis
- | FunctionInfo::Attributes::Generator
- | FunctionInfo::Attributes::ClassConstructor
- | FunctionInfo::Attributes::ClassMethod)) == 0,
- "Only the ErrorOnNew|SuperReference|Lambda|CapturesThis|Generator|ClassConstructor|Async|ClassMember attributes should be set on a serialized function");
- PrependInt32(builder, L"Offset Into Source", sourceDiff);
- if (function->GetNestedCount() > 0)
- {
- definedFields.has_m_nestedCount = true;
- PrependInt32(builder, L"Nested count", function->GetNestedCount());
- }
- // This field should always be non-zero
- Assert(function->m_constCount != 0);
- #define PrependArgSlot PrependInt16
- #define PrependRegSlot PrependInt32
- #define PrependCharCount PrependInt32
- #define PrependULong PrependInt32
- #define PrependUInt16 PrependInt16
- #define PrependUInt32 PrependInt32
- #define DEFINE_FUNCTION_PROXY_FIELDS 1
- #define DEFINE_PARSEABLE_FUNCTION_INFO_FIELDS 1
- #define DECLARE_SERIALIZABLE_FIELD(type, name, serializableType) \
- if (function->##name != 0) { \
- definedFields.has_##name = true; \
- Prepend##serializableType(builder, L#name, function->##name); \
- }
- #define DECLARE_MANUAL_SERIALIZABLE_FIELD(type, name, serializableType, serializeHere) \
- if (function->##name != 0 && serializeHere) { \
- definedFields.has_##name = true; \
- Prepend##serializableType(builder, L#name, function->##name); \
- }
- #include "SerializableFunctionFields.h"
- if (!OmitFunction(function->GetSerializationIndex()))
- {
- #define DEFINE_FUNCTION_BODY_FIELDS 1
- #define DECLARE_SERIALIZABLE_FIELD(type, name, serializableType) \
- if (function->##name != 0) { \
- definedFields.has_##name = true; \
- Prepend##serializableType(builder, L#name, function->##name); \
- }
- #define DECLARE_MANUAL_SERIALIZABLE_FIELD(type, name, serializableType, serializeHere) \
- if (function->##name != 0 && serializeHere) { \
- definedFields.has_##name = true; \
- Prepend##serializableType(builder, L#name, function->##name); \
- }
- #include "SerializableFunctionFields.h"
- }
- if (!OmitFunction(function->GetSerializationIndex()))
- {
- if (function->loopHeaderArray)
- {
- PrependByte(builder, L"Loop Header Array Exists", 1);
- for (uint i = 0; i < function->loopCount; ++i)
- {
- PrependInt32(builder, L"Loop Header Start", function->loopHeaderArray[i].startOffset);
- PrependInt32(builder, L"Loop Header End", function->loopHeaderArray[i].endOffset);
- }
- }
- else
- {
- PrependByte(builder, L"Loop Header Array Exists", 0);
- }
- #ifndef TEMP_DISABLE_ASMJS
- if (function->GetAsmJsFunctionInfo())
- {
- PrependByte(builder, L"Asm.js Info Exists", 1);
- AddAsmJsFunctionInfo(builder, function);
- }
- else if (function->GetIsAsmjsMode())
- {
- PrependByte(builder, L"Asm.js Info Exists", 2);
- AddAsmJsModuleInfo(builder, function);
- }
- else
- #endif
- {
- PrependByte(builder, L"Asm.js Info Exists", 0);
- }
- #ifndef TEMP_DISABLE_ASMJS
- if (function->GetIsAsmJsFunction())
- {
- AddAsmJsConstantTable(builder, function);
- auto hr = RewriteAsmJsByteCodesInto(builder, L"Rewritten Byte Code", function, function->byteCodeBlock);
- if (FAILED(hr))
- {
- return hr;
- }
- }
- else
- #endif
- {
- AddConstantTable(builder, function);
- auto hr = RewriteByteCodesInto(builder, L"Rewritten Byte Code", function, function->byteCodeBlock);
- if (FAILED(hr))
- {
- return hr;
- }
- }
- AddCacheIdToPropertyIdMap(builder, function);
- AddReferencedPropertyIdMap(builder, function);
- AddPropertyIdsForScopeSlotArray(builder, function);
- uint debuggerScopeSlotArraySize = GetDebuggerScopeSlotArrayCount(function);
- PrependInt32(builder, L"Debugger Scope Slot Array Size", debuggerScopeSlotArraySize);
- AddSlotArrayDebuggerScopes(builder, function, debuggerScopeSlotArraySize);
- // Literal regexes
- for (uint i = 0; i < function->literalRegexCount; ++i)
- {
- const auto literalRegex = function->GetLiteralRegex(i);
- if (!literalRegex)
- {
- PrependInt32(builder, L"Literal regex source length", -1);
- continue;
- }
- const auto source = literalRegex->GetSource();
- PrependInt32(builder, L"Literal regex source length", source.GetLength());
- PrependString16(builder, L"Literal regex source", source.GetBuffer(), (source.GetLength() + 1)* sizeof(wchar_t));
- PrependByte(builder, L"Literal regex flags", literalRegex->GetFlags());
- }
- // Write the SourceInfo stuff
- PrependSmallSpanSequence(builder, L"Span Sequence", function->m_sourceInfo.pSpanSequence);
- }
- // Lastly, write each of the lexically enclosed functions
- if (function->GetNestedCount())
- {
- auto nestedBodyList = Anew(alloc, BufferBuilderList, L"Nest Function Bodies");
- for(uint32 i = 0; i<function->GetNestedCount(); ++i)
- {
- auto nestedFunctionBody = function->GetNestedFunc(i)->GetFunctionBody();
- if (nestedFunctionBody==nullptr)
- {
- PrependInt32(builder, L"Empty Nested Function", 0);
- }
- else
- {
- auto nestedFunctionBuilder = Anew(alloc, BufferBuilderList, L"Nested Function");
- nestedBodyList->list = nestedBodyList->list->Prepend(nestedFunctionBuilder, alloc);
- auto offsetToNested = Anew(alloc, BufferBuilderRelativeOffset, L"Offset To Nested Function", nestedFunctionBuilder);
- builder.list = builder.list->Prepend(offsetToNested, alloc);
- AddFunctionBody(*nestedFunctionBuilder, nestedFunctionBody, srcInfo, serializationIndex);
- }
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"End Function Body", magicEndOfFunctionBody);
- #endif
- builder.list = builder.list->Prepend(nestedBodyList, alloc);
- }
- else
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- PrependInt32(builder, L"End Function Body", magicEndOfFunctionBody);
- #endif
- }
- // Increment the function count
- ++functionCount.value;
- // Reverse to put prepended items in correct order
- builder.list = builder.list->ReverseCurrentList();
- PrependStruct<SerializedFieldList>(builder, L"Serialized Field List", &definedFields);
- return S_OK;
- }
- HRESULT AddTopFunctionBody(FunctionBody * function, SRCINFO const * srcInfo)
- {
- topFunctionId = function->functionId;
- int serializationIndex = 0;
- return AddFunctionBody(functionsTable, function, srcInfo, &serializationIndex);
- }
- };
- class ByteCodeBufferReader
- {
- public:
- ScriptContext * scriptContext;
- byte * raw;
- int magic;
- int totalSize;
- byte fileVersionScheme;
- int V1;
- int V2;
- int V3;
- int V4;
- byte architecture;
- int expectedFunctionBodySize;
- int expectedBuildInPropertyCount;
- int expectedOpCodeCount;
- int firstFunctionId;
- int functionCount;
- const byte * string16s;
- int string16Count;
- const unaligned StringIndexRecord * string16IndexTable;
- const byte * string16Table;
- const byte * sourceSpans;
- int lineInfoCacheCount;
- const byte * lineInfoCaches;
- const JsUtil::LineOffsetCache<Recycler>::LineOffsetCacheItem * lineInfoCache;
- const byte * functions;
- int sourceSize;
- int sourceCharLength;
- Utf8SourceInfo *utf8SourceInfo;
- uint sourceIndex;
- bool const isLibraryCode;
- public:
- ByteCodeBufferReader(ScriptContext * scriptContext, byte * raw, bool isLibraryCode, int builtInPropertyCount)
- : scriptContext(scriptContext), raw(raw), utf8SourceInfo(nullptr), isLibraryCode(isLibraryCode),
- expectedFunctionBodySize(sizeof(unaligned FunctionBody)),
- expectedBuildInPropertyCount(builtInPropertyCount),
- expectedOpCodeCount((int)OpCode::Count)
- {
- if (isLibraryCode)
- {
- expectedFunctionBodySize = 0;
- expectedOpCodeCount = 0;
- }
- }
- static const byte* ReadFunctionBodyFlags(const byte * buffer, size_t remainingBytes, FunctionBody::FunctionBodyFlags * value)
- {
- Assert(remainingBytes >= sizeof(FunctionBody::FunctionBodyFlags));
- *value = *(FunctionBody::FunctionBodyFlags*) buffer;
- return buffer + sizeof(FunctionBody::FunctionBodyFlags);
- }
- const byte* ReadFunctionBodyFlags(const byte * buffer, FunctionBody::FunctionBodyFlags * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadFunctionBodyFlags(buffer, remainingBytes, value);
- }
- const byte* ReadBool(const byte * buffer, bool * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- Assert(remainingBytes >= sizeof(bool));
- *value = *buffer ? true : false;
- return buffer + sizeof(bool);
- }
- static const byte * ReadByte(const byte * buffer, size_t remainingBytes, byte * value)
- {
- Assert(remainingBytes>=sizeof(byte));
- *value = *(byte*)buffer;
- return buffer + sizeof(byte);
- }
- const byte * ReadByte(const byte * buffer, byte * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadByte(buffer, remainingBytes, value);
- }
- static const byte * ReadInt16(const byte * buffer, size_t remainingBytes, int16 * value)
- {
- #if VARIABLE_INT_ENCODING
- return ReadVariableInt<int16>(buffer, remainingBytes, value);
- #else
- Assert(remainingBytes>=sizeof(int16));
- *value = *(int16 *) buffer;
- return buffer + sizeof(int16);
- #endif
- }
- const byte * ReadInt16(const byte * buffer, int16 * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt16(buffer, remainingBytes, value);
- }
- static const byte * ReadConstantSizedInt64(const byte * buffer, size_t remainingBytes, int64 * value)
- {
- Assert(remainingBytes >= sizeof(int64));
- *value = *(int64 *)buffer;
- return buffer + sizeof(int64);
- }
- const byte * ReadConstantSizedInt64(const byte * buffer, int64 * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadConstantSizedInt64(buffer, remainingBytes, value);
- }
- static const byte * ReadConstantSizedInt32(const byte * buffer, size_t remainingBytes, int * value)
- {
- Assert(remainingBytes >= sizeof(int));
- *value = *(int *) buffer;
- return buffer + sizeof(int);
- }
- const byte * ReadConstantSizedInt32(const byte * buffer, int * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadConstantSizedInt32(buffer, remainingBytes, value);
- }
- static const byte * ReadInt32(const byte * buffer, size_t remainingBytes, int * value)
- {
- #if VARIABLE_INT_ENCODING
- return ReadVariableInt<int>(buffer, remainingBytes, value);
- #else
- Assert(remainingBytes >= sizeof(int));
- return ReadConstantSizedInt32(buffer, remainingBytes, value);
- #endif
- }
- const byte * ReadInt32(const byte * buffer, int * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt32(buffer, remainingBytes, value);
- }
- const byte * ReadCharCount(const byte * buffer, size_t remainingBytes, charcount_t * value)
- {
- Assert(remainingBytes>=sizeof(charcount_t));
- #if VARIABLE_INT_ENCODING
- return ReadVariableInt<charcount_t>(buffer, remainingBytes, value);
- #else
- *value = *(charcount_t *) buffer;
- return buffer + sizeof(charcount_t);
- #endif
- }
- const byte * ReadCharCount(const byte * buffer, charcount_t * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadCharCount(buffer, remainingBytes, value);
- }
- static const byte * ReadFloat(const byte * buffer, size_t remainingBytes, float * value)
- {
- Assert(remainingBytes >= sizeof(float));
- *value = *(float *)buffer;
- return buffer + sizeof(float);
- }
- const byte * ReadFloat(const byte * buffer, float * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadFloat(buffer, remainingBytes, value);
- }
- static const byte * ReadDouble(const byte * buffer, size_t remainingBytes, double * value)
- {
- Assert(remainingBytes>=sizeof(double));
- *value = *(double *)buffer;
- return buffer + sizeof(double);
- }
- const byte * ReadDouble(const byte * buffer, double * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadDouble(buffer, remainingBytes, value);
- }
- static const byte * ReadSIMDValue(const byte * buffer, size_t remainingBytes, SIMDValue * value)
- {
- Assert(remainingBytes >= sizeof(SIMDValue));
- *value = *(SIMDValue *)buffer;
- return buffer + sizeof(SIMDValue);
- }
- const byte * ReadSIMDValue(const byte * buffer, SIMDValue * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadSIMDValue(buffer, remainingBytes, value);
- }
- const byte * ReadUInt16(const byte * buffer, uint16 * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt16(buffer, remainingBytes, (int16*)value);
- }
- const byte * ReadUInt32(const byte * buffer, unsigned int * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt32(buffer, remainingBytes, (int*)value);
- }
- const byte * ReadULong(const byte * buffer, ulong * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt32(buffer, remainingBytes, (int*)value);
- }
- const byte * ReadRegSlot(const byte * buffer, RegSlot * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt32(buffer, remainingBytes, (int*)value);
- }
- const byte * ReadArgSlot(const byte * buffer, ArgSlot * value)
- {
- auto remainingBytes = (raw + totalSize) - buffer;
- return ReadInt32(buffer, remainingBytes, (int*)value);
- }
- const byte * ReadConstantSizedInt32NoSize(const byte * buffer, int * value)
- {
- *value = *(int *)buffer;
- return buffer + sizeof(int);
- }
- const byte * ReadOffsetAsPointer(const byte * buffer, byte const ** value)
- {
- int offset;
- auto next = ReadConstantSizedInt32(buffer, &offset);
- if (offset == 0)
- {
- *value = nullptr;
- return next;
- }
- *value = raw + offset;
- return next;
- }
- const byte * ReadByteBlock(const byte * buffer, WriteBarrierPtr<ByteBlock>* byteBlock)
- {
- int contentLength;
- buffer = ReadInt32(buffer, &contentLength);
- if (contentLength == 0)
- {
- *byteBlock = nullptr;
- }
- else
- {
- // TODO: Abstract this out to ByteBlock::New
- *byteBlock = RecyclerNewLeaf(scriptContext->GetRecycler(), ByteBlock, contentLength, (byte*)buffer);
- }
- return buffer + contentLength;
- }
- const byte * ReadAuxiliary(const byte * buffer, FunctionBody * functionBody)
- {
- const byte * current = buffer;
- uint32 countOfAuxiliaryStructure;
- current = ReadUInt32(current, &countOfAuxiliaryStructure);
- if (countOfAuxiliaryStructure == 0)
- {
- return current;
- }
- uint32 sizeOfAuxiliaryBlock;
- uint32 sizeOfAuxiliaryContextBlock;
- current = ReadUInt32(current, &sizeOfAuxiliaryBlock);
- current = ReadUInt32(current, &sizeOfAuxiliaryContextBlock);
- ByteBlock * auxBlock = sizeOfAuxiliaryBlock?
- ByteBlock::New(scriptContext->GetRecycler(), nullptr, sizeOfAuxiliaryBlock) : nullptr;
- ByteBlock * auxContextBlock = sizeOfAuxiliaryContextBlock?
- ByteBlock::New(scriptContext->GetRecycler(), nullptr, sizeOfAuxiliaryContextBlock) : nullptr;
- for (uint i = 0; i < countOfAuxiliaryStructure; i++)
- {
- typedef serialization_alignment const SerializedAuxiliary TBase;
- auto part = (serialization_alignment const SerializedAuxiliary * )current;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(part->auxMagic == magicStartOfAux);
- #endif
- switch(part->kind)
- {
- default:
- AssertMsg(false, "Unexpected auxiliary kind");
- Throw::FatalInternalError();
- break;
- case sakVarArrayIntCount:
- current = DeserializeVarArray<VarArray>(scriptContext, current, auxBlock);
- break;
- case sakVarArrayVarCount:
- current = DeserializeVarArray<VarArrayVarCount>(scriptContext, current, auxContextBlock);
- break;
- case sakIntArray:
- current = DeserializeIntArray(scriptContext, current, auxBlock);
- break;
- case sakFloatArray:
- current = DeserializeFloatArray(scriptContext, current, auxBlock);
- break;
- case sakPropertyIdArray:
- current = DeserializePropertyIdArray(scriptContext, current, auxBlock, functionBody);
- break;
- case sakFuncInfoArray:
- current = DeserializeFuncInfoArray(scriptContext, current, auxBlock);
- break;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAux);
- #endif
- }
- functionBody->auxBlock = auxBlock;
- functionBody->auxContextBlock = auxContextBlock;
- return current;
- }
- LPCWSTR GetString16ById(int id, bool* isPropertyRecord = nullptr)
- {
- if (id == 0xffffffff)
- {
- return nullptr;
- }
- if(!(id >= this->expectedBuildInPropertyCount && id <= string16Count + this->expectedBuildInPropertyCount))
- {
- Assert(false);
- }
- const unaligned StringIndexRecord* record = string16IndexTable + (id - this->expectedBuildInPropertyCount);
- if(isPropertyRecord)
- {
- *isPropertyRecord = record->isPropertyRecord;
- }
- auto offset = record->offset;
- auto addressOfString = raw + offset;
- return (LPCWSTR)addressOfString;
- }
- uint32 GetString16LengthById(int id)
- {
- if(!(id >= this->expectedBuildInPropertyCount && id<=string16Count + this->expectedBuildInPropertyCount))
- {
- Assert(false);
- }
- LPCWSTR s1 = GetString16ById(id);
- LPCWSTR s2 = GetString16ById(id + 1);
- auto result = s2 - s1 - 1;
- Assert(result <= UINT_MAX);
- return (uint32)result;
- }
- HRESULT ReadHeader()
- {
- auto current = ReadConstantSizedInt32NoSize(raw, &magic);
- if (magic != magicConstant)
- {
- AssertMsg(false, "Unrecognized magic constant in byte code file header. Is this really a bytecode file?");
- return E_FAIL;
- }
- current = ReadConstantSizedInt32NoSize(current, &totalSize);
- current = ReadByte(current, &fileVersionScheme);
- byte expectedFileVersionScheme = isLibraryCode? ReleaseVersioningScheme : CurrentFileVersionScheme;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.ForceSerializedBytecodeVersionSchema)
- {
- expectedFileVersionScheme = (byte)Js::Configuration::Global.flags.ForceSerializedBytecodeVersionSchema;
- }
- #endif
- // Ignore the version scheme check if it is library code
- if (!isLibraryCode && fileVersionScheme != expectedFileVersionScheme)
- {
- // File version scheme is incompatible.
- return ByteCodeSerializer::InvalidByteCode;
- }
- DWORD expectedV1 = 0;
- DWORD expectedV2 = 0;
- DWORD expectedV3 = 0;
- DWORD expectedV4 = 0;
- if (expectedFileVersionScheme != ReleaseVersioningScheme)
- {
- Js::VerifyCatastrophic(!isLibraryCode);
- Js::VerifyCatastrophic(expectedFileVersionScheme == EngineeringVersioningScheme);
- Js::VerifyOkCatastrophic(AutoSystemInfo::GetJscriptFileVersion(&expectedV1, &expectedV2, &expectedV3, &expectedV4));
- }
- else
- {
- auto guidDWORDs = (DWORD*)(&byteCodeCacheReleaseFileVersion);
- expectedV1 = guidDWORDs[0];
- expectedV2 = guidDWORDs[1];
- expectedV3 = guidDWORDs[2];
- expectedV4 = guidDWORDs[3];
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.ForceSerializedBytecodeMajorVersion)
- {
- expectedV1 = Js::Configuration::Global.flags.ForceSerializedBytecodeMajorVersion;
- expectedV2 = 0;
- expectedV3 = 0;
- expectedV4 = 0;
- }
- #endif
- current = ReadConstantSizedInt32(current, &V1);
- if ((DWORD)V1!=expectedV1)
- {
- // Incompatible major version
- return ByteCodeSerializer::InvalidByteCode;
- }
- // Library code is serialized with one build of the engine and then included into a subsequent build, so can't have match
- // on the build timestamp hash. Also want to share the generated bytecode between x86/ARM and debug/release, so skip the extra
- // checking. Will rework this validation entirely under TFS 555060
- current = ReadConstantSizedInt32(current, &V2);
- if ((DWORD)V2 != expectedV2)
- {
- // Incompatible minor version
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadConstantSizedInt32(current, &V3);
- if ((DWORD)V3 != expectedV3)
- {
- // Incompatible 3rd version part
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadConstantSizedInt32(current, &V4);
- if ((DWORD)V4 != expectedV4)
- {
- // Incompatible 4th version part
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadByte(current, &architecture);
- if (architecture!=magicArchitecture)
- {
- // This byte cache file was created with against a chakra running under a different architecture. It is incompatible.
- return ByteCodeSerializer::InvalidByteCode;
- }
- int functionBodySize, buildInPropertyCount, opCodeCount;
- current = ReadInt32(current, &functionBodySize);
- if (functionBodySize != expectedFunctionBodySize)
- {
- // The size of function body didn't match. It is incompatible.
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadInt32(current, &buildInPropertyCount);
- if (buildInPropertyCount!=expectedBuildInPropertyCount)
- {
- // This byte cache file was created with against a chakra that has a different number of built in properties. It is incompatible.
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadInt32(current, &opCodeCount);
- if (opCodeCount != expectedOpCodeCount)
- {
- // This byte cache file was created with against a chakra that has a different number of built in properties. It is incompatible.
- return ByteCodeSerializer::InvalidByteCode;
- }
- current = ReadInt32(current, &sourceSize);
- current = ReadInt32(current, &sourceCharLength);
- current = ReadOffsetAsPointer(current, &string16s);
- current = ReadOffsetAsPointer(current, &lineInfoCaches);
- current = ReadOffsetAsPointer(current, &sourceSpans);
- current = ReadOffsetAsPointer(current, &functions);
- // Read strings header
- string16IndexTable = (StringIndexRecord*)ReadInt32(string16s, &string16Count);
- lineInfoCache = (JsUtil::LineOffsetCache<Recycler>::LineOffsetCacheItem *)ReadInt32(lineInfoCaches, &lineInfoCacheCount);
- string16Table = (byte*)(string16IndexTable + string16Count + 1);
- // string16Table is aligned to 2-bytes
- uint32 string16TableOffset = (uint32)(string16Table - raw);
- string16TableOffset = ::Math::Align(string16TableOffset, (uint32)sizeof(wchar_t));
- string16Table = raw + string16TableOffset;
- return S_OK;
- }
- const byte* ReadStringConstant(const byte* current, FunctionBody* function, LPCWSTR& string, uint32& len)
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartStringConstant);
- #endif
- int stringId;
- current = ReadInt32(current, &stringId);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndStringConstant);
- #endif
- string = GetString16ById(stringId);
- len = GetString16LengthById(stringId);
- return current;
- }
- const byte* ReadStringTemplateCallsiteConstant(const byte* current, FunctionBody* function, Var& var)
- {
- int arrayLength = 0;
- current = ReadInt32(current, &arrayLength);
- ScriptContext* scriptContext = function->GetScriptContext();
- ENTER_PINNED_SCOPE(Js::JavascriptArray, callsite);
- callsite = scriptContext->GetLibrary()->CreateArray(arrayLength);
- LPCWSTR string;
- uint32 len;
- uint32 rawlen = 0;
- for (int i = 0; i < arrayLength; i++)
- {
- current = ReadStringConstant(current, function, string, len);
- JavascriptString* str = JavascriptString::NewCopyBuffer(string, len, scriptContext);
- callsite->SetItemWithAttributes(i, str, PropertyEnumerable);
- }
- JavascriptArray* rawArray = scriptContext->GetLibrary()->CreateArray(arrayLength);
- for (int i = 0; i < arrayLength; i++)
- {
- current = ReadStringConstant(current, function, string, len);
- rawlen += len;
- JavascriptString* str = JavascriptString::NewCopyBuffer(string, len, scriptContext);
- rawArray->SetItemWithAttributes(i, str, PropertyEnumerable);
- }
- rawArray->Freeze();
- callsite->SetPropertyWithAttributes(Js::PropertyIds::raw, rawArray, PropertyNone, nullptr);
- callsite->Freeze();
- JavascriptLibrary* library = scriptContext->GetLibrary();
- var = library->TryGetStringTemplateCallsiteObject(callsite);
- if (var == nullptr)
- {
- library->AddStringTemplateCallsiteObject(callsite);
- var = callsite;
- }
- LEAVE_PINNED_SCOPE();
- return current;
- }
- #ifndef TEMP_DISABLE_ASMJS
- const byte * ReadAsmJsConstantsTable(const byte * current, FunctionBody * function)
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfConstantTable);
- #endif
- function->CreateConstantTable();
- uint32 intConstCount = function->GetAsmJsFunctionInfo()->GetIntConstCount();
- uint32 floatConstCount = function->GetAsmJsFunctionInfo()->GetFloatConstCount();
- uint32 doubleConstCount = function->GetAsmJsFunctionInfo()->GetDoubleConstCount();
- Js::Var * constTable = static_cast<Js::Var *>(function->GetConstTable());
- int * intConstTable = reinterpret_cast<int *>(constTable + Js::AsmJsFunctionMemory::RequiredVarConstants - 1);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < intConstCount; ++reg)
- {
- current = ReadConstantSizedInt32(current, &intConstTable[reg]);
- }
- float * floatConstTable = reinterpret_cast<float *>(intConstTable + intConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < floatConstCount; ++reg)
- {
- current = ReadFloat(current, &floatConstTable[reg]);
- }
- double * doubleConstTable = reinterpret_cast<double *>(floatConstTable + floatConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < doubleConstCount; ++reg)
- {
- current = ReadDouble(current, &doubleConstTable[reg]);
- }
- uint32 simdConstCount = function->GetAsmJsFunctionInfo()->GetSimdConstCount();
- AsmJsSIMDValue *simdConstTable = reinterpret_cast<AsmJsSIMDValue *>(doubleConstTable + doubleConstCount);
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < simdConstCount; ++reg)
- {
- current = ReadSIMDValue(current, &simdConstTable[reg]);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfConstantTable);
- #endif
- return current;
- }
- #endif
- const byte * ReadConstantsTable(const byte * current, FunctionBody * function)
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfConstantTable);
- #endif
- function->CreateConstantTable();
- for (auto reg = FunctionBody::FirstRegSlot + 1; reg < function->m_constCount; reg++) // Ignore first slot, it is always global or module root and has been preinitialized.
- {
- byte ct;
- current = ReadByte(current, &ct);
- switch(ct)
- {
- case ctString16:
- {
- LPCWSTR string;
- uint32 len;
- current = ReadStringConstant(current, function, string, len);
- function->RecordStrConstant(reg, string, len);
- break;
- }
- case ctStringTemplateCallsite:
- {
- Var callsite;
- current = ReadStringTemplateCallsiteConstant(current, function, callsite);
- function->RecordConstant(reg, callsite);
- break;
- }
- case ctInt:
- {
- int value;
- current = ReadConstantSizedInt32(current, &value);
- function->RecordIntConstant(reg, value);
- break;
- }
- case ctNull:
- function->RecordNullObject(reg);
- break;
- case ctUndefined:
- function->RecordUndefinedObject(reg);
- break;
- case ctNumber:
- {
- double value;
- current = ReadDouble(current, &value);
- function->RecordFloatConstant(reg, value);
- break;
- }
- case ctNullDisplay:
- function->RecordNullDisplayConstant(reg);
- break;
- case ctStrictNullDisplay:
- function->RecordStrictNullDisplayConstant(reg);
- break;
- case ctTrue:
- function->RecordTrueObject(reg);
- break;
- case ctFalse:
- function->RecordFalseObject(reg);
- break;
- default:
- AssertMsg(UNREACHED, "Unexpected object type in ReadConstantsTable");
- break;
- }
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfConstantTable);
- #endif
- return current;
- }
- const byte * ReadPropertyIdsForScopeSlotArray(const byte * current, FunctionBody * function)
- {
- if (function->scopeSlotArraySize == 0)
- {
- return current;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfPropertyIdsForScopeSlotArray);
- #endif
- function->propertyIdsForScopeSlotArray = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), Js::PropertyId, function->scopeSlotArraySize);
- for (uint i = 0; i < function->scopeSlotArraySize; i++)
- {
- int value;
- current = ReadInt32(current, &value);
- PropertyId propertyId = function->GetByteCodeCache()->LookupPropertyId(value);
- function->propertyIdsForScopeSlotArray[i] = propertyId;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfPropertyIdsForScopeSlotArray);
- #endif
- return current;
- }
- const byte * ReadSlotArrayDebuggerScopeProperties(const byte * current, FunctionBody* function, DebuggerScope* debuggerScope, uint propertyCount)
- {
- Assert(function);
- Assert(debuggerScope);
- if (propertyCount == 0)
- {
- return current;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfDebuggerScopeProperties);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- for (uint i = 0u; i < propertyCount; ++i)
- {
- // Read the slot array index and property ID for each property (for heap enum to use). The remaining properties
- // are needed for the debugger and will be filled in when generating byte code.
- int value;
- current = ReadInt32(current, &value);
- RegSlot slotIndex = value;
- current = ReadInt32(current, &value);
- PropertyId propertyId = function->GetByteCodeCache()->LookupPropertyId(value);
- debuggerScope->AddProperty(slotIndex, propertyId, DebuggerScopePropertyFlags_None);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfDebuggerScopeProperties);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- return current;
- }
- const byte * ReadSlotArrayDebuggerScopes(const byte * current, FunctionBody * function, uint debuggerScopeCount)
- {
- Assert(function);
- if (debuggerScopeCount == 0)
- {
- return current;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfDebuggerScopes);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- AssertMsg(function->GetScopeObjectChain() == nullptr, "Scope chain should not exist before deserialization.");
- function->SetScopeObjectChain(RecyclerNew(scriptContext->GetRecycler(), ScopeObjectChain, scriptContext->GetRecycler()));
- int currentScopeOffset = 0;
- for (uint i = 0u; i < debuggerScopeCount; i++)
- {
- int scopeIndex;
- current = ReadInt32(current, &scopeIndex);
- DebuggerScope* slotArrayDebuggerScope = nullptr;
- AssertMsg(currentScopeOffset <= scopeIndex, "Scope indices were not inserted into the serialized byte code in ascending order.");
- while (currentScopeOffset <= scopeIndex)
- {
- // Fill the chain with dummy scopes until we reach the slot array scope we're on.
- // These non-slot array scopes are only needed for the debugger and will be filled in
- // properly during byte code generation (when attaching).
- // We also don't need to worry about the parenting/sibling chain, as this will be built when
- // generating bytecode as well.
- slotArrayDebuggerScope = function->AddScopeObject(Js::DiagUnknownScope, 0, Constants::NoRegister);
- ++currentScopeOffset;
- }
- Assert(slotArrayDebuggerScope);
- // Create the slot array properties.
- int propertyCount;
- current = ReadInt32(current, &propertyCount);
- current = ReadSlotArrayDebuggerScopeProperties(current, function, slotArrayDebuggerScope, propertyCount);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfDebuggerScopes);
- #endif // BYTE_CODE_MAGIC_CONSTANTS
- return current;
- }
- const byte * ReadCacheIdToPropertyIdMap(const byte * current, FunctionBody * function)
- {
- uint count = function->GetInlineCacheCount();
- if (count == 0)
- {
- return current;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfCacheIdToPropIdMap);
- #endif
- function->CreateCacheIdToPropertyIdMap();
- for (uint i = 0; i < count; i++)
- {
- int value;
- current = ReadInt32(current, &value);
- PropertyId propertyId = function->GetByteCodeCache()->LookupPropertyId(value);
- function->SetPropertyIdForCacheId(i, propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfCacheIdToPropIdMap);
- #endif
- #if DBG
- function->VerifyCacheIdToPropertyIdMap();
- #endif
- return current;
- }
- const byte * ReadReferencedPropertyIdMap(const byte * current, FunctionBody * function)
- {
- uint count = function->GetReferencedPropertyIdCount();
- if (count == 0)
- {
- return current;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfReferencedPropIdMap);
- #endif
- function->CreateReferencedPropertyIdMap();
- for (uint i = 0; i < count; i++)
- {
- int value;
- current = ReadInt32(current, &value);
- PropertyId propertyId = function->GetByteCodeCache()->LookupNonBuiltinPropertyId(value);
- function->SetReferencedPropertyIdWithMapIndex(i, propertyId);
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfReferencedPropIdMap);
- #endif
- #if DBG
- function->VerifyReferencedPropertyIdMap();
- #endif
- return current;
- }
- // Read a growing Uint32 array
- const byte * ReadGrowingUint32Array(const byte * current, JsUtil::GrowingUint32HeapArray ** arr)
- {
- int count = 0;
- current = ReadInt32(current, &count);
- if (count == 0)
- {
- (*arr) = nullptr;
- return current;
- }
- (*arr) = JsUtil::GrowingUint32HeapArray::Create(/*length=*/count);
- js_memcpy_s((*arr)->GetBuffer(), count * sizeof(uint32), current, count*sizeof(uint32));
- (*arr)->SetCount(count);
- current += count * sizeof(uint32);
- return current;
- }
- // Read a small span sequence
- const byte * ReadSmallSpanSequence(const byte * current, SmallSpanSequence ** smallSpanSequence)
- {
- (*smallSpanSequence) = HeapNew(SmallSpanSequence);
- current = ReadInt32(current, &(*smallSpanSequence)->baseValue);
- current = ReadGrowingUint32Array(current, &(*smallSpanSequence)->pStatementBuffer); // CONSIDER: It would be really nice to change GrowingUint32Array to something with a fixed, readonly layout
- current = ReadGrowingUint32Array(current, &(*smallSpanSequence)->pActualOffsetList);
- return current;
- }
- void ReadSourceInfo(const byte * functionBytes, int& lineNumber, int& columnNumber, bool& m_isEval, bool& m_isDynamicFunction)
- {
- int displayNameId;
- unsigned int bitflags;
- this->ReadFunctionBodyHeader(functionBytes, displayNameId, lineNumber, columnNumber, bitflags);
- m_isEval = (bitflags & ffIsEval) ? true : false;
- m_isDynamicFunction = (bitflags & ffIsDynamicFunction) ? true : false;
- }
- const byte * ReadFunctionBodyHeader(const byte * functionBytes, int& displayNameId, int& lineNumber, int& columnNumber, unsigned int& bitflags)
- {
- serialization_alignment SerializedFieldList* definedFields = (serialization_alignment SerializedFieldList*) functionBytes;
- // Basic function body constructor arguments
- const byte * current = functionBytes + sizeof(serialization_alignment SerializedFieldList);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfFunctionBody);
- #endif
- current = ReadInt32(current, &displayNameId);
- if (definedFields->has_m_lineNumber)
- {
- current = ReadInt32(current, &lineNumber);
- }
- else
- {
- lineNumber = 0;
- }
- if (definedFields->has_m_columnNumber)
- {
- current = ReadInt32(current, &columnNumber);
- }
- else
- {
- columnNumber = 0;
- }
- current = ReadUInt32(current, &bitflags);
- return current;
- }
- #ifndef TEMP_DISABLE_ASMJS
- const byte * ReadAsmJsFunctionInfo(const byte * current, FunctionBody * function)
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfAsmJsFuncInfo);
- #endif
- AsmJsFunctionInfo* funcInfo = function->AllocateAsmJsFunctionInfo();
- int retVal;
- current = ReadInt32(current, &retVal);
- funcInfo->SetReturnType(AsmJsRetType((AsmJsRetType::Which)retVal));
- int count;
- current = ReadInt32(current, &count);
- funcInfo->SetIntConstCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetDoubleConstCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetFloatConstCount(count);
- ArgSlot argCount;
- current = ReadUInt16(current, &argCount);
- funcInfo->SetArgCount(argCount);
- ArgSlot argByteSize;
- current = ReadUInt16(current, &argByteSize);
- funcInfo->SetArgByteSize(argByteSize);
- current = ReadInt32(current, &count);
- funcInfo->SetIntVarCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetDoubleVarCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetFloatVarCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetIntTmpCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetDoubleTmpCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetFloatTmpCount(count);
- ArgSlot argSizeArrayLength;
- current = ReadUInt16(current, &argSizeArrayLength);
- funcInfo->SetArgSizeArrayLength(argSizeArrayLength);
- uint* argArray = RecyclerNewArrayLeafZ(scriptContext->GetRecycler(), uint, argSizeArrayLength);
- funcInfo->SetArgsSizesArray(argArray);
- for (int i = 0; i < argSizeArrayLength; i++)
- {
- int32 size;
- current = ReadConstantSizedInt32(current, &size);
- argArray[i] = (uint32)size;
- }
- if (argCount > 0)
- {
- AsmJsVarType::Which * typeArray = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), AsmJsVarType::Which, argCount);
- funcInfo->SetArgTypeArray(typeArray);
- for (uint i = 0; i < argCount; i++)
- {
- current = ReadByte(current, (byte*)&typeArray[i]);
- }
- }
- current = ReadInt32(current, &count);
- funcInfo->SetIntByteOffset(count);
- current = ReadInt32(current, &count);
- funcInfo->SetDoubleByteOffset(count);
- current = ReadInt32(current, &count);
- funcInfo->SetFloatByteOffset(count);
- bool boolVal;
- current = ReadBool(current, &boolVal);
- funcInfo->SetIsHeapBufferConst(boolVal);
- current = ReadBool(current, &boolVal);
- funcInfo->SetUsesHeapBuffer(boolVal);
- current = ReadInt32(current, &count);
- funcInfo->SetSimdConstCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetSimdVarCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetSimdTmpCount(count);
- current = ReadInt32(current, &count);
- funcInfo->SetSimdByteOffset(count);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfAsmJsFuncInfo);
- #endif
- return current;
- }
- const byte * ReadAsmJsModuleInfo(const byte * current, FunctionBody * function)
- {
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int constant;
- current = ReadInt32(current, &constant);
- Assert(constant == magicStartOfAsmJsModuleInfo);
- #endif
- AsmJsModuleInfo* moduleInfo = function->AllocateAsmJsModuleInfo();
- int count;
- current = ReadInt32(current, &count);
- moduleInfo->SetArgInCount(count);
- int exportsCount;
- current = ReadInt32(current, &exportsCount);
- moduleInfo->SetExportsCount(exportsCount);
- current = ReadInt32(current, &count);
- moduleInfo->InitializeSlotMap(count);
- current = ReadInt32(current, &count);
- moduleInfo->SetSimdRegCount(count);
- int id;
- if (exportsCount > 0)
- {
- PropertyIdArray * propArray = moduleInfo->GetExportsIdArray();
- bool boolVal;
- current = ReadBool(current, &boolVal);
- propArray->hadDuplicates = boolVal;
- current = ReadBool(current, &boolVal);
- propArray->has__proto__ = boolVal;
- current = ReadInt32(current, &count);
- propArray->count = count;
- for (uint i = 0; i < propArray->count; i++)
- {
- current = ReadInt32(current, &id);
- PropertyId propertyId = function->GetByteCodeCache()->LookupPropertyId(id);
- propArray->elements[i] = propertyId;
- }
- RegSlot* exportLocations = moduleInfo->GetExportsFunctionLocation();
- for (int i = 0; i < exportsCount; i++)
- {
- int32 loc;
- current = ReadConstantSizedInt32(current, &loc);
- exportLocations[i] = (uint32)loc;
- }
- }
- RegSlot regSlot;
- current = ReadUInt32(current, ®Slot);
- moduleInfo->SetExportFunctionIndex(regSlot);
- current = ReadInt32(current, &count);
- moduleInfo->SetVarCount(count);
- for (int i = 0; i < count; i++)
- {
- serialization_alignment AsmJsModuleInfo::ModuleVar * modVar = (serialization_alignment AsmJsModuleInfo::ModuleVar*)current;
- moduleInfo->SetVar(i, *modVar);
- current = current + sizeof(serialization_alignment AsmJsModuleInfo::ModuleVar);
- }
- current = ReadInt32(current, &count);
- moduleInfo->SetVarImportCount(count);
- AsmJsModuleInfo::ModuleVarImport varImport;
- for (int i = 0; i < count; i++)
- {
- current = ReadUInt32(current, &varImport.location);
- current = ReadByte(current, (byte*)&varImport.type);
- current = ReadInt32(current, &id);
- varImport.field = function->GetByteCodeCache()->LookupPropertyId(id);
- moduleInfo->SetVarImport(i, varImport);
- }
- current = ReadInt32(current, &count);
- moduleInfo->SetFunctionImportCount(count);
- AsmJsModuleInfo::ModuleFunctionImport funcImport;
- for (int i = 0; i < count; i++)
- {
- current = ReadUInt32(current, &funcImport.location);
- current = ReadInt32(current, &id);
- funcImport.field = function->GetByteCodeCache()->LookupPropertyId(id);
- moduleInfo->SetFunctionImport(i, funcImport);
- }
- current = ReadInt32(current, &count);
- moduleInfo->SetFunctionCount(count);
- AsmJsModuleInfo::ModuleFunction modFunc;
- for (int i = 0; i < count; i++)
- {
- current = ReadUInt32(current, &modFunc.location);
- moduleInfo->SetFunction(i, modFunc);
- }
- current = ReadInt32(current, &count);
- moduleInfo->SetFunctionTableCount(count);
- AsmJsModuleInfo::ModuleFunctionTable funcTable;
- for (int i = 0; i < count; i++)
- {
- current = ReadUInt32(current, &funcTable.size);
- if (funcTable.size > 0)
- {
- funcTable.moduleFunctionIndex = RecyclerNewArray(this->scriptContext->GetRecycler(), RegSlot, funcTable.size);
- }
- else
- {
- funcTable.moduleFunctionIndex = nullptr;
- }
- for (uint j = 0; j < funcTable.size; j++)
- {
- current = ReadConstantSizedInt32(current, (int32*)&funcTable.moduleFunctionIndex[j]);
- }
- moduleInfo->SetFunctionTable(i, funcTable);
- }
- serialization_alignment AsmJsModuleMemory * modMem = (serialization_alignment AsmJsModuleMemory*)current;
- moduleInfo->SetModuleMemory(*modMem);
- current = current + sizeof(serialization_alignment AsmJsModuleMemory);
- current = ReadInt32(current, &count);
- for (int i = 0; i < count; i++)
- {
- current = ReadInt32(current, &id);
- PropertyId key = function->GetByteCodeCache()->LookupPropertyId(id);
- serialization_alignment AsmJsSlot * slot = (serialization_alignment AsmJsSlot*)current;
- current = current + sizeof(serialization_alignment AsmJsSlot);
- // copy the slot to recycler memory
- AsmJsSlot * recyclerSlot = RecyclerNew(scriptContext->GetRecycler(), AsmJsSlot);
- *recyclerSlot = *slot;
- moduleInfo->GetAsmJsSlotMap()->Add(key, recyclerSlot);
- }
- serialization_alignment BVStatic<ASMMATH_BUILTIN_SIZE> * mathBV = (serialization_alignment BVStatic<ASMMATH_BUILTIN_SIZE>*)current;
- current = current + sizeof(serialization_alignment BVStatic<ASMMATH_BUILTIN_SIZE>);
- moduleInfo->SetAsmMathBuiltinUsed(*mathBV);
- serialization_alignment BVStatic<ASMARRAY_BUILTIN_SIZE> * arrayBV = (serialization_alignment BVStatic<ASMARRAY_BUILTIN_SIZE>*)current;
- current = current + sizeof(serialization_alignment BVStatic<ASMARRAY_BUILTIN_SIZE>);
- moduleInfo->SetAsmArrayBuiltinUsed(*arrayBV);
- serialization_alignment BVStatic<ASMSIMD_BUILTIN_SIZE> * simdBV = (serialization_alignment BVStatic<ASMSIMD_BUILTIN_SIZE>*)current;
- current = current + sizeof(serialization_alignment BVStatic<ASMSIMD_BUILTIN_SIZE>);
- moduleInfo->SetAsmSimdBuiltinUsed(*simdBV);
- uint maxAccess;
- current = ReadUInt32(current, &maxAccess);
- moduleInfo->SetMaxHeapAccess(maxAccess);
- bool usesChangeHeap;
- current = ReadBool(current, &usesChangeHeap);
- moduleInfo->SetUsesChangeHeap(usesChangeHeap);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- current = ReadInt32(current, &constant);
- Assert(constant == magicEndOfAsmJsModuleInfo);
- #endif
- return current;
- }
- #endif
- // Read a function body
- HRESULT ReadFunctionBody(const byte * functionBytes, FunctionProxy ** functionProxy, Utf8SourceInfo* sourceInfo, ByteCodeCache * cache, NativeModule *nativeModule, bool deserializeThis, bool deserializeNested = true, Js::DeferDeserializeFunctionInfo* deferDeserializeFunctionInfo = NULL)
- {
- Assert(sourceInfo->GetSrcInfo()->moduleID == kmodGlobal);
- int displayNameId;
- int lineNumber;
- int columnNumber;
- unsigned int bitflags;
- const byte * current = this->ReadFunctionBodyHeader(functionBytes, displayNameId, lineNumber, columnNumber, bitflags);
- serialization_alignment SerializedFieldList* definedFields = (serialization_alignment SerializedFieldList*) functionBytes;
- auto displayName = deferDeserializeFunctionInfo != nullptr ?
- deferDeserializeFunctionInfo->GetDisplayName() :
- GetString16ById(displayNameId);
- uint displayNameLength = deferDeserializeFunctionInfo ? deferDeserializeFunctionInfo->GetDisplayNameLength() : GetString16LengthById(displayNameId);
- uint displayShortNameOffset = deferDeserializeFunctionInfo ? deferDeserializeFunctionInfo->GetShortDisplayNameOffset() : 0;
- int functionId;
- current = ReadInt32(current, &functionId);
- int serializationIndex;
- current = ReadInt32(current, &serializationIndex);
- int32 attributes;
- current = ReadInt32(current, &attributes);
- uint32 offsetIntoSource = 0;
- current = ReadUInt32(current, &offsetIntoSource);
- int nestedCount = 0;
- if (definedFields->has_m_nestedCount)
- {
- current = ReadInt32(current, &nestedCount);
- }
- if (!deserializeThis)
- {
- Assert(sourceInfo->GetSrcInfo()->moduleID == kmodGlobal);
- Assert(!deserializeNested);
- *functionProxy = DeferDeserializeFunctionInfo::New(this->scriptContext, nestedCount, functionId, cache, functionBytes, sourceInfo, displayName, displayNameLength, displayShortNameOffset, nativeModule, (FunctionInfo::Attributes)attributes);
- return S_OK;
- }
- ParseableFunctionInfo **function = (ParseableFunctionInfo **) functionProxy;
- uint functionNumber;
- if (deferDeserializeFunctionInfo)
- {
- functionNumber = deferDeserializeFunctionInfo->GetFunctionNumber();
- }
- else
- {
- functionNumber = scriptContext->GetThreadContext()->NewFunctionNumber();
- }
- if (definedFields->has_m_constCount)
- {
- FunctionBody **functionBody = (FunctionBody **) function;
- *functionBody = FunctionBody::NewFromRecycler(this->scriptContext, nullptr /*displayName*/, 0 /*displayNameLength*/, 0 /*displayShortNameOffset*/, nestedCount,
- sourceInfo,
- functionNumber,
- sourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId,
- firstFunctionId + functionId, nullptr, (FunctionInfo::Attributes)attributes
- #ifdef PERF_COUNTERS
- , (deferDeserializeFunctionInfo != nullptr)
- #endif
- );
- (*functionBody)->SetDisplayName(displayName, displayNameLength, displayShortNameOffset, FunctionProxy::SetDisplayNameFlags::SetDisplayNameFlagsDontCopy);
- (*functionBody)->serializationIndex = serializationIndex;
- (*functionBody)->byteCodeCache = cache;
- (*functionBody)->m_utf8SourceInfo = utf8SourceInfo; // Set source info
- (*function)->m_utf8SourceHasBeenSet = true;
- }
- else
- {
- *function = ParseableFunctionInfo::New(this->scriptContext, nestedCount, firstFunctionId + functionId, utf8SourceInfo, displayName, displayNameLength, displayShortNameOffset, nullptr, (FunctionInfo::Attributes)attributes);
- }
- // These fields are manually deserialized previously
- (*function)->m_lineNumber = lineNumber;
- (*function)->m_columnNumber = columnNumber;
- (*function)->m_isDeclaration = (bitflags & ffIsDeclaration) ? true : false;
- (*function)->m_hasImplicitArgIns = (bitflags & ffHasImplicitArgsIn) ? true : false;
- (*function)->m_isAccessor = (bitflags & ffIsAccessor) ? true : false;
- (*function)->m_isStaticNameFunction = (bitflags & ffIsStaticNameFunction) ? true : false;
- (*function)->m_isNamedFunctionExpression = (bitflags & ffIsNamedFunctionExpression) ? true : false;
- (*function)->m_isNameIdentifierRef = (bitflags & ffIsNameIdentifierRef ) ? true : false;
- (*function)->m_isGlobalFunc = (bitflags & ffIsGlobalFunc) ? true : false;
- (*function)->m_dontInline = (bitflags & ffDontInline) ? true : false;
- (*function)->m_isStrictMode = (bitflags & ffIsStrictMode) ? true : false;
- (*function)->m_doBackendArgumentsOptimization = (bitflags & ffDoBackendArgumentsOptimization) ? true : false;
- (*function)->m_isEval = (bitflags & ffIsEval) ? true : false;
- (*function)->m_isDynamicFunction = (bitflags & ffIsDynamicFunction) ? true : false;
- // This is offsetIntoSource is the start offset in bytes as well.
- (*function)->m_cbStartOffset = (size_t) offsetIntoSource;
- (*function)->m_sourceIndex = this->sourceIndex;
- #define DEFINE_FUNCTION_PROXY_FIELDS 1
- #define DEFINE_PARSEABLE_FUNCTION_INFO_FIELDS 1
- #define DECLARE_SERIALIZABLE_FIELD(type, name, serializableType) \
- if (definedFields->has_##name == true) { \
- current = Read##serializableType(current, &(*function)->##name); \
- }
- #define DECLARE_MANUAL_SERIALIZABLE_FIELD(type, name, serializableType, deserializeHere) \
- if (deserializeHere && definedFields->has_##name == true) { \
- current = Read##serializableType(current, &(*function)->##name); \
- }
- #include "SerializableFunctionFields.h"
- if (definedFields->has_m_constCount)
- {
- FunctionBody **functionBody = (FunctionBody **)function;
- #define DEFINE_FUNCTION_BODY_FIELDS 1
- #define DECLARE_SERIALIZABLE_FIELD(type, name, serializableType) \
- if (definedFields->has_##name == true) { \
- current = Read##serializableType(current, &(*functionBody)->##name); \
- }
- #define DECLARE_MANUAL_SERIALIZABLE_FIELD(type, name, serializableType, deserializeHere) \
- if (deserializeHere && definedFields->has_##name == true) { \
- current = Read##serializableType(current, &(*functionBody)->##name); \
- }
- #include "SerializableFunctionFields.h"
- // TODO-STACK-NESTED-FUNC: Defer deserialize function doesn't have parent pointer, can't do stack nested func yet
- // The flags field is set to by default to Flags_HasNoExplicitReturnValue which means if it's serialized, the field will be set
- // in the definedFields struct. If it's not set, that means that the flag was explicitly set to Flags_None so we'll have to set
- // that here.
- if (definedFields->has_flags == false)
- {
- (*functionBody)->flags = FunctionBody::FunctionBodyFlags::Flags_None;
- }
- else
- {
- (*functionBody)->flags = (FunctionBody::FunctionBodyFlags)((*functionBody)->flags & ~FunctionBody::Flags_StackNestedFunc);
- }
- if (definedFields->has_m_firstTmpReg == false)
- {
- (*functionBody)->m_firstTmpReg = 0;
- }
- if (definedFields->has_m_envDepth == false)
- {
- (*functionBody)->m_envDepth = 0;
- }
- if (deserializeThis && !deserializeNested)
- {
- (*functionBody)->m_isPartialDeserializedFunction = true;
- }
- (*functionBody)->FinishSourceInfo(); // SourceInfo is complete. Register this functionBody to utf8SourceInfo.
- (*functionBody)->m_isFuncRegistered = (bitflags & ffIsFuncRegistered) ? true : false;
- (*functionBody)->m_hasAllNonLocalReferenced = (bitflags & ffhasAllNonLocalReferenced) ? true : false;
- (*functionBody)->m_hasSetIsObject = (bitflags & ffhasSetIsObject) ? true : false;
- (*functionBody)->m_CallsEval = (bitflags & ffhasSetCallsEval) ? true : false;
- (*functionBody)->m_ChildCallsEval = (bitflags & ffChildCallsEval) ? true : false;
- (*functionBody)->m_hasReferenceableBuiltInArguments = (bitflags & ffHasReferenceableBuiltInArguments) ? true : false;
- #ifndef TEMP_DISABLE_ASMJS
- (*functionBody)->m_isAsmJsFunction = (bitflags & ffIsAsmJsFunction) ? true : false;
- (*functionBody)->m_isAsmjsMode = (bitflags & ffIsAsmJsMode) ? true : false;
- #endif
- byte loopHeaderExists;
- current = ReadByte(current, &loopHeaderExists);
- if (loopHeaderExists)
- {
- (*functionBody)->AllocateLoopHeaders();
- for (uint i = 0; i < (*functionBody)->loopCount; ++i)
- {
- uint startOffset, endOffset;
- current = ReadUInt32(current, &startOffset);
- current = ReadUInt32(current, &endOffset);
- (*functionBody)->loopHeaderArray[i].startOffset = startOffset;
- (*functionBody)->loopHeaderArray[i].endOffset = endOffset;
- }
- }
- byte asmJsInfoExists;
- current = ReadByte(current, &asmJsInfoExists);
- #ifndef TEMP_DISABLE_ASMJS
- if (asmJsInfoExists == 1)
- {
- current = ReadAsmJsFunctionInfo(current, *functionBody);
- }
- else if (asmJsInfoExists == 2)
- {
- current = ReadAsmJsModuleInfo(current, *functionBody);
- }
- else
- #endif
- {
- Assert(asmJsInfoExists == 0);
- }
- // Read constants table
- #ifndef TEMP_DISABLE_ASMJS
- if ((*functionBody)->GetIsAsmJsFunction())
- {
- current = ReadAsmJsConstantsTable(current, *functionBody);
- }
- else
- #endif
- {
- current = ReadConstantsTable(current, *functionBody);
- }
- // Byte code
- current = ReadByteBlock(current, &(*functionBody)->byteCodeBlock);
- // Auxiliary
- current = ReadAuxiliary(current, *functionBody);
- // Inline cache
- current = ReadCacheIdToPropertyIdMap(current, *functionBody);
- current = ReadReferencedPropertyIdMap(current, *functionBody);
- (*functionBody)->AllocateInlineCache();
- current = ReadPropertyIdsForScopeSlotArray(current, *functionBody);
- uint debuggerScopeCount = 0;
- current = ReadUInt32(current, &debuggerScopeCount);
- current = ReadSlotArrayDebuggerScopes(current, *functionBody, debuggerScopeCount);
- (*functionBody)->AllocateObjectLiteralTypeArray();
- // Literal regexes
- (*functionBody)->AllocateLiteralRegexArray();
- for (uint i = 0; i < (*functionBody)->literalRegexCount; ++i)
- {
- int length;
- current = ReadInt32(current, &length);
- if (length == -1)
- {
- Assert(!(*functionBody)->GetLiteralRegex(i));
- continue;
- }
- int sourceId;
- current = ReadInt32(current, &sourceId);
- const auto source = GetString16ById(sourceId);
- UnifiedRegex::RegexFlags flags;
- CompileAssert(sizeof(flags) == sizeof(byte));
- current = ReadByte(current, reinterpret_cast<byte *>(&flags));
- (*functionBody)->SetLiteralRegex(i, RegexHelper::CompileDynamic(scriptContext, source, length, flags, true));
- }
- // Read source information
- current = ReadSmallSpanSequence(current, &(*functionBody)->m_sourceInfo.pSpanSequence);
- (*functionBody)->InitializeExecutionModeAndLimits();
- }
- // Read lexically nested functions
- if (nestedCount)
- {
- for(auto i = 0; i<nestedCount; ++i)
- {
- const byte * nestedFunctionBytes;
- current = ReadOffsetAsPointer(current, &nestedFunctionBytes);
- if (nestedFunctionBytes == nullptr)
- {
- (*function)->SetNestedFunc(NULL, i, 0u);
- }
- else
- {
- FunctionProxy* nestedFunction;
- // If we should deserialize nested functions, go ahead and do so
- // If we shouldn't, and we're currently deserializing a function proxy
- // that has been defer-deserialized, simply copy over the function proxy from
- // from the old function- otherwise, create proxies for the nested functions
- auto hr = ReadFunctionBody(nestedFunctionBytes, &nestedFunction, sourceInfo, cache, nativeModule, deserializeNested, deserializeNested);
- if (FAILED(hr))
- {
- Assert(0);
- return hr;
- }
- (*function)->SetNestedFunc(nestedFunction, i, 0u);
- }
- }
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- // Magical ending
- int constant;
- ReadInt32(current, &constant);
- if (constant != magicEndOfFunctionBody)
- {
- Assert(constant == magicEndOfFunctionBody);
- Throw::FatalInternalError();
- }
- #endif
- if (definedFields->has_m_constCount)
- {
- FunctionBody **functionBody = (FunctionBody **) function;
- #if DBG
- if (PHASE_DUMP(Js::DebuggerScopePhase, (*functionBody)))
- {
- (*functionBody)->DumpScopes();
- }
- #endif
- #if ENABLE_NATIVE_CODEGEN
- if ((!PHASE_OFF(Js::BackEndPhase, *functionBody))
- && !this->scriptContext->GetConfig()->IsNoNative()
- && !(*functionBody)->GetIsAsmjsMode())
- {
- GenerateFunction(this->scriptContext->GetNativeCodeGenerator(), *functionBody);
- }
- #endif // ENABLE_NATIVE_CODEGEN
- (*functionBody)->m_isPartialDeserializedFunction = false;
- }
- else
- {
- *function = (*function)->Parse(nullptr, true);
- }
- return S_OK;
- }
- // Read the top function body.
- HRESULT ReadTopFunctionBody(FunctionBody** function, Utf8SourceInfo* sourceInfo, ByteCodeCache * cache, bool allowDefer, NativeModule *nativeModule)
- {
- auto topFunction = ReadInt32(functions, &functionCount);
- firstFunctionId = sourceInfo->GetSrcInfo()->sourceContextInfo->nextLocalFunctionId;
- sourceInfo->GetSrcInfo()->sourceContextInfo->nextLocalFunctionId += functionCount;
- sourceInfo->EnsureInitialized(functionCount);
- sourceInfo->GetSrcInfo()->sourceContextInfo->EnsureInitialized();
- #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_PREJIT)
- bool prejit = false;
- prejit = (!scriptContext->GetConfig()->IsNoNative() && Js::Configuration::Global.flags.Prejit && nativeModule == nullptr);
- allowDefer = allowDefer && !prejit;
- #endif
- FunctionBody* functionBody = NULL;
- auto result = ReadFunctionBody(topFunction, (FunctionProxy **)&functionBody, sourceInfo, cache, nativeModule, true, !allowDefer /* don't deserialize nested if defer is allowed */);
- (*function) = functionBody;
- #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_PREJIT)
- if (prejit)
- {
- Assert(!allowDefer);
- GenerateAllFunctions(scriptContext->GetNativeCodeGenerator(), functionBody);
- }
- #endif
- return result;
- }
- // Deserialize and save a PropertyIdArray
- const byte *
- DeserializePropertyIdArray(ScriptContext * scriptContext, const byte * buffer, ByteBlock * deserializeInto, FunctionBody * functionBody)
- {
- auto serialized = (serialization_alignment const Js::SerializedPropertyIdArray *)buffer;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(serialized->magic == magicStartOfAuxPropIdArray);
- #endif
- auto propertyCount = serialized->propertyCount;
- auto extraSlotCount = serialized->extraSlots;
- Assert(serialized->offset + sizeof(PropertyIdArray) < deserializeInto->GetLength());
- auto result = (PropertyIdArray *)(deserializeInto->GetBuffer() + serialized->offset);
- result->count = propertyCount;
- Assert(serialized->offset + result->GetDataSize(extraSlotCount) <= deserializeInto->GetLength());
- result->hadDuplicates = serialized->hadDuplicates;
- result->has__proto__ = serialized->has__proto__;
- auto elements = (PropertyId*)(serialized + 1);
- for(int i=0;i<propertyCount;++i)
- {
- result->elements[i] = functionBody->GetByteCodeCache()->LookupPropertyId(elements[i]);
- }
- for(int i=0;i<extraSlotCount;++i)
- {
- result->elements[propertyCount + i] = elements[propertyCount + i];
- }
- auto current = buffer +
- sizeof(serialization_alignment const Js::SerializedPropertyIdArray) + (propertyCount + extraSlotCount) * sizeof(PropertyId);
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAuxPropIdArray);
- #endif
- return current;
- }
- // Deserialize and save a FuncInfoArray
- const byte *
- DeserializeFuncInfoArray(ScriptContext * scriptContext, const byte * buffer, ByteBlock * deserializeInto)
- {
- auto serialized = (serialization_alignment const SerializedFuncInfoArray *)buffer;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(serialized->magic == magicStartOfAuxFuncInfoArray);
- #endif
- auto count = serialized->count;
- Assert(serialized->offset + sizeof(AuxArray<FuncInfoEntry>) < deserializeInto->GetLength());
- auto result = (AuxArray<FuncInfoEntry> *)(deserializeInto->GetBuffer() + serialized->offset);
- result->count = count;
- Assert(serialized->offset + result->GetDataSize() <= deserializeInto->GetLength());
- auto elements = (int*)(serialized+1);
- for(int i=0;i<count;++i)
- {
- result->elements[i].nestedIndex = elements[i*2];
- result->elements[i].scopeSlot = elements[i*2+1];
- }
- auto current = buffer + sizeof(serialization_alignment const SerializedFuncInfoArray) + (count * 2 * sizeof(int));
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAuxFuncInfoArray);
- #endif
- return current;
- }
- // Deserialize a var array
- template<typename T>
- const byte * DeserializeVarArray(ScriptContext * scriptContext, const byte * buffer, ByteBlock * deserializeInto)
- {
- auto serialized = (serialization_alignment const Js::SerializedVarArray *)buffer;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(serialized->magic == magicStartOfAuxVarArray);
- #endif
- Assert(serialized->offset + sizeof(T) < deserializeInto->GetLength());
- auto result = (T *)(deserializeInto->GetBuffer() + serialized->offset);
- uint count = serialized->varCount;
- result->SetCount(count);
- Assert(serialized->offset + result->GetDataSize() <= deserializeInto->GetLength());
- auto content = (const byte*)(serialized + 1);
- auto current = content;
- for (uint index = 0; index < count; index++)
- {
- byte code;
- current = ReadByte(current, &code);
- switch(code)
- {
- case ctInt:
- {
- int value;
- current = ReadConstantSizedInt32(current, &value);
- result->elements[index] = Js::TaggedInt::ToVarUnchecked(value);
- break;
- }
- case ctNumber:
- {
- double value;
- current = ReadDouble(current, &value);
- const auto number = Js::JavascriptNumber::New(value, scriptContext);
- #if !FLOATVAR
- scriptContext->BindReference(number);
- #endif
- result->elements[index] = number;
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unexpected object type in VarArray");
- Throw::FatalInternalError();
- }
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAuxVarArray);
- #endif
- return current;
- }
- const byte * DeserializeIntArray(ScriptContext * scriptContext, const byte * buffer, ByteBlock * deserializeInto)
- {
- auto serialized = (serialization_alignment const Js::SerializedIntArray *)buffer;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(serialized->magic == magicStartOfAuxIntArray);
- #endif
- Assert(serialized->offset + sizeof(AuxArray<int>) < deserializeInto->GetLength());
- auto result = (AuxArray<int> *)(deserializeInto->GetBuffer() + serialized->offset);
- uint count = serialized->intCount;
- result->count = count;
- Assert(serialized->offset + result->GetDataSize() <= deserializeInto->GetLength());
- auto content = (const byte*)(serialized + 1);
- auto current = content;
- for (uint index = 0; index < count; index++)
- {
- int32 value;
- current = ReadConstantSizedInt32(current, &value);
- result->elements[index] = value;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAuxIntArray);
- #endif
- return current;
- }
- const byte *
- DeserializeFloatArray(ScriptContext * scriptContext, const byte * buffer, ByteBlock * deserializeInto)
- {
- auto serialized = (serialization_alignment const SerializedFloatArray *)buffer;
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- Assert(serialized->magic == magicStartOfAuxFltArray);
- #endif
- Assert(serialized->offset + sizeof(AuxArray<double>) < deserializeInto->GetLength());
- auto result = (AuxArray<double> *)(deserializeInto->GetBuffer() + serialized->offset);
- uint count = serialized->floatCount;
- result->count = count;
- Assert(serialized->offset + result->GetDataSize() <= deserializeInto->GetLength());
- auto content = (const byte*)(serialized + 1);
- auto current = content;
- for (uint index = 0; index < count; index++)
- {
- double value;
- current = ReadDouble(current, &value);
- result->elements[index] = value;
- }
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- int magicEnd;
- current = ReadInt32(current, &magicEnd);
- Assert(magicEnd == magicEndOfAuxFltArray);
- #endif
- return current;
- }
- };
- // Construct the byte code cache. Copy things needed by inline 'Lookup' functions from reader.
- ByteCodeCache::ByteCodeCache(ScriptContext * scriptContext, ByteCodeBufferReader * reader, int builtInPropertyCount)
- : reader(reader), propertyCount(reader->string16Count), builtInPropertyCount(builtInPropertyCount)
- {
- auto alloc = scriptContext->SourceCodeAllocator();
- propertyIds = AnewArray(alloc, PropertyId, propertyCount);
- for (auto i=0; i < propertyCount; ++i)
- {
- propertyIds[i] = -1;
- }
- raw = reader->raw;
- // Read and populate PropertyIds
- for(int i=0; i < propertyCount; ++i)
- {
- PopulateLookupPropertyId(scriptContext, i);
- }
- }
- // Deserialize and save a PropertyId
- void ByteCodeCache::PopulateLookupPropertyId(ScriptContext * scriptContext, int realOffset)
- {
- PropertyId idInCache = realOffset + this->builtInPropertyCount;
- bool isPropertyRecord;
- auto propertyName = reader->GetString16ById(idInCache, &isPropertyRecord);
- if(isPropertyRecord)
- {
- auto propertyNameLength = reader->GetString16LengthById(idInCache);
- const Js::PropertyRecord * propertyRecord = scriptContext->GetThreadContext()->GetOrAddPropertyRecordBind(
- JsUtil::CharacterBuffer<wchar_t>(propertyName, propertyNameLength));
- propertyIds[realOffset] = propertyRecord->GetPropertyId();
- }
- }
- // Serialize function body
- HRESULT ByteCodeSerializer::SerializeToBuffer(ScriptContext * scriptContext, ArenaAllocator * alloc, DWORD sourceByteLength, LPCUTF8 utf8Source, DWORD dwFunctionTableLength, BYTE * functionTable, FunctionBody * function, SRCINFO const* srcInfo, bool allocateBuffer, byte ** buffer, DWORD * bufferBytes, DWORD dwFlags)
- {
- int builtInPropertyCount = (dwFlags & GENERATE_BYTE_CODE_BUFFER_LIBRARY) != 0 ? PropertyIds::_countJSOnlyProperty : TotalNumberOfBuiltInProperties;
- Utf8SourceInfo *utf8SourceInfo = function->GetUtf8SourceInfo();
- HRESULT hr = utf8SourceInfo->EnsureLineOffsetCacheNoThrow();
- if (FAILED(hr))
- {
- return hr;
- }
- int32 sourceCharLength = utf8SourceInfo->GetCchLength();
- ByteCodeBufferBuilder builder(sourceByteLength, sourceCharLength, utf8Source, dwFunctionTableLength, functionTable, utf8SourceInfo, scriptContext, alloc, dwFlags, builtInPropertyCount);
- hr = builder.AddTopFunctionBody(function, srcInfo);
- if (SUCCEEDED(hr))
- {
- hr = builder.Create(allocateBuffer, buffer, bufferBytes);
- }
- #if INSTRUMENT_BUFFER_INTS
- for (int i = 0; i < 4; i++)
- {
- printf("[BCGENSTATS] %d, %d\n", i, Counts[i]);
- }
- #endif
- return hr;
- }
- HRESULT ByteCodeSerializer::DeserializeFromBuffer(ScriptContext * scriptContext, ulong scriptFlags, LPCUTF8 utf8Source, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex)
- {
- return ByteCodeSerializer::DeserializeFromBufferInternal(scriptContext, scriptFlags, utf8Source, /* sourceHolder */ nullptr, srcInfo, buffer, nativeModule, function, sourceIndex);
- }
- // Deserialize function body from supplied buffer
- HRESULT ByteCodeSerializer::DeserializeFromBuffer(ScriptContext * scriptContext, ulong scriptFlags, ISourceHolder* sourceHolder, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex)
- {
- AssertMsg(sourceHolder != nullptr, "SourceHolder can't be null, if you have an empty source then pass ISourceHolder::GetEmptySourceHolder()");
- return ByteCodeSerializer::DeserializeFromBufferInternal(scriptContext, scriptFlags, /* utf8Source */ nullptr, sourceHolder, srcInfo, buffer, nativeModule, function, sourceIndex);
- }
- HRESULT ByteCodeSerializer::DeserializeFromBufferInternal(ScriptContext * scriptContext, ulong scriptFlags, LPCUTF8 utf8Source, ISourceHolder* sourceHolder, SRCINFO const * srcInfo, byte * buffer, NativeModule *nativeModule, FunctionBody** function, uint sourceIndex)
- {
- //ETW Event start
- JS_ETW(EventWriteJSCRIPT_BYTECODEDESERIALIZE_START(scriptContext, 0));
- auto alloc = scriptContext->SourceCodeAllocator();
- bool isLibraryCode = ((scriptFlags & fscrIsLibraryCode) == fscrIsLibraryCode);
- int builtInPropertyCount = isLibraryCode ? PropertyIds::_countJSOnlyProperty : TotalNumberOfBuiltInProperties;
- auto reader = Anew(alloc, ByteCodeBufferReader, scriptContext, buffer, isLibraryCode, builtInPropertyCount);
- auto hr = reader->ReadHeader();
- if (FAILED(hr))
- {
- return hr;
- }
- ENTER_PINNED_SCOPE(Js::Utf8SourceInfo, sourceInfo);
- ENTER_PINNED_SCOPE(SRCINFO const, pinnedSrcInfo);
- pinnedSrcInfo = srcInfo;
- if(sourceIndex == Js::Constants::InvalidSourceIndex)
- {
- if (sourceHolder == nullptr)
- {
- sourceHolder = utf8Source == nullptr ? ISourceHolder::GetEmptySourceHolder() : RecyclerNew(scriptContext->GetRecycler(), SimpleSourceHolder, utf8Source, reader->sourceSize);
- }
- sourceInfo = Js::Utf8SourceInfo::NewWithHolder(scriptContext, sourceHolder, reader->sourceCharLength, pinnedSrcInfo);
- reader->utf8SourceInfo = sourceInfo;
- reader->sourceIndex = scriptContext->SaveSourceNoCopy(sourceInfo, reader->sourceCharLength, false);
- if(isLibraryCode)
- {
- sourceInfo->SetIsLibraryCode();
- }
- sourceInfo->CreateLineOffsetCache(reader->lineInfoCache, reader->lineInfoCacheCount);
- }
- else
- {
- Assert(CONFIG_FLAG(ForceSerialized));
- sourceInfo = scriptContext->GetSource(sourceIndex);
- reader->utf8SourceInfo = sourceInfo;
- reader->sourceIndex = sourceIndex;
- }
- auto cache = Anew(alloc, ByteCodeCache, scriptContext, reader, builtInPropertyCount);
- hr = reader->ReadTopFunctionBody(function, sourceInfo, cache, ((scriptFlags & fscrAllowFunctionProxy) == fscrAllowFunctionProxy), nativeModule);
- //ETW Event stop
- JS_ETW(EventWriteJSCRIPT_BYTECODEDESERIALIZE_STOP(scriptContext,0));
- LEAVE_PINNED_SCOPE();
- LEAVE_PINNED_SCOPE();
- return hr;
- }
- void ByteCodeSerializer::ReadSourceInfo(const DeferDeserializeFunctionInfo* deferredFunction, int& lineNumber, int& columnNumber, bool& m_isEval, bool& m_isDynamicFunction)
- {
- ByteCodeCache* cache = deferredFunction->m_cache;
- ByteCodeBufferReader* reader = cache->GetReader();
- reader->ReadSourceInfo(deferredFunction->m_functionBytes, lineNumber, columnNumber, m_isEval, m_isDynamicFunction);
- }
- FunctionBody* ByteCodeSerializer::DeserializeFunction(ScriptContext* scriptContext, DeferDeserializeFunctionInfo* deferredFunction)
- {
- FunctionBody* deserializedFunctionBody = nullptr;
- ByteCodeCache* cache = deferredFunction->m_cache;
- ByteCodeBufferReader* reader = cache->GetReader();
- HRESULT hr = reader->ReadFunctionBody(deferredFunction->m_functionBytes, (FunctionProxy **)&deserializedFunctionBody, deferredFunction->m_utf8SourceInfo, cache, deferredFunction->m_nativeModule, true /* deserialize this */, false /* deserialize nested functions */, deferredFunction);
- if (FAILED(hr))
- {
- // This should never happen as the code is currently
- // structured since we validate the serialized bytecode during creation
- // of function proxies. In the future though, when we reorganize the byte
- // code file format, we could hit this error, in which case we
- // need a strategy to deal with this.
- Assert(false);
- Js::Throw::InternalError();
- }
- return deserializedFunctionBody;
- }
- SerializedAuxiliary::SerializedAuxiliary( uint offset, SerializedAuxiliaryKind kind ) :
- offset(offset), kind(kind)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , auxMagic(magicStartOfAux)
- #endif
- {
- }
- SerializedVarArray::SerializedVarArray( uint offset, bool isVarCount, int varCount ) :
- SerializedAuxiliary(offset, isVarCount ? sakVarArrayVarCount : sakVarArrayIntCount), varCount(varCount)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , magic(magicStartOfAuxVarArray)
- #endif
- {
- }
- SerializedIntArray::SerializedIntArray( uint offset, int intCount ) :
- SerializedAuxiliary(offset, sakIntArray), intCount(intCount)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , magic(magicStartOfAuxIntArray)
- #endif
- {
- }
- SerializedFloatArray::SerializedFloatArray( uint offset, int floatCount ) :
- SerializedAuxiliary(offset, sakFloatArray), floatCount(floatCount)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , magic(magicStartOfAuxFltArray)
- #endif
- {
- }
- SerializedPropertyIdArray::SerializedPropertyIdArray( uint offset, int propertyCount, int extraSlots, bool hadDuplicates, bool has__proto__) :
- SerializedAuxiliary(offset, sakPropertyIdArray), propertyCount(propertyCount), extraSlots(extraSlots), hadDuplicates(hadDuplicates), has__proto__(has__proto__)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , magic(magicStartOfAuxPropIdArray)
- #endif
- {
- }
- SerializedFuncInfoArray::SerializedFuncInfoArray( uint offset, int count ) :
- SerializedAuxiliary(offset, sakFuncInfoArray), count(count)
- #ifdef BYTE_CODE_MAGIC_CONSTANTS
- , magic(magicStartOfAuxFuncInfoArray)
- #endif
- {
- }
- }
|