ThreadContext.cpp 158 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #include "ThreadServiceWrapper.h"
  7. #include "Types/TypePropertyCache.h"
  8. #ifdef ENABLE_SCRIPT_DEBUGGING
  9. #include "Debug/DebuggingFlags.h"
  10. #include "Debug/DiagProbe.h"
  11. #include "Debug/DebugManager.h"
  12. #endif
  13. #include "Chars.h"
  14. #include "CaseInsensitive.h"
  15. #include "CharSet.h"
  16. #include "CharMap.h"
  17. #include "StandardChars.h"
  18. #include "Base/ThreadContextTlsEntry.h"
  19. #include "Base/ThreadBoundThreadContextManager.h"
  20. #include "Language/SourceDynamicProfileManager.h"
  21. #include "Language/CodeGenRecyclableData.h"
  22. #include "Language/InterpreterStackFrame.h"
  23. #include "Language/JavascriptStackWalker.h"
  24. #include "Base/ScriptMemoryDumper.h"
  25. // SIMD_JS
  26. #include "Library/SimdLib.h"
  27. #if DBG
  28. #include "Memory/StressTest.h"
  29. #endif
  30. #ifdef DYNAMIC_PROFILE_MUTATOR
  31. #include "Language/DynamicProfileMutator.h"
  32. #endif
  33. #ifdef ENABLE_BASIC_TELEMETRY
  34. #include "Telemetry.h"
  35. #endif
  36. const int TotalNumberOfBuiltInProperties = Js::PropertyIds::_countJSOnlyProperty;
  37. /*
  38. * When we aren't adding any additional properties
  39. */
  40. void DefaultInitializeAdditionalProperties(ThreadContext *threadContext)
  41. {
  42. }
  43. /*
  44. *
  45. */
  46. void (*InitializeAdditionalProperties)(ThreadContext *threadContext) = DefaultInitializeAdditionalProperties;
  47. // To make sure the marker function doesn't get inlined, optimized away, or merged with other functions we disable optimization.
  48. // If this method ends up causing a perf problem in the future, we should replace it with asm versions which should be lighter.
  49. #pragma optimize("g", off)
  50. _NOINLINE extern "C" void* MarkerForExternalDebugStep()
  51. {
  52. // We need to return something here to prevent this function from being merged with other empty functions by the linker.
  53. static int __dummy;
  54. return &__dummy;
  55. }
  56. #pragma optimize("", on)
  57. CriticalSection ThreadContext::s_csThreadContext;
  58. size_t ThreadContext::processNativeCodeSize = 0;
  59. ThreadContext * ThreadContext::globalListFirst = nullptr;
  60. ThreadContext * ThreadContext::globalListLast = nullptr;
  61. THREAD_LOCAL uint ThreadContext::activeScriptSiteCount = 0;
  62. const Js::PropertyRecord * const ThreadContext::builtInPropertyRecords[] =
  63. {
  64. Js::BuiltInPropertyRecords::EMPTY,
  65. #define ENTRY_INTERNAL_SYMBOL(n) Js::BuiltInPropertyRecords::n,
  66. #define ENTRY_SYMBOL(n, d) Js::BuiltInPropertyRecords::n,
  67. #define ENTRY(n) Js::BuiltInPropertyRecords::n,
  68. #define ENTRY2(n, s) ENTRY(n)
  69. #include "Base/JnDirectFields.h"
  70. };
  71. ThreadContext::RecyclableData::RecyclableData(Recycler *const recycler) :
  72. soErrorObject(nullptr, nullptr, nullptr, true),
  73. oomErrorObject(nullptr, nullptr, nullptr, true),
  74. terminatedErrorObject(nullptr, nullptr, nullptr),
  75. typesWithProtoPropertyCache(recycler),
  76. #if ENABLE_NATIVE_CODEGEN
  77. propertyGuards(recycler, 128),
  78. #endif
  79. oldEntryPointInfo(nullptr),
  80. #ifdef ENABLE_SCRIPT_DEBUGGING
  81. returnedValueList(nullptr),
  82. #endif
  83. constructorCacheInvalidationCount(0)
  84. {
  85. }
  86. ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager, JsUtil::ThreadService::ThreadServiceCallback threadServiceCallback, bool enableExperimentalFeatures) :
  87. currentThreadId(::GetCurrentThreadId()),
  88. stackLimitForCurrentThread(0),
  89. stackProber(nullptr),
  90. isThreadBound(false),
  91. hasThrownPendingException(false),
  92. pendingFinallyException(nullptr),
  93. noScriptScope(false),
  94. heapEnum(nullptr),
  95. threadContextFlags(ThreadContextFlagNoFlag),
  96. JsUtil::DoublyLinkedListElement<ThreadContext>(),
  97. allocationPolicyManager(allocationPolicyManager),
  98. threadService(threadServiceCallback),
  99. isOptimizedForManyInstances(Js::Configuration::Global.flags.OptimizeForManyInstances),
  100. bgJit(Js::Configuration::Global.flags.BgJit),
  101. pageAllocator(allocationPolicyManager, PageAllocatorType_Thread, Js::Configuration::Global.flags, 0, PageAllocator::DefaultMaxFreePageCount,
  102. false
  103. #if ENABLE_BACKGROUND_PAGE_FREEING
  104. , &backgroundPageQueue
  105. #endif
  106. ),
  107. recycler(nullptr),
  108. hasCollectionCallBack(false),
  109. callDispose(true),
  110. #if ENABLE_NATIVE_CODEGEN
  111. jobProcessor(nullptr),
  112. #endif
  113. interruptPoller(nullptr),
  114. expirableCollectModeGcCount(-1),
  115. expirableObjectList(nullptr),
  116. expirableObjectDisposeList(nullptr),
  117. numExpirableObjects(0),
  118. disableExpiration(false),
  119. callRootLevel(0),
  120. nextTypeId((Js::TypeId)Js::Constants::ReservedTypeIds),
  121. entryExitRecord(nullptr),
  122. leafInterpreterFrame(nullptr),
  123. threadServiceWrapper(nullptr),
  124. temporaryArenaAllocatorCount(0),
  125. temporaryGuestArenaAllocatorCount(0),
  126. crefSContextForDiag(0),
  127. m_prereservedRegionAddr(0),
  128. scriptContextList(nullptr),
  129. scriptContextEverRegistered(false),
  130. #if DBG_DUMP || defined(PROFILE_EXEC)
  131. topLevelScriptSite(nullptr),
  132. #endif
  133. polymorphicCacheState(0),
  134. stackProbeCount(0),
  135. #ifdef BAILOUT_INJECTION
  136. bailOutByteCodeLocationCount(0),
  137. #endif
  138. sourceCodeSize(0),
  139. nativeCodeSize(0),
  140. threadAlloc(_u("TC"), GetPageAllocator(), Js::Throw::OutOfMemory),
  141. inlineCacheThreadInfoAllocator(_u("TC-InlineCacheInfo"), GetPageAllocator(), Js::Throw::OutOfMemory),
  142. isInstInlineCacheThreadInfoAllocator(_u("TC-IsInstInlineCacheInfo"), GetPageAllocator(), Js::Throw::OutOfMemory),
  143. equivalentTypeCacheInfoAllocator(_u("TC-EquivalentTypeCacheInfo"), GetPageAllocator(), Js::Throw::OutOfMemory),
  144. preReservedVirtualAllocator(),
  145. protoInlineCacheByPropId(&inlineCacheThreadInfoAllocator, 512),
  146. storeFieldInlineCacheByPropId(&inlineCacheThreadInfoAllocator, 256),
  147. isInstInlineCacheByFunction(&isInstInlineCacheThreadInfoAllocator, 128),
  148. registeredInlineCacheCount(0),
  149. unregisteredInlineCacheCount(0),
  150. prototypeChainEnsuredToHaveOnlyWritableDataPropertiesAllocator(_u("TC-ProtoWritableProp"), GetPageAllocator(), Js::Throw::OutOfMemory),
  151. standardUTF8Chars(0),
  152. standardUnicodeChars(0),
  153. hasUnhandledException(FALSE),
  154. hasCatchHandler(FALSE),
  155. disableImplicitFlags(DisableImplicitNoFlag),
  156. hasCatchHandlerToUserCode(false),
  157. caseInvariantPropertySet(nullptr),
  158. entryPointToBuiltInOperationIdCache(&threadAlloc, 0),
  159. #if ENABLE_NATIVE_CODEGEN
  160. #if !FLOATVAR
  161. codeGenNumberThreadAllocator(nullptr),
  162. xProcNumberPageSegmentManager(nullptr),
  163. #endif
  164. m_jitNumericProperties(nullptr),
  165. m_jitNeedsPropertyUpdate(false),
  166. #if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
  167. thunkPageAllocators(allocationPolicyManager, /* allocXData */ false, /* virtualAllocator */ nullptr, GetCurrentProcess()),
  168. #endif
  169. codePageAllocators(allocationPolicyManager, ALLOC_XDATA, GetPreReservedVirtualAllocator(), GetCurrentProcess()),
  170. #if defined(_CONTROL_FLOW_GUARD) && (_M_IX86 || _M_X64)
  171. jitThunkEmitter(this, &VirtualAllocWrapper::Instance , GetCurrentProcess()),
  172. #endif
  173. #endif
  174. dynamicObjectEnumeratorCacheMap(&HeapAllocator::Instance, 16),
  175. //threadContextFlags(ThreadContextFlagNoFlag),
  176. #ifdef NTBUILD
  177. telemetryBlock(&localTelemetryBlock),
  178. #endif
  179. configuration(enableExperimentalFeatures),
  180. jsrtRuntime(nullptr),
  181. propertyMap(nullptr),
  182. rootPendingClose(nullptr),
  183. exceptionCode(0),
  184. isProfilingUserCode(true),
  185. loopDepth(0),
  186. redeferralState(InitialRedeferralState),
  187. gcSinceLastRedeferral(0),
  188. gcSinceCallCountsCollected(0),
  189. tridentLoadAddress(nullptr),
  190. m_remoteThreadContextInfo(nullptr)
  191. #ifdef ENABLE_SCRIPT_DEBUGGING
  192. , debugManager(nullptr)
  193. #endif
  194. #if ENABLE_TTD
  195. , TTDContext(nullptr)
  196. , TTDExecutionInfo(nullptr)
  197. , TTDLog(nullptr)
  198. , TTDRootNestingCount(0)
  199. #endif
  200. #ifdef ENABLE_DIRECTCALL_TELEMETRY
  201. , directCallTelemetry(this)
  202. #endif
  203. #if ENABLE_JS_REENTRANCY_CHECK
  204. , noJsReentrancy(false)
  205. #endif
  206. {
  207. pendingProjectionContextCloseList = JsUtil::List<IProjectionContext*, ArenaAllocator>::New(GetThreadAlloc());
  208. hostScriptContextStack = Anew(GetThreadAlloc(), JsUtil::Stack<HostScriptContext*>, GetThreadAlloc());
  209. functionCount = 0;
  210. sourceInfoCount = 0;
  211. #if DBG || defined(RUNTIME_DATA_COLLECTION)
  212. scriptContextCount = 0;
  213. #endif
  214. isScriptActive = false;
  215. #ifdef ENABLE_CUSTOM_ENTROPY
  216. entropy.Initialize();
  217. #endif
  218. #if ENABLE_NATIVE_CODEGEN
  219. this->bailOutRegisterSaveSpace = AnewArrayZ(this->GetThreadAlloc(), Js::Var, GetBailOutRegisterSaveSlotCount());
  220. #endif
  221. #if defined(ENABLE_SIMDJS) && ENABLE_NATIVE_CODEGEN
  222. simdFuncInfoToOpcodeMap = Anew(this->GetThreadAlloc(), FuncInfoToOpcodeMap, this->GetThreadAlloc());
  223. simdOpcodeToSignatureMap = AnewArrayZ(this->GetThreadAlloc(), SimdFuncSignature, Js::Simd128OpcodeCount());
  224. {
  225. #define MACRO_SIMD_WMS(op, LayoutAsmJs, OpCodeAttrAsmJs, OpCodeAttr, ...) \
  226. AddSimdFuncToMaps(Js::OpCode::##op, __VA_ARGS__);
  227. #define MACRO_SIMD_EXTEND_WMS(op, LayoutAsmJs, OpCodeAttrAsmJs, OpCodeAttr, ...) MACRO_SIMD_WMS(op, LayoutAsmJs, OpCodeAttrAsmJs, OpCodeAttr, __VA_ARGS__)
  228. #include "ByteCode/OpCodesSimd.h"
  229. }
  230. #endif // defined(ENABLE_SIMDJS) && ENABLE_NATIVE_CODEGEN
  231. #if DBG_DUMP
  232. scriptSiteCount = 0;
  233. pageAllocator.debugName = _u("Thread");
  234. #endif
  235. #ifdef DYNAMIC_PROFILE_MUTATOR
  236. this->dynamicProfileMutator = DynamicProfileMutator::GetMutator();
  237. #endif
  238. PERF_COUNTER_INC(Basic, ThreadContext);
  239. #ifdef LEAK_REPORT
  240. this->rootTrackerScriptContext = nullptr;
  241. this->threadId = ::GetCurrentThreadId();
  242. #endif
  243. #ifdef NTBUILD
  244. memset(&localTelemetryBlock, 0, sizeof(localTelemetryBlock));
  245. #endif
  246. AutoCriticalSection autocs(ThreadContext::GetCriticalSection());
  247. ThreadContext::LinkToBeginning(this, &ThreadContext::globalListFirst, &ThreadContext::globalListLast);
  248. #if DBG
  249. // Since we created our page allocator while we were constructing this thread context
  250. // it will pick up the thread context id that is current on the thread. We need to update
  251. // that now.
  252. pageAllocator.UpdateThreadContextHandle((ThreadContextId)this);
  253. #endif
  254. #ifdef ENABLE_PROJECTION
  255. #if DBG_DUMP
  256. this->projectionMemoryInformation = nullptr;
  257. #endif
  258. #endif
  259. this->InitAvailableCommit();
  260. }
  261. void ThreadContext::InitAvailableCommit()
  262. {
  263. // Once per process: get the available commit for the process from the OS and push it to the AutoSystemInfo.
  264. // (This must be done lazily, outside DllMain. And it must be done from the Runtime, since the common lib
  265. // doesn't have access to the DelayLoadLibrary stuff.)
  266. ULONG64 commit;
  267. BOOL success = AutoSystemInfo::Data.GetAvailableCommit(&commit);
  268. if (!success)
  269. {
  270. commit = (ULONG64)-1;
  271. #ifdef NTBUILD
  272. APP_MEMORY_INFORMATION AppMemInfo;
  273. success = GetWinCoreProcessThreads()->GetProcessInformation(
  274. GetCurrentProcess(),
  275. ProcessAppMemoryInfo,
  276. &AppMemInfo,
  277. sizeof(AppMemInfo));
  278. if (success)
  279. {
  280. commit = AppMemInfo.AvailableCommit;
  281. }
  282. #endif
  283. AutoSystemInfo::Data.SetAvailableCommit(commit);
  284. }
  285. }
  286. void ThreadContext::SetStackProber(StackProber * stackProber)
  287. {
  288. this->stackProber = stackProber;
  289. if (stackProber != NULL && this->stackLimitForCurrentThread != Js::Constants::StackLimitForScriptInterrupt)
  290. {
  291. this->stackLimitForCurrentThread = stackProber->GetScriptStackLimit();
  292. }
  293. }
  294. size_t ThreadContext::GetScriptStackLimit() const
  295. {
  296. return stackProber->GetScriptStackLimit();
  297. }
  298. HANDLE
  299. ThreadContext::GetProcessHandle() const
  300. {
  301. return GetCurrentProcess();
  302. }
  303. intptr_t
  304. ThreadContext::GetThreadStackLimitAddr() const
  305. {
  306. return (intptr_t)GetAddressOfStackLimitForCurrentThread();
  307. }
  308. #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_SIMDJS) && (defined(_M_IX86) || defined(_M_X64))
  309. intptr_t
  310. ThreadContext::GetSimdTempAreaAddr(uint8 tempIndex) const
  311. {
  312. return (intptr_t)&X86_TEMP_SIMD[tempIndex];
  313. }
  314. #endif
  315. intptr_t
  316. ThreadContext::GetDisableImplicitFlagsAddr() const
  317. {
  318. return (intptr_t)&disableImplicitFlags;
  319. }
  320. intptr_t
  321. ThreadContext::GetImplicitCallFlagsAddr() const
  322. {
  323. return (intptr_t)&implicitCallFlags;
  324. }
  325. ptrdiff_t
  326. ThreadContext::GetChakraBaseAddressDifference() const
  327. {
  328. return 0;
  329. }
  330. ptrdiff_t
  331. ThreadContext::GetCRTBaseAddressDifference() const
  332. {
  333. return 0;
  334. }
  335. IActiveScriptProfilerHeapEnum* ThreadContext::GetHeapEnum()
  336. {
  337. return heapEnum;
  338. }
  339. void ThreadContext::SetHeapEnum(IActiveScriptProfilerHeapEnum* newHeapEnum)
  340. {
  341. Assert((newHeapEnum != nullptr && heapEnum == nullptr) || (newHeapEnum == nullptr && heapEnum != nullptr));
  342. heapEnum = newHeapEnum;
  343. }
  344. void ThreadContext::ClearHeapEnum()
  345. {
  346. Assert(heapEnum != nullptr);
  347. heapEnum = nullptr;
  348. }
  349. void ThreadContext::GlobalInitialize()
  350. {
  351. for (int i = 0; i < _countof(builtInPropertyRecords); i++)
  352. {
  353. builtInPropertyRecords[i]->SetHash(JsUtil::CharacterBuffer<WCHAR>::StaticGetHashCode(builtInPropertyRecords[i]->GetBuffer(), builtInPropertyRecords[i]->GetLength()));
  354. }
  355. }
  356. ThreadContext::~ThreadContext()
  357. {
  358. {
  359. AutoCriticalSection autocs(ThreadContext::GetCriticalSection());
  360. ThreadContext::Unlink(this, &ThreadContext::globalListFirst, &ThreadContext::globalListLast);
  361. }
  362. #if ENABLE_TTD
  363. if(this->TTDContext != nullptr)
  364. {
  365. TT_HEAP_DELETE(TTD::ThreadContextTTD, this->TTDContext);
  366. this->TTDContext = nullptr;
  367. }
  368. if(this->TTDExecutionInfo != nullptr)
  369. {
  370. TT_HEAP_DELETE(TTD::ThreadContextTTD, this->TTDExecutionInfo);
  371. this->TTDExecutionInfo = nullptr;
  372. }
  373. if(this->TTDLog != nullptr)
  374. {
  375. TT_HEAP_DELETE(TTD::EventLog, this->TTDLog);
  376. this->TTDLog = nullptr;
  377. }
  378. #endif
  379. #ifdef LEAK_REPORT
  380. if (Js::Configuration::Global.flags.IsEnabled(Js::LeakReportFlag))
  381. {
  382. AUTO_LEAK_REPORT_SECTION(Js::Configuration::Global.flags, _u("Thread Context (%p): %s (TID: %d)"), this,
  383. this->GetRecycler()->IsInDllCanUnloadNow()? _u("DllCanUnloadNow") :
  384. this->GetRecycler()->IsInDetachProcess()? _u("DetachProcess") : _u("Destructor"), this->threadId);
  385. LeakReport::DumpUrl(this->threadId);
  386. }
  387. #endif
  388. if (interruptPoller)
  389. {
  390. HeapDelete(interruptPoller);
  391. interruptPoller = nullptr;
  392. }
  393. #if DBG
  394. // ThreadContext dtor may be running on a different thread.
  395. // Recycler may call finalizer that free temp Arenas, which will free pages back to
  396. // the page Allocator, which will try to suspend idle on a different thread.
  397. // So we need to disable idle decommit asserts.
  398. pageAllocator.ShutdownIdleDecommit();
  399. #endif
  400. // Allocating memory during the shutdown codepath is not preferred
  401. // so we'll close the page allocator before we release the GC
  402. // If any dispose is allocating memory during shutdown, that is a bug
  403. pageAllocator.Close();
  404. // The recycler need to delete before the background code gen thread
  405. // because that might run finalizer which need access to the background code gen thread.
  406. if (recycler != nullptr)
  407. {
  408. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext; scriptContext = scriptContext->next)
  409. {
  410. if (!scriptContext->IsActuallyClosed())
  411. {
  412. // We close ScriptContext here because anyhow HeapDelete(recycler) when disposing the
  413. // JavaScriptLibrary will close ScriptContext. Explicit close gives us chance to clear
  414. // other things to which ScriptContext holds reference to
  415. AssertMsg(!IsInScript(), "Can we be in script here?");
  416. scriptContext->MarkForClose();
  417. }
  418. }
  419. // If all scriptContext's have been closed, then the sourceProfileManagersByUrl
  420. // should have been released
  421. AssertMsg(this->recyclableData->sourceProfileManagersByUrl == nullptr ||
  422. this->recyclableData->sourceProfileManagersByUrl->Count() == 0, "There seems to have been a refcounting imbalance.");
  423. this->recyclableData->sourceProfileManagersByUrl = nullptr;
  424. this->recyclableData->oldEntryPointInfo = nullptr;
  425. if (this->recyclableData->symbolRegistrationMap != nullptr)
  426. {
  427. this->recyclableData->symbolRegistrationMap->Clear();
  428. this->recyclableData->symbolRegistrationMap = nullptr;
  429. }
  430. #ifdef ENABLE_SCRIPT_DEBUGGING
  431. if (this->recyclableData->returnedValueList != nullptr)
  432. {
  433. this->recyclableData->returnedValueList->Clear();
  434. this->recyclableData->returnedValueList = nullptr;
  435. }
  436. #endif
  437. if (this->propertyMap != nullptr)
  438. {
  439. HeapDelete(this->propertyMap);
  440. this->propertyMap = nullptr;
  441. }
  442. #if ENABLE_NATIVE_CODEGEN
  443. if (this->m_jitNumericProperties != nullptr)
  444. {
  445. HeapDelete(this->m_jitNumericProperties);
  446. this->m_jitNumericProperties = nullptr;
  447. }
  448. #endif
  449. // Unpin the memory for leak report so we don't report this as a leak.
  450. recyclableData.Unroot(recycler);
  451. #if defined(LEAK_REPORT) || defined(CHECK_MEMORY_LEAK)
  452. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext; scriptContext = scriptContext->next)
  453. {
  454. scriptContext->ClearSourceContextInfoMaps();
  455. scriptContext->ShutdownClearSourceLists();
  456. }
  457. #ifdef LEAK_REPORT
  458. // heuristically figure out which one is the root tracker script engine
  459. // and force close on it
  460. if (this->rootTrackerScriptContext != nullptr)
  461. {
  462. this->rootTrackerScriptContext->Close(false);
  463. }
  464. #endif
  465. #endif
  466. #if ENABLE_NATIVE_CODEGEN
  467. #if !FLOATVAR
  468. if (this->codeGenNumberThreadAllocator)
  469. {
  470. HeapDelete(this->codeGenNumberThreadAllocator);
  471. this->codeGenNumberThreadAllocator = nullptr;
  472. }
  473. if (this->xProcNumberPageSegmentManager)
  474. {
  475. HeapDelete(this->xProcNumberPageSegmentManager);
  476. this->xProcNumberPageSegmentManager = nullptr;
  477. }
  478. #endif
  479. #endif
  480. #ifdef ENABLE_SCRIPT_DEBUGGING
  481. Assert(this->debugManager == nullptr);
  482. #endif
  483. HeapDelete(recycler);
  484. }
  485. #if ENABLE_NATIVE_CODEGEN
  486. if(jobProcessor)
  487. {
  488. if(this->bgJit)
  489. {
  490. HeapDelete(static_cast<JsUtil::BackgroundJobProcessor *>(jobProcessor));
  491. }
  492. else
  493. {
  494. HeapDelete(static_cast<JsUtil::ForegroundJobProcessor *>(jobProcessor));
  495. }
  496. jobProcessor = nullptr;
  497. }
  498. #endif
  499. // Do not require all GC callbacks to be revoked, because Trident may not revoke if there
  500. // is a leak, and we don't want the leak to be masked by an assert
  501. #ifdef ENABLE_PROJECTION
  502. externalWeakReferenceCacheList.Clear(&HeapAllocator::Instance);
  503. #endif
  504. this->collectCallBackList.Clear(&HeapAllocator::Instance);
  505. this->protoInlineCacheByPropId.Reset();
  506. this->storeFieldInlineCacheByPropId.Reset();
  507. this->isInstInlineCacheByFunction.Reset();
  508. this->equivalentTypeCacheEntryPoints.Reset();
  509. this->prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext.Reset();
  510. this->registeredInlineCacheCount = 0;
  511. this->unregisteredInlineCacheCount = 0;
  512. AssertMsg(this->GetHeapEnum() == nullptr, "Heap enumeration should have been cleared/closed by the ScriptSite.");
  513. if (this->GetHeapEnum() != nullptr)
  514. {
  515. this->ClearHeapEnum();
  516. }
  517. #ifdef BAILOUT_INJECTION
  518. if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutByteCodeFlag)
  519. && Js::Configuration::Global.flags.BailOutByteCode.Empty())
  520. {
  521. Output::Print(_u("Bail out byte code location count: %d"), this->bailOutByteCodeLocationCount);
  522. }
  523. #endif
  524. Assert(processNativeCodeSize >= nativeCodeSize);
  525. ::InterlockedExchangeSubtract(&processNativeCodeSize, nativeCodeSize);
  526. PERF_COUNTER_DEC(Basic, ThreadContext);
  527. #ifdef DYNAMIC_PROFILE_MUTATOR
  528. if (this->dynamicProfileMutator != nullptr)
  529. {
  530. this->dynamicProfileMutator->Delete();
  531. }
  532. #endif
  533. #ifdef ENABLE_PROJECTION
  534. #if DBG_DUMP
  535. if (this->projectionMemoryInformation)
  536. {
  537. this->projectionMemoryInformation->Release();
  538. this->projectionMemoryInformation = nullptr;
  539. }
  540. #endif
  541. #endif
  542. }
  543. void
  544. ThreadContext::SetJSRTRuntime(void* runtime)
  545. {
  546. Assert(jsrtRuntime == nullptr);
  547. jsrtRuntime = runtime;
  548. #ifdef ENABLE_BASIC_TELEMETRY
  549. Telemetry::EnsureInitializeForJSRT();
  550. #endif
  551. }
  552. void ThreadContext::CloseForJSRT()
  553. {
  554. // This is used for JSRT APIs only.
  555. Assert(this->jsrtRuntime);
  556. #ifdef ENABLE_BASIC_TELEMETRY
  557. // log any relevant telemetry before disposing the current thread for cases which are properly shutdown
  558. Telemetry::OnJSRTThreadContextClose();
  559. #endif
  560. ShutdownThreads();
  561. }
  562. ThreadContext* ThreadContext::GetContextForCurrentThread()
  563. {
  564. ThreadContextTLSEntry * tlsEntry = ThreadContextTLSEntry::GetEntryForCurrentThread();
  565. if (tlsEntry != nullptr)
  566. {
  567. return static_cast<ThreadContext *>(tlsEntry->GetThreadContext());
  568. }
  569. return nullptr;
  570. }
  571. void ThreadContext::ValidateThreadContext()
  572. {
  573. #if DBG
  574. // verify the runtime pointer is valid.
  575. {
  576. BOOL found = FALSE;
  577. AutoCriticalSection autocs(ThreadContext::GetCriticalSection());
  578. ThreadContext* currentThreadContext = GetThreadContextList();
  579. while (currentThreadContext)
  580. {
  581. if (currentThreadContext == this)
  582. {
  583. return;
  584. }
  585. currentThreadContext = currentThreadContext->Next();
  586. }
  587. AssertMsg(found, "invalid thread context");
  588. }
  589. #endif
  590. }
  591. #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_SIMDJS)
  592. void ThreadContext::AddSimdFuncToMaps(Js::OpCode op, ...)
  593. {
  594. Assert(simdFuncInfoToOpcodeMap != nullptr);
  595. Assert(simdOpcodeToSignatureMap != nullptr);
  596. va_list arguments;
  597. va_start(arguments, op);
  598. int argumentsCount = va_arg(arguments, int);
  599. AssertMsg(argumentsCount >= 0 && argumentsCount <= 20, "Invalid arguments count for SIMD opcode");
  600. if (argumentsCount == 0)
  601. {
  602. // no info to add
  603. return;
  604. }
  605. Js::FunctionInfo *funcInfo = va_arg(arguments, Js::FunctionInfo*);
  606. AddSimdFuncInfo(op, funcInfo);
  607. SimdFuncSignature simdFuncSignature;
  608. simdFuncSignature.valid = true;
  609. simdFuncSignature.argCount = argumentsCount - 2; // arg count to Simd func = argumentsCount - FuncInfo and return Type fields.
  610. simdFuncSignature.returnType = va_arg(arguments, ValueType);
  611. simdFuncSignature.args = AnewArrayZ(this->GetThreadAlloc(), ValueType, simdFuncSignature.argCount);
  612. for (uint iArg = 0; iArg < simdFuncSignature.argCount; iArg++)
  613. {
  614. simdFuncSignature.args[iArg] = va_arg(arguments, ValueType);
  615. }
  616. simdOpcodeToSignatureMap[Js::SIMDUtils::SimdOpcodeAsIndex(op)] = simdFuncSignature;
  617. va_end(arguments);
  618. }
  619. void ThreadContext::AddSimdFuncInfo(Js::OpCode op, Js::FunctionInfo *funcInfo)
  620. {
  621. // primary funcInfo
  622. simdFuncInfoToOpcodeMap->AddNew(funcInfo, op);
  623. // Entry points of SIMD loads/stores of non-full width all map to the same opcode. This is not captured in the opcode table, so add additional entry points here.
  624. switch (op)
  625. {
  626. case Js::OpCode::Simd128_LdArr_F4:
  627. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Load1, op);
  628. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Load2, op);
  629. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Load3, op);
  630. break;
  631. case Js::OpCode::Simd128_StArr_F4:
  632. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Store1, op);
  633. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Store2, op);
  634. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDFloat32x4Lib::EntryInfo::Store3, op);
  635. break;
  636. case Js::OpCode::Simd128_LdArr_I4:
  637. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Load1, op);
  638. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Load2, op);
  639. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Load3, op);
  640. break;
  641. case Js::OpCode::Simd128_StArr_I4:
  642. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Store1, op);
  643. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Store2, op);
  644. simdFuncInfoToOpcodeMap->AddNew(&Js::SIMDInt32x4Lib::EntryInfo::Store3, op);
  645. break;
  646. }
  647. }
  648. Js::OpCode ThreadContext::GetSimdOpcodeFromFuncInfo(Js::FunctionInfo * funcInfo)
  649. {
  650. Assert(simdFuncInfoToOpcodeMap != nullptr);
  651. if (simdFuncInfoToOpcodeMap->ContainsKey(funcInfo))
  652. {
  653. return simdFuncInfoToOpcodeMap->Item(funcInfo);
  654. }
  655. return (Js::OpCode) 0;
  656. }
  657. void ThreadContext::GetSimdFuncSignatureFromOpcode(Js::OpCode op, SimdFuncSignature &funcSignature)
  658. {
  659. Assert(simdOpcodeToSignatureMap != nullptr);
  660. funcSignature = simdOpcodeToSignatureMap[Js::SIMDUtils::SimdOpcodeAsIndex(op)];
  661. }
  662. #endif
  663. class AutoRecyclerPtr : public AutoPtr<Recycler>
  664. {
  665. public:
  666. AutoRecyclerPtr(Recycler * ptr) : AutoPtr<Recycler>(ptr) {}
  667. ~AutoRecyclerPtr()
  668. {
  669. #if ENABLE_CONCURRENT_GC
  670. if (ptr != nullptr)
  671. {
  672. ptr->ShutdownThread();
  673. }
  674. #endif
  675. }
  676. };
  677. Recycler* ThreadContext::EnsureRecycler()
  678. {
  679. if (recycler == NULL)
  680. {
  681. AutoRecyclerPtr newRecycler(HeapNew(Recycler, GetAllocationPolicyManager(), &pageAllocator, Js::Throw::OutOfMemory, Js::Configuration::Global.flags));
  682. newRecycler->Initialize(isOptimizedForManyInstances, &threadService); // use in-thread GC when optimizing for many instances
  683. newRecycler->SetCollectionWrapper(this);
  684. #if ENABLE_NATIVE_CODEGEN
  685. // This may throw, so it needs to be after the recycler is initialized,
  686. // otherwise, the recycler dtor may encounter problems
  687. #if !FLOATVAR
  688. // TODO: we only need one of the following, one for OOP jit and one for in-proc BG JIT
  689. AutoPtr<CodeGenNumberThreadAllocator> localCodeGenNumberThreadAllocator(
  690. HeapNew(CodeGenNumberThreadAllocator, newRecycler));
  691. AutoPtr<XProcNumberPageSegmentManager> localXProcNumberPageSegmentManager(
  692. HeapNew(XProcNumberPageSegmentManager, newRecycler));
  693. #endif
  694. #endif
  695. this->recyclableData.Root(RecyclerNewZ(newRecycler, RecyclableData, newRecycler), newRecycler);
  696. if (this->IsThreadBound())
  697. {
  698. newRecycler->SetIsThreadBound();
  699. }
  700. // Assign the recycler to the ThreadContext after everything is initialized, because an OOM during initialization would
  701. // result in only partial initialization, so the 'recycler' member variable should remain null to cause full
  702. // reinitialization when requested later. Anything that happens after the Detach must have special cleanup code.
  703. this->recycler = newRecycler.Detach();
  704. try
  705. {
  706. #ifdef RECYCLER_WRITE_BARRIER
  707. #ifdef _M_X64_OR_ARM64
  708. if (!RecyclerWriteBarrierManager::OnThreadInit())
  709. {
  710. Js::Throw::OutOfMemory();
  711. }
  712. #endif
  713. #endif
  714. this->expirableObjectList = Anew(&this->threadAlloc, ExpirableObjectList, &this->threadAlloc);
  715. this->expirableObjectDisposeList = Anew(&this->threadAlloc, ExpirableObjectList, &this->threadAlloc);
  716. InitializePropertyMaps(); // has many dependencies on the recycler and other members of the thread context
  717. #if ENABLE_NATIVE_CODEGEN
  718. #if !FLOATVAR
  719. this->codeGenNumberThreadAllocator = localCodeGenNumberThreadAllocator.Detach();
  720. this->xProcNumberPageSegmentManager = localXProcNumberPageSegmentManager.Detach();
  721. #endif
  722. #endif
  723. }
  724. catch(...)
  725. {
  726. // Initialization failed, undo what was done above. Callees that throw must clean up after themselves.
  727. if (this->recyclableData != nullptr)
  728. {
  729. this->recyclableData.Unroot(this->recycler);
  730. }
  731. {
  732. // AutoRecyclerPtr's destructor takes care of shutting down the background thread and deleting the recycler
  733. AutoRecyclerPtr recyclerToDelete(this->recycler);
  734. this->recycler = nullptr;
  735. }
  736. throw;
  737. }
  738. JS_ETW(EventWriteJSCRIPT_GC_INIT(this->recycler, this->GetHiResTimer()->Now()));
  739. }
  740. #if DBG
  741. if (CONFIG_FLAG(RecyclerTest))
  742. {
  743. StressTester test(recycler);
  744. test.Run();
  745. }
  746. #endif
  747. return recycler;
  748. }
  749. Js::PropertyRecord const *
  750. ThreadContext::GetPropertyName(Js::PropertyId propertyId)
  751. {
  752. // This API should only be use on the main thread
  753. Assert(GetCurrentThreadContextId() == (ThreadContextId)this);
  754. return this->GetPropertyNameImpl<false>(propertyId);
  755. }
  756. Js::PropertyRecord const *
  757. ThreadContext::GetPropertyNameLocked(Js::PropertyId propertyId)
  758. {
  759. return GetPropertyNameImpl<true>(propertyId);
  760. }
  761. template <bool locked>
  762. Js::PropertyRecord const *
  763. ThreadContext::GetPropertyNameImpl(Js::PropertyId propertyId)
  764. {
  765. //TODO: Remove this when completely transformed to use PropertyRecord*. Currently this is only partially done,
  766. // and there are calls to GetPropertyName with InternalPropertyId.
  767. if (propertyId >= 0 && Js::IsInternalPropertyId(propertyId))
  768. {
  769. return Js::InternalPropertyRecords::GetInternalPropertyName(propertyId);
  770. }
  771. int propertyIndex = propertyId - Js::PropertyIds::_none;
  772. if (propertyIndex < 0 || propertyIndex > propertyMap->GetLastIndex())
  773. {
  774. propertyIndex = 0;
  775. }
  776. const Js::PropertyRecord * propertyRecord = nullptr;
  777. if (locked) { propertyMap->LockResize(); }
  778. bool found = propertyMap->TryGetValueAt(propertyIndex, &propertyRecord);
  779. if (locked) { propertyMap->UnlockResize(); }
  780. AssertMsg(found && propertyRecord != nullptr, "using invalid propertyid");
  781. return propertyRecord;
  782. }
  783. void
  784. ThreadContext::FindPropertyRecord(Js::JavascriptString *pstName, Js::PropertyRecord const ** propertyRecord)
  785. {
  786. LPCWSTR psz = pstName->GetSz();
  787. FindPropertyRecord(psz, pstName->GetLength(), propertyRecord);
  788. }
  789. void
  790. ThreadContext::FindPropertyRecord(__in LPCWSTR propertyName, __in int propertyNameLength, Js::PropertyRecord const ** propertyRecord)
  791. {
  792. EnterPinnedScope((volatile void **)propertyRecord);
  793. *propertyRecord = FindPropertyRecord(propertyName, propertyNameLength);
  794. LeavePinnedScope();
  795. }
  796. Js::PropertyRecord const *
  797. ThreadContext::GetPropertyRecord(Js::PropertyId propertyId)
  798. {
  799. return GetPropertyNameLocked(propertyId);
  800. }
  801. bool
  802. ThreadContext::IsNumericProperty(Js::PropertyId propertyId)
  803. {
  804. return GetPropertyRecord(propertyId)->IsNumeric();
  805. }
  806. const Js::PropertyRecord *
  807. ThreadContext::FindPropertyRecord(const char16 * propertyName, int propertyNameLength)
  808. {
  809. Js::PropertyRecord const * propertyRecord = nullptr;
  810. if (IsDirectPropertyName(propertyName, propertyNameLength))
  811. {
  812. propertyRecord = propertyNamesDirect[propertyName[0]];
  813. Assert(propertyRecord == propertyMap->LookupWithKey(Js::HashedCharacterBuffer<char16>(propertyName, propertyNameLength)));
  814. }
  815. else
  816. {
  817. propertyRecord = propertyMap->LookupWithKey(Js::HashedCharacterBuffer<char16>(propertyName, propertyNameLength));
  818. }
  819. return propertyRecord;
  820. }
  821. Js::PropertyRecord const *
  822. ThreadContext::UncheckedAddPropertyId(__in LPCWSTR propertyName, __in int propertyNameLength, bool bind, bool isSymbol)
  823. {
  824. return UncheckedAddPropertyId(JsUtil::CharacterBuffer<WCHAR>(propertyName, propertyNameLength), bind, isSymbol);
  825. }
  826. void ThreadContext::InitializePropertyMaps()
  827. {
  828. Assert(this->recycler != nullptr);
  829. Assert(this->recyclableData != nullptr);
  830. Assert(this->propertyMap == nullptr);
  831. Assert(this->caseInvariantPropertySet == nullptr);
  832. try
  833. {
  834. this->propertyMap = HeapNew(PropertyMap, &HeapAllocator::Instance, TotalNumberOfBuiltInProperties + 700);
  835. this->recyclableData->boundPropertyStrings = RecyclerNew(this->recycler, JsUtil::List<Js::PropertyRecord const*>, this->recycler);
  836. memset(propertyNamesDirect, 0, 128*sizeof(Js::PropertyRecord *));
  837. Js::JavascriptLibrary::InitializeProperties(this);
  838. InitializeAdditionalProperties(this);
  839. //Js::JavascriptLibrary::InitializeDOMProperties(this);
  840. }
  841. catch(...)
  842. {
  843. // Initialization failed, undo what was done above. Callees that throw must clean up after themselves. The recycler will
  844. // be trashed, so clear members that point to recyclable memory. Stuff in 'recyclableData' will be taken care of by the
  845. // recycler, and the 'recyclableData' instance will be trashed as well.
  846. if (this->propertyMap != nullptr)
  847. {
  848. HeapDelete(this->propertyMap);
  849. }
  850. this->propertyMap = nullptr;
  851. this->caseInvariantPropertySet = nullptr;
  852. memset(propertyNamesDirect, 0, 128*sizeof(Js::PropertyRecord *));
  853. throw;
  854. }
  855. }
  856. void ThreadContext::UncheckedAddBuiltInPropertyId()
  857. {
  858. for (int i = 0; i < _countof(builtInPropertyRecords); i++)
  859. {
  860. AddPropertyRecordInternal(builtInPropertyRecords[i]);
  861. }
  862. }
  863. bool
  864. ThreadContext::IsDirectPropertyName(const char16 * propertyName, int propertyNameLength)
  865. {
  866. return ((propertyNameLength == 1) && ((propertyName[0] & 0xFF80) == 0));
  867. }
  868. RecyclerWeakReference<const Js::PropertyRecord> *
  869. ThreadContext::CreatePropertyRecordWeakRef(const Js::PropertyRecord * propertyRecord)
  870. {
  871. RecyclerWeakReference<const Js::PropertyRecord> * propertyRecordWeakRef;
  872. if (propertyRecord->IsBound())
  873. {
  874. // Create a fake weak ref
  875. propertyRecordWeakRef = RecyclerNewLeaf(this->recycler, StaticPropertyRecordReference, propertyRecord);
  876. }
  877. else
  878. {
  879. propertyRecordWeakRef = recycler->CreateWeakReferenceHandle(propertyRecord);
  880. }
  881. return propertyRecordWeakRef;
  882. }
  883. Js::PropertyRecord const *
  884. ThreadContext::UncheckedAddPropertyId(JsUtil::CharacterBuffer<WCHAR> const& propertyName, bool bind, bool isSymbol)
  885. {
  886. #if ENABLE_TTD
  887. if(isSymbol & this->IsRuntimeInTTDMode())
  888. {
  889. if(this->TTDContext->GetActiveScriptContext() != nullptr && this->TTDContext->GetActiveScriptContext()->ShouldPerformReplayAction())
  890. {
  891. //We reload all properties that occour in the trace so they only way we get here in TTD mode is:
  892. //(1) if the program is creating a new symbol (which always gets a fresh id) and we should recreate it or
  893. //(2) if it is forcing arguments in debug parse mode (instead of regular which we recorded in)
  894. Js::PropertyId propertyId = Js::Constants::NoProperty;
  895. this->TTDLog->ReplaySymbolCreationEvent(&propertyId);
  896. //Don't recreate the symbol below, instead return the known symbol by looking up on the pid
  897. const Js::PropertyRecord* res = this->GetPropertyName(propertyId);
  898. AssertMsg(res != nullptr, "This should never happen!!!");
  899. return res;
  900. }
  901. }
  902. #endif
  903. this->propertyMap->EnsureCapacity();
  904. // Automatically bind direct (single-character) property names, so that they can be
  905. // stored in the direct property table
  906. if (IsDirectPropertyName(propertyName.GetBuffer(), propertyName.GetLength()))
  907. {
  908. bind = true;
  909. }
  910. // Create the PropertyRecord
  911. int length = propertyName.GetLength();
  912. uint bytelength = sizeof(char16) * length;
  913. size_t allocLength = bytelength + sizeof(char16) + ( (!isSymbol && length <= 10 && length > 0) ? sizeof(uint32) : 0);
  914. // If it's bound, create it in the thread arena, along with a fake weak ref
  915. Js::PropertyRecord * propertyRecord;
  916. if (bind)
  917. {
  918. propertyRecord = AnewPlus(GetThreadAlloc(), allocLength, Js::PropertyRecord, propertyName.GetBuffer(), length, bytelength, isSymbol);
  919. propertyRecord->isBound = true;
  920. }
  921. else
  922. {
  923. propertyRecord = RecyclerNewFinalizedLeafPlus(recycler, allocLength, Js::PropertyRecord, propertyName.GetBuffer(), length, bytelength, isSymbol);
  924. }
  925. Js::PropertyId propertyId = this->GetNextPropertyId();
  926. #if ENABLE_TTD
  927. if(isSymbol & this->IsRuntimeInTTDMode())
  928. {
  929. if(this->TTDContext->GetActiveScriptContext() != nullptr && this->TTDContext->GetActiveScriptContext()->ShouldPerformRecordAction())
  930. {
  931. this->TTDLog->RecordSymbolCreationEvent(propertyId);
  932. }
  933. }
  934. #endif
  935. propertyRecord->pid = propertyId;
  936. AddPropertyRecordInternal(propertyRecord);
  937. return propertyRecord;
  938. }
  939. void
  940. ThreadContext::AddPropertyRecordInternal(const Js::PropertyRecord * propertyRecord)
  941. {
  942. // At this point the PropertyRecord is constructed but not added to the map.
  943. const char16 * propertyName = propertyRecord->GetBuffer();
  944. int propertyNameLength = propertyRecord->GetLength();
  945. Js::PropertyId propertyId = propertyRecord->GetPropertyId();
  946. Assert(propertyId == GetNextPropertyId());
  947. Assert(!IsActivePropertyId(propertyId));
  948. #if DBG
  949. // Only Assert we can't find the property if we are not adding a symbol.
  950. // For a symbol, the propertyName is not used and may collide with something in the map already.
  951. if (!propertyRecord->IsSymbol())
  952. {
  953. Assert(FindPropertyRecord(propertyName, propertyNameLength) == nullptr);
  954. }
  955. #endif
  956. #if ENABLE_TTD
  957. if(this->IsRuntimeInTTDMode())
  958. {
  959. this->TTDLog->AddPropertyRecord(propertyRecord);
  960. }
  961. #endif
  962. // Add to the map
  963. propertyMap->Add(propertyRecord);
  964. #if ENABLE_NATIVE_CODEGEN
  965. if (m_jitNumericProperties)
  966. {
  967. if (propertyRecord->IsNumeric())
  968. {
  969. m_jitNumericProperties->Set(propertyRecord->GetPropertyId());
  970. m_jitNeedsPropertyUpdate = true;
  971. }
  972. }
  973. #endif
  974. PropertyRecordTrace(_u("Added property '%s' at 0x%08x, pid = %d\n"), propertyName, propertyRecord, propertyId);
  975. // Do not store the pid for symbols in the direct property name table.
  976. // We don't want property ids for symbols to be searchable anyway.
  977. if (!propertyRecord->IsSymbol() && IsDirectPropertyName(propertyName, propertyNameLength))
  978. {
  979. // Store the pids for single character properties in the propertyNamesDirect array.
  980. // This property record should have been created as bound by the caller.
  981. Assert(propertyRecord->IsBound());
  982. Assert(propertyNamesDirect[propertyName[0]] == nullptr);
  983. propertyNamesDirect[propertyName[0]] = propertyRecord;
  984. }
  985. if (caseInvariantPropertySet)
  986. {
  987. AddCaseInvariantPropertyRecord(propertyRecord);
  988. }
  989. // Check that everything was added correctly
  990. #if DBG
  991. // Only Assert we can find the property if we are not adding a symbol.
  992. // For a symbol, the propertyName is not used and we won't be able to look the pid up via name.
  993. if (!propertyRecord->IsSymbol())
  994. {
  995. Assert(FindPropertyRecord(propertyName, propertyNameLength) == propertyRecord);
  996. }
  997. // We will still be able to lookup the symbol property by the property id, so go ahead and check that.
  998. Assert(GetPropertyName(propertyRecord->GetPropertyId()) == propertyRecord);
  999. #endif
  1000. JS_ETW_INTERNAL(EventWriteJSCRIPT_HOSTING_PROPERTYID_LIST(propertyRecord, propertyRecord->GetBuffer()));
  1001. }
  1002. void
  1003. ThreadContext::AddCaseInvariantPropertyRecord(const Js::PropertyRecord * propertyRecord)
  1004. {
  1005. Assert(this->caseInvariantPropertySet != nullptr);
  1006. // Create a weak reference to the property record here (since we no longer use weak refs in the property map)
  1007. RecyclerWeakReference<const Js::PropertyRecord> * propertyRecordWeakRef = CreatePropertyRecordWeakRef(propertyRecord);
  1008. JsUtil::CharacterBuffer<WCHAR> newPropertyName(propertyRecord->GetBuffer(), propertyRecord->GetLength());
  1009. Js::CaseInvariantPropertyListWithHashCode* list;
  1010. if (!FindExistingPropertyRecord(newPropertyName, &list))
  1011. {
  1012. // This binds all the property string that is key in this map with no hope of reclaiming them
  1013. // TODO: do better
  1014. list = RecyclerNew(recycler, Js::CaseInvariantPropertyListWithHashCode, recycler, 1);
  1015. // Do the add first so that the list is non-empty and we can calculate its hashcode correctly
  1016. list->Add(propertyRecordWeakRef);
  1017. // This will calculate the hashcode
  1018. caseInvariantPropertySet->Add(list);
  1019. }
  1020. else
  1021. {
  1022. list->Add(propertyRecordWeakRef);
  1023. }
  1024. }
  1025. void
  1026. ThreadContext::BindPropertyRecord(const Js::PropertyRecord * propertyRecord)
  1027. {
  1028. if (!propertyRecord->IsBound())
  1029. {
  1030. Assert(!this->recyclableData->boundPropertyStrings->Contains(propertyRecord));
  1031. this->recyclableData->boundPropertyStrings->Add(propertyRecord);
  1032. // Cast around constness to set propertyRecord as bound
  1033. const_cast<Js::PropertyRecord *>(propertyRecord)->isBound = true;
  1034. }
  1035. }
  1036. void ThreadContext::GetOrAddPropertyId(__in LPCWSTR propertyName, __in int propertyNameLength, Js::PropertyRecord const ** propertyRecord)
  1037. {
  1038. GetOrAddPropertyId(JsUtil::CharacterBuffer<WCHAR>(propertyName, propertyNameLength), propertyRecord);
  1039. }
  1040. void ThreadContext::GetOrAddPropertyId(JsUtil::CharacterBuffer<WCHAR> const& propertyName, Js::PropertyRecord const ** propRecord)
  1041. {
  1042. EnterPinnedScope((volatile void **)propRecord);
  1043. *propRecord = GetOrAddPropertyRecord(propertyName);
  1044. LeavePinnedScope();
  1045. }
  1046. const Js::PropertyRecord *
  1047. ThreadContext::GetOrAddPropertyRecordImpl(JsUtil::CharacterBuffer<char16> propertyName, bool bind)
  1048. {
  1049. // Make sure the recycler is around so that we can take weak references to the property strings
  1050. EnsureRecycler();
  1051. const Js::PropertyRecord * propertyRecord;
  1052. FindPropertyRecord(propertyName.GetBuffer(), propertyName.GetLength(), &propertyRecord);
  1053. if (propertyRecord == nullptr)
  1054. {
  1055. propertyRecord = UncheckedAddPropertyId(propertyName, bind);
  1056. }
  1057. else
  1058. {
  1059. // PropertyRecord exists, but may not be bound. Bind now if requested.
  1060. if (bind)
  1061. {
  1062. BindPropertyRecord(propertyRecord);
  1063. }
  1064. }
  1065. Assert(propertyRecord != nullptr);
  1066. Assert(!bind || propertyRecord->IsBound());
  1067. return propertyRecord;
  1068. }
  1069. void ThreadContext::AddBuiltInPropertyRecord(const Js::PropertyRecord *propertyRecord)
  1070. {
  1071. this->AddPropertyRecordInternal(propertyRecord);
  1072. }
  1073. BOOL ThreadContext::IsNumericPropertyId(Js::PropertyId propertyId, uint32* value)
  1074. {
  1075. Js::PropertyRecord const * propertyRecord = this->GetPropertyName(propertyId);
  1076. Assert(propertyRecord != nullptr);
  1077. if (propertyRecord == nullptr || !propertyRecord->IsNumeric())
  1078. {
  1079. return false;
  1080. }
  1081. *value = propertyRecord->GetNumericValue();
  1082. return true;
  1083. }
  1084. bool ThreadContext::IsActivePropertyId(Js::PropertyId pid)
  1085. {
  1086. Assert(pid != Js::Constants::NoProperty);
  1087. if (Js::IsInternalPropertyId(pid))
  1088. {
  1089. return true;
  1090. }
  1091. int propertyIndex = pid - Js::PropertyIds::_none;
  1092. const Js::PropertyRecord * propertyRecord;
  1093. if (propertyMap->TryGetValueAt(propertyIndex, &propertyRecord) && propertyRecord != nullptr)
  1094. {
  1095. return true;
  1096. }
  1097. return false;
  1098. }
  1099. void ThreadContext::InvalidatePropertyRecord(const Js::PropertyRecord * propertyRecord)
  1100. {
  1101. InternalInvalidateProtoTypePropertyCaches(propertyRecord->GetPropertyId()); // use the internal version so we don't check for active property id
  1102. #if ENABLE_NATIVE_CODEGEN
  1103. if (propertyRecord->IsNumeric() && m_jitNumericProperties)
  1104. {
  1105. m_jitNumericProperties->Clear(propertyRecord->GetPropertyId());
  1106. m_jitNeedsPropertyUpdate = true;
  1107. }
  1108. #endif
  1109. this->propertyMap->Remove(propertyRecord);
  1110. PropertyRecordTrace(_u("Reclaimed property '%s' at 0x%08x, pid = %d\n"),
  1111. propertyRecord->GetBuffer(), propertyRecord, propertyRecord->GetPropertyId());
  1112. }
  1113. Js::PropertyId ThreadContext::GetNextPropertyId()
  1114. {
  1115. return this->propertyMap->GetNextIndex() + Js::PropertyIds::_none;
  1116. }
  1117. Js::PropertyId ThreadContext::GetMaxPropertyId()
  1118. {
  1119. auto maxPropertyId = this->propertyMap->Count() + Js::InternalPropertyIds::Count;
  1120. return maxPropertyId;
  1121. }
  1122. void ThreadContext::CreateNoCasePropertyMap()
  1123. {
  1124. Assert(caseInvariantPropertySet == nullptr);
  1125. caseInvariantPropertySet = RecyclerNew(recycler, PropertyNoCaseSetType, recycler, 173);
  1126. // Prevent the set from being reclaimed
  1127. // Individual items in the set can be reclaimed though since they're lists of weak references
  1128. // The lists themselves can be reclaimed when all the weak references in them are cleared
  1129. this->recyclableData->caseInvariantPropertySet = caseInvariantPropertySet;
  1130. // Note that we are allocating from the recycler below, so we may cause a GC at any time, which
  1131. // could cause PropertyRecords to be collected and removed from the propertyMap.
  1132. // Thus, don't use BaseDictionary::Map here, as it cannot tolerate changes while mapping.
  1133. // Instead, walk the PropertyRecord entries in index order. This will work even if a GC occurs.
  1134. for (int propertyIndex = 0; propertyIndex <= this->propertyMap->GetLastIndex(); propertyIndex++)
  1135. {
  1136. const Js::PropertyRecord * propertyRecord;
  1137. if (this->propertyMap->TryGetValueAt(propertyIndex, &propertyRecord) && propertyRecord != nullptr)
  1138. {
  1139. AddCaseInvariantPropertyRecord(propertyRecord);
  1140. }
  1141. }
  1142. }
  1143. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>*
  1144. ThreadContext::FindPropertyIdNoCase(Js::ScriptContext * scriptContext, LPCWSTR propertyName, int propertyNameLength)
  1145. {
  1146. return ThreadContext::FindPropertyIdNoCase(scriptContext, JsUtil::CharacterBuffer<WCHAR>(propertyName, propertyNameLength));
  1147. }
  1148. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>*
  1149. ThreadContext::FindPropertyIdNoCase(Js::ScriptContext * scriptContext, JsUtil::CharacterBuffer<WCHAR> const& propertyName)
  1150. {
  1151. if (caseInvariantPropertySet == nullptr)
  1152. {
  1153. this->CreateNoCasePropertyMap();
  1154. }
  1155. Js::CaseInvariantPropertyListWithHashCode* list;
  1156. if (FindExistingPropertyRecord(propertyName, &list))
  1157. {
  1158. return list;
  1159. }
  1160. return nullptr;
  1161. }
  1162. bool
  1163. ThreadContext::FindExistingPropertyRecord(_In_ JsUtil::CharacterBuffer<WCHAR> const& propertyName, Js::CaseInvariantPropertyListWithHashCode** list)
  1164. {
  1165. Js::CaseInvariantPropertyListWithHashCode* l = this->caseInvariantPropertySet->LookupWithKey(propertyName);
  1166. (*list) = l;
  1167. return (l != nullptr);
  1168. }
  1169. void ThreadContext::CleanNoCasePropertyMap()
  1170. {
  1171. if (this->caseInvariantPropertySet != nullptr)
  1172. {
  1173. this->caseInvariantPropertySet->MapAndRemoveIf([](Js::CaseInvariantPropertyListWithHashCode* value) -> bool {
  1174. if (value && value->Count() == 0)
  1175. {
  1176. // Remove entry
  1177. return true;
  1178. }
  1179. // Keep entry
  1180. return false;
  1181. });
  1182. }
  1183. }
  1184. void
  1185. ThreadContext::ForceCleanPropertyMap()
  1186. {
  1187. // No-op now that we no longer use weak refs
  1188. }
  1189. #if ENABLE_NATIVE_CODEGEN
  1190. JsUtil::JobProcessor *
  1191. ThreadContext::GetJobProcessor()
  1192. {
  1193. if(bgJit && isOptimizedForManyInstances)
  1194. {
  1195. return ThreadBoundThreadContextManager::GetSharedJobProcessor();
  1196. }
  1197. if (!jobProcessor)
  1198. {
  1199. if(bgJit && !isOptimizedForManyInstances)
  1200. {
  1201. jobProcessor = HeapNew(JsUtil::BackgroundJobProcessor, GetAllocationPolicyManager(), &threadService, false /*disableParallelThreads*/);
  1202. }
  1203. else
  1204. {
  1205. jobProcessor = HeapNew(JsUtil::ForegroundJobProcessor);
  1206. }
  1207. }
  1208. return jobProcessor;
  1209. }
  1210. #endif
  1211. void
  1212. ThreadContext::RegisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData)
  1213. {
  1214. Assert(codeGenRecyclableData);
  1215. Assert(recyclableData);
  1216. // Linking must not be done concurrently with unlinking (caller must use lock)
  1217. recyclableData->codeGenRecyclableDatas.LinkToEnd(codeGenRecyclableData);
  1218. }
  1219. void
  1220. ThreadContext::UnregisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData)
  1221. {
  1222. Assert(codeGenRecyclableData);
  1223. if(!recyclableData)
  1224. {
  1225. // The thread context's recyclable data may have already been released to the recycler if we're shutting down
  1226. return;
  1227. }
  1228. // Unlinking may be done from a background thread, but not concurrently with linking (caller must use lock). Partial unlink
  1229. // does not zero the previous and next links for the unlinked node so that the recycler can scan through the node from the
  1230. // main thread.
  1231. recyclableData->codeGenRecyclableDatas.UnlinkPartial(codeGenRecyclableData);
  1232. }
  1233. uint
  1234. ThreadContext::EnterScriptStart(Js::ScriptEntryExitRecord * record, bool doCleanup)
  1235. {
  1236. Recycler * recycler = this->GetRecycler();
  1237. Assert(recycler->IsReentrantState());
  1238. JS_ETW_INTERNAL(EventWriteJSCRIPT_RUN_START(this,0));
  1239. // Increment the callRootLevel early so that Dispose ran during FinishConcurrent will not close the current scriptContext
  1240. uint oldCallRootLevel = this->callRootLevel++;
  1241. if (oldCallRootLevel == 0)
  1242. {
  1243. Assert(!this->hasThrownPendingException);
  1244. RECORD_TIMESTAMP(lastScriptStartTime);
  1245. InterruptPoller *poller = this->interruptPoller;
  1246. if (poller)
  1247. {
  1248. poller->StartScript();
  1249. }
  1250. recycler->SetIsInScript(true);
  1251. if (doCleanup)
  1252. {
  1253. recycler->EnterIdleDecommit();
  1254. #if ENABLE_CONCURRENT_GC
  1255. recycler->FinishConcurrent<FinishConcurrentOnEnterScript>();
  1256. #endif
  1257. if (threadServiceWrapper == NULL)
  1258. {
  1259. // Reschedule the next collection at the start of the script.
  1260. recycler->ScheduleNextCollection();
  1261. }
  1262. }
  1263. }
  1264. this->PushEntryExitRecord(record);
  1265. AssertMsg(!this->IsScriptActive(),
  1266. "Missing EnterScriptEnd or LeaveScriptStart");
  1267. this->isScriptActive = true;
  1268. recycler->SetIsScriptActive(true);
  1269. #if DBG_DUMP
  1270. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::RunPhase))
  1271. {
  1272. Output::Trace(Js::RunPhase, _u("%p> EnterScriptStart(%p): Level %d\n"), ::GetCurrentThreadId(), this, this->callRootLevel);
  1273. Output::Flush();
  1274. }
  1275. #endif
  1276. return oldCallRootLevel;
  1277. }
  1278. void
  1279. ThreadContext::EnterScriptEnd(Js::ScriptEntryExitRecord * record, bool doCleanup)
  1280. {
  1281. #if DBG_DUMP
  1282. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::RunPhase))
  1283. {
  1284. Output::Trace(Js::RunPhase, _u("%p> EnterScriptEnd (%p): Level %d\n"), ::GetCurrentThreadId(), this, this->callRootLevel);
  1285. Output::Flush();
  1286. }
  1287. #endif
  1288. this->PopEntryExitRecord(record);
  1289. AssertMsg(this->IsScriptActive(),
  1290. "Missing EnterScriptStart or LeaveScriptEnd");
  1291. this->isScriptActive = false;
  1292. this->GetRecycler()->SetIsScriptActive(false);
  1293. this->callRootLevel--;
  1294. #ifdef EXCEPTION_CHECK
  1295. ExceptionCheck::SetHandledExceptionType(record->handledExceptionType);
  1296. #endif
  1297. #ifdef RECYCLER_MEMORY_VERIFY
  1298. recycler->Verify(Js::RunPhase);
  1299. #endif
  1300. if (this->callRootLevel == 0)
  1301. {
  1302. RECORD_TIMESTAMP(lastScriptEndTime);
  1303. this->GetRecycler()->SetIsInScript(false);
  1304. InterruptPoller *poller = this->interruptPoller;
  1305. if (poller)
  1306. {
  1307. poller->EndScript();
  1308. }
  1309. ClosePendingProjectionContexts();
  1310. ClosePendingScriptContexts();
  1311. Assert(rootPendingClose == nullptr);
  1312. if (this->hasThrownPendingException)
  1313. {
  1314. // We have some cases where the thread instant of JavascriptExceptionObject
  1315. // are ignored and not clear. To avoid leaks, clear it here when
  1316. // we are not in script, where no one should be using these JavascriptExceptionObject
  1317. this->ClearPendingOOMError();
  1318. this->ClearPendingSOError();
  1319. this->hasThrownPendingException = false;
  1320. }
  1321. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1322. if (Js::Configuration::Global.flags.FreeRejittedCode)
  1323. #endif
  1324. {
  1325. // Since we're no longer in script, old entry points can now be collected
  1326. Js::FunctionEntryPointInfo* current = this->recyclableData->oldEntryPointInfo;
  1327. this->recyclableData->oldEntryPointInfo = nullptr;
  1328. // Clear out the next pointers so older entry points wont be held on
  1329. // as a false positive
  1330. while (current != nullptr)
  1331. {
  1332. Js::FunctionEntryPointInfo* next = current->nextEntryPoint;
  1333. current->nextEntryPoint = nullptr;
  1334. current = next;
  1335. }
  1336. }
  1337. if (doCleanup)
  1338. {
  1339. ThreadServiceWrapper* threadServiceWrapper = GetThreadServiceWrapper();
  1340. if (!threadServiceWrapper || !threadServiceWrapper->ScheduleNextCollectOnExit())
  1341. {
  1342. // Do the idle GC now if we fail schedule one.
  1343. recycler->CollectNow<CollectOnScriptExit>();
  1344. }
  1345. recycler->LeaveIdleDecommit();
  1346. }
  1347. }
  1348. if (doCleanup)
  1349. {
  1350. PHASE_PRINT_TRACE1(Js::DisposePhase, _u("[Dispose] NeedDispose in EnterScriptEnd: %d\n"), this->recycler->NeedDispose());
  1351. if (this->recycler->NeedDispose())
  1352. {
  1353. this->recycler->FinishDisposeObjectsNow<FinishDispose>();
  1354. }
  1355. }
  1356. JS_ETW_INTERNAL(EventWriteJSCRIPT_RUN_STOP(this,0));
  1357. }
  1358. void
  1359. ThreadContext::SetForceOneIdleCollection()
  1360. {
  1361. ThreadServiceWrapper* threadServiceWrapper = GetThreadServiceWrapper();
  1362. if (threadServiceWrapper)
  1363. {
  1364. threadServiceWrapper->SetForceOneIdleCollection();
  1365. }
  1366. }
  1367. BOOLEAN
  1368. ThreadContext::IsOnStack(void const *ptr)
  1369. {
  1370. #if defined(_M_IX86) && defined(_MSC_VER)
  1371. return ptr < (void*)__readfsdword(0x4) && ptr >= (void*)__readfsdword(0xE0C);
  1372. #elif defined(_M_AMD64) && defined(_MSC_VER)
  1373. return ptr < (void*)__readgsqword(0x8) && ptr >= (void*)__readgsqword(0x1478);
  1374. #elif defined(_M_ARM)
  1375. ULONG lowLimit, highLimit;
  1376. ::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
  1377. bool isOnStack = (void*)lowLimit <= ptr && ptr < (void*)highLimit;
  1378. return isOnStack;
  1379. #elif defined(_M_ARM64)
  1380. ULONG64 lowLimit, highLimit;
  1381. ::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
  1382. bool isOnStack = (void*)lowLimit <= ptr && ptr < (void*)highLimit;
  1383. return isOnStack;
  1384. #elif !defined(_MSC_VER)
  1385. return ::IsAddressOnStack((ULONG_PTR) ptr);
  1386. #else
  1387. AssertMsg(FALSE, "IsOnStack -- not implemented yet case");
  1388. Js::Throw::NotImplemented();
  1389. return false;
  1390. #endif
  1391. }
  1392. size_t
  1393. ThreadContext::GetStackLimitForCurrentThread() const
  1394. {
  1395. FAULTINJECT_SCRIPT_TERMINATION;
  1396. size_t limit = this->stackLimitForCurrentThread;
  1397. Assert(limit == Js::Constants::StackLimitForScriptInterrupt
  1398. || !this->GetStackProber()
  1399. || limit == this->GetStackProber()->GetScriptStackLimit());
  1400. return limit;
  1401. }
  1402. void
  1403. ThreadContext::SetStackLimitForCurrentThread(size_t limit)
  1404. {
  1405. this->stackLimitForCurrentThread = limit;
  1406. }
  1407. _NOINLINE //Win8 947081: might use wrong _AddressOfReturnAddress() if this and caller are inlined
  1408. bool
  1409. ThreadContext::IsStackAvailable(size_t size)
  1410. {
  1411. size_t sp = (size_t)_AddressOfReturnAddress();
  1412. size_t stackLimit = this->GetStackLimitForCurrentThread();
  1413. bool stackAvailable = (sp > size && (sp - size) > stackLimit);
  1414. // Verify that JIT'd frames didn't mess up the ABI stack alignment
  1415. Assert(((uintptr_t)sp & (AutoSystemInfo::StackAlign - 1)) == (sizeof(void*) & (AutoSystemInfo::StackAlign - 1)));
  1416. #if DBG
  1417. this->GetStackProber()->AdjustKnownStackLimit(sp, size);
  1418. #endif
  1419. FAULTINJECT_STACK_PROBE
  1420. if (stackAvailable)
  1421. {
  1422. return true;
  1423. }
  1424. if (sp <= stackLimit)
  1425. {
  1426. if (stackLimit == Js::Constants::StackLimitForScriptInterrupt)
  1427. {
  1428. if (sp <= this->GetStackProber()->GetScriptStackLimit())
  1429. {
  1430. // Take down the process if we cant recover from the stack overflow
  1431. Js::Throw::FatalInternalError();
  1432. }
  1433. }
  1434. }
  1435. return false;
  1436. }
  1437. _NOINLINE //Win8 947081: might use wrong _AddressOfReturnAddress() if this and caller are inlined
  1438. bool
  1439. ThreadContext::IsStackAvailableNoThrow(size_t size)
  1440. {
  1441. size_t sp = (size_t)_AddressOfReturnAddress();
  1442. size_t stackLimit = this->GetStackLimitForCurrentThread();
  1443. bool stackAvailable = (sp > stackLimit) && (sp > size) && ((sp - size) > stackLimit);
  1444. FAULTINJECT_STACK_PROBE
  1445. return stackAvailable;
  1446. }
  1447. /* static */ bool
  1448. ThreadContext::IsCurrentStackAvailable(size_t size)
  1449. {
  1450. ThreadContext *currentContext = GetContextForCurrentThread();
  1451. Assert(currentContext);
  1452. return currentContext->IsStackAvailable(size);
  1453. }
  1454. /*
  1455. returnAddress will be passed in the stackprobe call at the beginning of interpreter frame.
  1456. We need to probe the stack before we link up the InterpreterFrame structure in threadcontext,
  1457. and if we throw there, the stack walker might get confused when trying to identify a frame
  1458. is interpreter frame by comparing the current ebp in ebp chain with return address specified
  1459. in the last InterpreterFrame linked in threadcontext. We need to pass in the return address
  1460. of the probing frame to skip the right one (we need to skip first match in a->a->a recursion,
  1461. but not in a->b->a recursion).
  1462. */
  1463. void
  1464. ThreadContext::ProbeStackNoDispose(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress)
  1465. {
  1466. AssertCanHandleStackOverflow();
  1467. if (!this->IsStackAvailable(size))
  1468. {
  1469. if (this->IsExecutionDisabled())
  1470. {
  1471. // The probe failed because we hammered the stack limit to trigger script interrupt.
  1472. Assert(this->DoInterruptProbe());
  1473. throw Js::ScriptAbortException();
  1474. }
  1475. Js::Throw::StackOverflow(scriptContext, returnAddress);
  1476. }
  1477. #if defined(NTBUILD) || defined(__IOS__) || defined(__ANDROID__)
  1478. // Use every Nth stack probe as a QC trigger.
  1479. if (AutoSystemInfo::ShouldQCMoreFrequently() && this->HasInterruptPoller() && this->IsScriptActive())
  1480. {
  1481. ++(this->stackProbeCount);
  1482. if (this->stackProbeCount > ThreadContext::StackProbePollThreshold)
  1483. {
  1484. this->stackProbeCount = 0;
  1485. this->CheckInterruptPoll();
  1486. }
  1487. }
  1488. #endif
  1489. }
  1490. void
  1491. ThreadContext::ProbeStack(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress)
  1492. {
  1493. this->ProbeStackNoDispose(size, scriptContext, returnAddress);
  1494. #if PERFMAP_TRACE_ENABLED
  1495. if (PlatformAgnostic::PerfTrace::mapsRequested)
  1496. {
  1497. PlatformAgnostic::PerfTrace::WritePerfMap();
  1498. }
  1499. #endif
  1500. // BACKGROUND-GC TODO: If we're stuck purely in JITted code, we should have the
  1501. // background GC thread modify the threads stack limit to trigger the runtime stack probe
  1502. if (this->callDispose && this->recycler->NeedDispose())
  1503. {
  1504. PHASE_PRINT_TRACE1(Js::DisposePhase, _u("[Dispose] NeedDispose in ProbeStack: %d\n"), this->recycler->NeedDispose());
  1505. this->recycler->FinishDisposeObjectsNow<FinishDisposeTimed>();
  1506. }
  1507. }
  1508. void
  1509. ThreadContext::ProbeStack(size_t size, Js::RecyclableObject * obj, Js::ScriptContext *scriptContext)
  1510. {
  1511. AssertCanHandleStackOverflowCall(obj->IsExternal() ||
  1512. (Js::JavascriptOperators::GetTypeId(obj) == Js::TypeIds_Function &&
  1513. Js::JavascriptFunction::FromVar(obj)->IsExternalFunction()));
  1514. if (!this->IsStackAvailable(size))
  1515. {
  1516. if (this->IsExecutionDisabled())
  1517. {
  1518. // The probe failed because we hammered the stack limit to trigger script interrupt.
  1519. Assert(this->DoInterruptProbe());
  1520. throw Js::ScriptAbortException();
  1521. }
  1522. if (obj->IsExternal() ||
  1523. (Js::JavascriptOperators::GetTypeId(obj) == Js::TypeIds_Function &&
  1524. Js::JavascriptFunction::FromVar(obj)->IsExternalFunction()))
  1525. {
  1526. Js::JavascriptError::ThrowStackOverflowError(scriptContext);
  1527. }
  1528. Js::Throw::StackOverflow(scriptContext, NULL);
  1529. }
  1530. }
  1531. void
  1532. ThreadContext::ProbeStack(size_t size)
  1533. {
  1534. Assert(this->IsScriptActive());
  1535. Js::ScriptEntryExitRecord *entryExitRecord = this->GetScriptEntryExit();
  1536. Assert(entryExitRecord);
  1537. Js::ScriptContext *scriptContext = entryExitRecord->scriptContext;
  1538. Assert(scriptContext);
  1539. this->ProbeStack(size, scriptContext);
  1540. }
  1541. /* static */ void
  1542. ThreadContext::ProbeCurrentStack(size_t size, Js::ScriptContext *scriptContext)
  1543. {
  1544. Assert(scriptContext != nullptr);
  1545. Assert(scriptContext->GetThreadContext() == GetContextForCurrentThread());
  1546. scriptContext->GetThreadContext()->ProbeStack(size, scriptContext);
  1547. }
  1548. /* static */ void
  1549. ThreadContext::ProbeCurrentStackNoDispose(size_t size, Js::ScriptContext *scriptContext)
  1550. {
  1551. Assert(scriptContext != nullptr);
  1552. Assert(scriptContext->GetThreadContext() == GetContextForCurrentThread());
  1553. scriptContext->GetThreadContext()->ProbeStackNoDispose(size, scriptContext);
  1554. }
  1555. template <bool leaveForHost>
  1556. void
  1557. ThreadContext::LeaveScriptStart(void * frameAddress)
  1558. {
  1559. Assert(this->IsScriptActive());
  1560. #if DBG_DUMP
  1561. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::RunPhase))
  1562. {
  1563. Output::Trace(Js::RunPhase, _u("%p> LeaveScriptStart(%p): Level %d\n"), ::GetCurrentThreadId(), this, this->callRootLevel);
  1564. Output::Flush();
  1565. }
  1566. #endif
  1567. Js::ScriptEntryExitRecord * entryExitRecord = this->GetScriptEntryExit();
  1568. AssertMsg(entryExitRecord && entryExitRecord->frameIdOfScriptExitFunction == nullptr,
  1569. "Missing LeaveScriptEnd or EnterScriptStart");
  1570. entryExitRecord->frameIdOfScriptExitFunction = frameAddress;
  1571. this->isScriptActive = false;
  1572. this->GetRecycler()->SetIsScriptActive(false);
  1573. AssertMsg(!(leaveForHost && this->IsDisableImplicitCall()),
  1574. "Disable implicit call should have been caught before leaving script for host");
  1575. // Save the implicit call flags
  1576. entryExitRecord->savedImplicitCallFlags = this->GetImplicitCallFlags();
  1577. // clear the hasReentered to detect if we have reentered into script
  1578. entryExitRecord->hasReentered = false;
  1579. #if DBG || defined(PROFILE_EXEC)
  1580. entryExitRecord->leaveForHost = leaveForHost;
  1581. #endif
  1582. #if DBG
  1583. entryExitRecord->leaveForAsyncHostOperation = false;
  1584. #endif
  1585. #ifdef PROFILE_EXEC
  1586. if (leaveForHost)
  1587. {
  1588. entryExitRecord->scriptContext->ProfileEnd(Js::RunPhase);
  1589. }
  1590. #endif
  1591. }
  1592. void ThreadContext::DisposeOnLeaveScript()
  1593. {
  1594. PHASE_PRINT_TRACE1(Js::DisposePhase, _u("[Dispose] NeedDispose in LeaveScriptStart: %d\n"), this->recycler->NeedDispose());
  1595. if (this->callDispose && this->recycler->NeedDispose())
  1596. {
  1597. this->recycler->FinishDisposeObjectsNow<FinishDispose>();
  1598. }
  1599. }
  1600. template <bool leaveForHost>
  1601. void
  1602. ThreadContext::LeaveScriptEnd(void * frameAddress)
  1603. {
  1604. Assert(!this->IsScriptActive());
  1605. #if DBG_DUMP
  1606. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::RunPhase))
  1607. {
  1608. Output::Trace(Js::RunPhase, _u("%p> LeaveScriptEnd(%p): Level %d\n"), ::GetCurrentThreadId(), this, this->callRootLevel);
  1609. Output::Flush();
  1610. }
  1611. #endif
  1612. Js::ScriptEntryExitRecord * entryExitRecord = this->GetScriptEntryExit();
  1613. AssertMsg(entryExitRecord && entryExitRecord->frameIdOfScriptExitFunction,
  1614. "LeaveScriptEnd without LeaveScriptStart");
  1615. AssertMsg(frameAddress == nullptr || frameAddress == entryExitRecord->frameIdOfScriptExitFunction,
  1616. "Mismatched script exit frames");
  1617. Assert(!!entryExitRecord->leaveForHost == leaveForHost);
  1618. entryExitRecord->frameIdOfScriptExitFunction = nullptr;
  1619. AssertMsg(!this->IsScriptActive(), "Missing LeaveScriptStart or LeaveScriptStart");
  1620. this->isScriptActive = true;
  1621. this->GetRecycler()->SetIsScriptActive(true);
  1622. Js::ImplicitCallFlags savedImplicitCallFlags = entryExitRecord->savedImplicitCallFlags;
  1623. if (leaveForHost)
  1624. {
  1625. savedImplicitCallFlags = (Js::ImplicitCallFlags)(savedImplicitCallFlags | Js::ImplicitCall_External);
  1626. }
  1627. else if (entryExitRecord->hasReentered)
  1628. {
  1629. savedImplicitCallFlags = (Js::ImplicitCallFlags)(savedImplicitCallFlags | Js::ImplicitCall_AsyncHostOperation);
  1630. }
  1631. // Restore the implicit call flags
  1632. this->SetImplicitCallFlags(savedImplicitCallFlags);
  1633. #ifdef PROFILE_EXEC
  1634. if (leaveForHost)
  1635. {
  1636. entryExitRecord->scriptContext->ProfileBegin(Js::RunPhase);
  1637. }
  1638. #endif
  1639. }
  1640. // explicit instantiations
  1641. template void ThreadContext::LeaveScriptStart<true>(void * frameAddress);
  1642. template void ThreadContext::LeaveScriptStart<false>(void * frameAddress);
  1643. template void ThreadContext::LeaveScriptEnd<true>(void * frameAddress);
  1644. template void ThreadContext::LeaveScriptEnd<false>(void * frameAddress);
  1645. void
  1646. ThreadContext::PushInterpreterFrame(Js::InterpreterStackFrame *interpreterFrame)
  1647. {
  1648. interpreterFrame->SetPreviousFrame(this->leafInterpreterFrame);
  1649. this->leafInterpreterFrame = interpreterFrame;
  1650. }
  1651. Js::InterpreterStackFrame *
  1652. ThreadContext::PopInterpreterFrame()
  1653. {
  1654. Js::InterpreterStackFrame *interpreterFrame = this->leafInterpreterFrame;
  1655. Assert(interpreterFrame);
  1656. this->leafInterpreterFrame = interpreterFrame->GetPreviousFrame();
  1657. return interpreterFrame;
  1658. }
  1659. BOOL
  1660. ThreadContext::ExecuteRecyclerCollectionFunctionCommon(Recycler * recycler, CollectionFunction function, CollectionFlags flags)
  1661. {
  1662. return __super::ExecuteRecyclerCollectionFunction(recycler, function, flags);
  1663. }
  1664. #if DBG
  1665. bool
  1666. ThreadContext::IsInAsyncHostOperation() const
  1667. {
  1668. if (!this->IsScriptActive())
  1669. {
  1670. Js::ScriptEntryExitRecord * lastRecord = this->entryExitRecord;
  1671. if (lastRecord != NULL)
  1672. {
  1673. return !!lastRecord->leaveForAsyncHostOperation;
  1674. }
  1675. }
  1676. return false;
  1677. }
  1678. #endif
  1679. #if ENABLE_NATIVE_CODEGEN
  1680. void
  1681. ThreadContext::SetJITConnectionInfo(HANDLE processHandle, void* serverSecurityDescriptor, UUID connectionId)
  1682. {
  1683. Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
  1684. if (!JITManager::GetJITManager()->IsConnected())
  1685. {
  1686. // TODO: return HRESULT
  1687. JITManager::GetJITManager()->ConnectRpcServer(processHandle, serverSecurityDescriptor, connectionId);
  1688. }
  1689. }
  1690. bool
  1691. ThreadContext::EnsureJITThreadContext(bool allowPrereserveAlloc)
  1692. {
  1693. #if ENABLE_OOP_NATIVE_CODEGEN
  1694. Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
  1695. if (!JITManager::GetJITManager()->IsConnected())
  1696. {
  1697. return false;
  1698. }
  1699. if (m_remoteThreadContextInfo)
  1700. {
  1701. return true;
  1702. }
  1703. #ifdef USE_RPC_HANDLE_MARSHALLING
  1704. HANDLE processHandle;
  1705. if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &processHandle, 0, false, DUPLICATE_SAME_ACCESS))
  1706. {
  1707. return false;
  1708. }
  1709. AutoCloseHandle autoClose(processHandle);
  1710. #endif
  1711. ThreadContextDataIDL contextData;
  1712. contextData.chakraBaseAddress = (intptr_t)AutoSystemInfo::Data.GetChakraBaseAddr();
  1713. contextData.crtBaseAddress = (intptr_t)AutoSystemInfo::Data.GetCRTHandle();
  1714. contextData.threadStackLimitAddr = reinterpret_cast<intptr_t>(GetAddressOfStackLimitForCurrentThread());
  1715. contextData.bailOutRegisterSaveSpaceAddr = (intptr_t)bailOutRegisterSaveSpace;
  1716. contextData.disableImplicitFlagsAddr = (intptr_t)GetAddressOfDisableImplicitFlags();
  1717. contextData.implicitCallFlagsAddr = (intptr_t)GetAddressOfImplicitCallFlags();
  1718. contextData.scriptStackLimit = GetScriptStackLimit();
  1719. contextData.isThreadBound = IsThreadBound();
  1720. contextData.allowPrereserveAlloc = allowPrereserveAlloc;
  1721. #if defined(ENABLE_SIMDJS) && (_M_IX86 || _M_AMD64)
  1722. contextData.simdTempAreaBaseAddr = (intptr_t)GetSimdTempArea();
  1723. #endif
  1724. m_jitNumericProperties = HeapNew(BVSparse<HeapAllocator>, &HeapAllocator::Instance);
  1725. for (auto iter = propertyMap->GetIterator(); iter.IsValid(); iter.MoveNext())
  1726. {
  1727. if (iter.CurrentKey()->IsNumeric())
  1728. {
  1729. m_jitNumericProperties->Set(iter.CurrentKey()->GetPropertyId());
  1730. m_jitNeedsPropertyUpdate = true;
  1731. }
  1732. }
  1733. HRESULT hr = JITManager::GetJITManager()->InitializeThreadContext(
  1734. &contextData,
  1735. #ifdef USE_RPC_HANDLE_MARSHALLING
  1736. processHandle,
  1737. #endif
  1738. &m_remoteThreadContextInfo,
  1739. &m_prereservedRegionAddr,
  1740. &m_jitThunkStartAddr);
  1741. JITManager::HandleServerCallResult(hr, RemoteCallType::StateUpdate);
  1742. return m_remoteThreadContextInfo != nullptr;
  1743. #endif
  1744. }
  1745. #endif
  1746. #if ENABLE_TTD
  1747. void ThreadContext::InitTimeTravel(ThreadContext* threadContext, void* runtimeHandle, uint32 snapInterval, uint32 snapHistoryLength)
  1748. {
  1749. TTDAssert(!this->IsRuntimeInTTDMode(), "We should only init once.");
  1750. this->TTDContext = HeapNew(TTD::ThreadContextTTD, this, runtimeHandle, snapInterval, snapHistoryLength);
  1751. this->TTDLog = HeapNew(TTD::EventLog, this);
  1752. }
  1753. void ThreadContext::InitHostFunctionsAndTTData(bool record, bool replay, bool debug, size_t optTTUriLength, const char* optTTUri,
  1754. TTD::TTDOpenResourceStreamCallback openResourceStreamfp, TTD::TTDReadBytesFromStreamCallback readBytesFromStreamfp,
  1755. TTD::TTDWriteBytesToStreamCallback writeBytesToStreamfp, TTD::TTDFlushAndCloseStreamCallback flushAndCloseStreamfp,
  1756. TTD::TTDCreateExternalObjectCallback createExternalObjectfp,
  1757. TTD::TTDCreateJsRTContextCallback createJsRTContextCallbackfp, TTD::TTDReleaseJsRTContextCallback releaseJsRTContextCallbackfp, TTD::TTDSetActiveJsRTContext setActiveJsRTContextfp)
  1758. {
  1759. AssertMsg(this->IsRuntimeInTTDMode(), "Need to call init first.");
  1760. this->TTDContext->TTDataIOInfo = { openResourceStreamfp, readBytesFromStreamfp, writeBytesToStreamfp, flushAndCloseStreamfp, 0, nullptr };
  1761. this->TTDContext->TTDExternalObjectFunctions = { createExternalObjectfp, createJsRTContextCallbackfp, releaseJsRTContextCallbackfp, setActiveJsRTContextfp };
  1762. if(record)
  1763. {
  1764. TTDAssert(optTTUri == nullptr, "No URI is needed in record mode (the host explicitly provides it when writing.");
  1765. this->TTDLog->InitForTTDRecord();
  1766. }
  1767. else
  1768. {
  1769. TTDAssert(optTTUri != nullptr, "We need a URI in replay mode so we can initialize the log from it");
  1770. this->TTDLog->InitForTTDReplay(this->TTDContext->TTDataIOInfo, optTTUri, optTTUriLength, debug);
  1771. this->sourceInfoCount = this->TTDLog->GetSourceInfoCount();
  1772. }
  1773. #if !ENABLE_TTD_DIAGNOSTICS_TRACING
  1774. if(debug)
  1775. {
  1776. #endif
  1777. this->TTDExecutionInfo = HeapNew(TTD::ExecutionInfoManager);
  1778. #if !ENABLE_TTD_DIAGNOSTICS_TRACING
  1779. }
  1780. #endif
  1781. }
  1782. #endif
  1783. BOOL
  1784. ThreadContext::ExecuteRecyclerCollectionFunction(Recycler * recycler, CollectionFunction function, CollectionFlags flags)
  1785. {
  1786. // If the thread context doesn't have an associated Recycler set, don't do anything
  1787. if (this->recycler == nullptr)
  1788. {
  1789. return FALSE;
  1790. }
  1791. // Take etw rundown lock on this thread context. We can't collect entryPoints if we are in etw rundown.
  1792. AutoCriticalSection autocs(this->GetFunctionBodyLock());
  1793. // Disable calling dispose from leave script or the stack probe
  1794. // while we're executing the recycler wrapper
  1795. AutoRestoreValue<bool> callDispose(&this->callDispose, false);
  1796. BOOL ret = FALSE;
  1797. #if ENABLE_TTD
  1798. //
  1799. //TODO: We lose any events that happen in the callbacks (such as JsRelease) which may be a problem in the future.
  1800. // It may be possible to defer the collection of these objects to an explicit collection at the yield loop (same for weak set/map).
  1801. // We already indirectly do this for ScriptContext collection (but that is buggy so needs to be fixed too).
  1802. //
  1803. if(this->IsRuntimeInTTDMode())
  1804. {
  1805. this->TTDLog->PushMode(TTD::TTDMode::ExcludedExecutionTTAction);
  1806. }
  1807. #endif
  1808. if (!this->IsScriptActive())
  1809. {
  1810. Assert(!this->IsDisableImplicitCall() || this->IsInAsyncHostOperation());
  1811. ret = this->ExecuteRecyclerCollectionFunctionCommon(recycler, function, flags);
  1812. // Make sure that we finish a collect that is activated outside of script, since
  1813. // we won't have exit script to schedule it
  1814. if (!this->IsInScript() && recycler->CollectionInProgress()
  1815. && ((flags & CollectOverride_DisableIdleFinish) == 0) && threadServiceWrapper)
  1816. {
  1817. threadServiceWrapper->ScheduleFinishConcurrent();
  1818. }
  1819. }
  1820. else
  1821. {
  1822. void * frameAddr = nullptr;
  1823. GET_CURRENT_FRAME_ID(frameAddr);
  1824. // We may need stack to call out from Dispose or QC
  1825. if (!this->IsDisableImplicitCall()) // otherwise Dispose/QC disabled
  1826. {
  1827. // If we don't have stack space to call out from Dispose or QC,
  1828. // don't throw, simply return false. This gives SnailAlloc a better
  1829. // chance of allocating in low stack-space situations (like allocating
  1830. // a StackOverflowException object)
  1831. if (!this->IsStackAvailableNoThrow(Js::Constants::MinStackCallout))
  1832. {
  1833. return false;
  1834. }
  1835. }
  1836. this->LeaveScriptStart<false>(frameAddr);
  1837. ret = this->ExecuteRecyclerCollectionFunctionCommon(recycler, function, flags);
  1838. this->LeaveScriptEnd<false>(frameAddr);
  1839. if (this->callRootLevel != 0)
  1840. {
  1841. this->CheckScriptInterrupt();
  1842. }
  1843. }
  1844. #if ENABLE_TTD
  1845. if(this->IsRuntimeInTTDMode())
  1846. {
  1847. this->TTDLog->PopMode(TTD::TTDMode::ExcludedExecutionTTAction);
  1848. }
  1849. #endif
  1850. return ret;
  1851. }
  1852. void
  1853. ThreadContext::DisposeObjects(Recycler * recycler)
  1854. {
  1855. if (this->IsDisableImplicitCall())
  1856. {
  1857. // Don't dispose objects when implicit calls are disabled, since disposing may cause implicit calls. Objects will remain
  1858. // in the dispose queue and will be disposed later when implicit calls are not disabled.
  1859. return;
  1860. }
  1861. // We shouldn't DisposeObjects in NoScriptScope as this might lead to script execution.
  1862. // Callers of DisposeObjects should ensure !IsNoScriptScope() before calling DisposeObjects.
  1863. if (this->IsNoScriptScope())
  1864. {
  1865. FromDOM_NoScriptScope_fatal_error();
  1866. }
  1867. if (!this->IsScriptActive())
  1868. {
  1869. __super::DisposeObjects(recycler);
  1870. }
  1871. else
  1872. {
  1873. void * frameAddr = nullptr;
  1874. GET_CURRENT_FRAME_ID(frameAddr);
  1875. // We may need stack to call out from Dispose
  1876. this->ProbeStack(Js::Constants::MinStackCallout);
  1877. this->LeaveScriptStart<false>(frameAddr);
  1878. __super::DisposeObjects(recycler);
  1879. this->LeaveScriptEnd<false>(frameAddr);
  1880. }
  1881. }
  1882. void
  1883. ThreadContext::PushEntryExitRecord(Js::ScriptEntryExitRecord * record)
  1884. {
  1885. AssertMsg(record, "Didn't provide a script entry record to push");
  1886. Assert(record->next == nullptr);
  1887. Js::ScriptEntryExitRecord * lastRecord = this->entryExitRecord;
  1888. if (lastRecord != nullptr)
  1889. {
  1890. // If we enter script again, we should have leave with leaveForHost or leave for dispose.
  1891. Assert(lastRecord->leaveForHost || lastRecord->leaveForAsyncHostOperation);
  1892. lastRecord->hasReentered = true;
  1893. record->next = lastRecord;
  1894. // these are on stack, which grows down. if this condition doesn't hold,
  1895. // then the list somehow got messed up
  1896. if (
  1897. #if defined(JSRT_VERIFY_RUNTIME_STATE) || defined(DEBUG)
  1898. !IsOnStack(lastRecord) ||
  1899. #endif
  1900. (uintptr_t)record >= (uintptr_t)lastRecord)
  1901. {
  1902. EntryExitRecord_Corrupted_fatal_error();
  1903. }
  1904. }
  1905. this->entryExitRecord = record;
  1906. }
  1907. void ThreadContext::PopEntryExitRecord(Js::ScriptEntryExitRecord * record)
  1908. {
  1909. AssertMsg(record && record == this->entryExitRecord, "Mismatch script entry/exit");
  1910. // these are on stack, which grows down. if this condition doesn't hold,
  1911. // then the list somehow got messed up
  1912. Js::ScriptEntryExitRecord * next = this->entryExitRecord->next;
  1913. if (next && (
  1914. #if defined(JSRT_VERIFY_RUNTIME_STATE) || defined(DEBUG)
  1915. !IsOnStack(next) ||
  1916. #endif
  1917. (uintptr_t)this->entryExitRecord >= (uintptr_t)next))
  1918. {
  1919. EntryExitRecord_Corrupted_fatal_error();
  1920. }
  1921. this->entryExitRecord = next;
  1922. }
  1923. BOOL ThreadContext::ReserveStaticTypeIds(__in int first, __in int last)
  1924. {
  1925. if ( nextTypeId <= first )
  1926. {
  1927. nextTypeId = (Js::TypeId) last;
  1928. return TRUE;
  1929. }
  1930. else
  1931. {
  1932. return FALSE;
  1933. }
  1934. }
  1935. Js::TypeId ThreadContext::ReserveTypeIds(int count)
  1936. {
  1937. Js::TypeId firstTypeId = nextTypeId;
  1938. nextTypeId = (Js::TypeId)(nextTypeId + count);
  1939. return firstTypeId;
  1940. }
  1941. Js::TypeId ThreadContext::CreateTypeId()
  1942. {
  1943. return nextTypeId = (Js::TypeId)(nextTypeId + 1);
  1944. }
  1945. void ThreadContext::SetWellKnownHostTypeId(WellKnownHostType wellKnownType, Js::TypeId typeId)
  1946. {
  1947. AssertMsg(wellKnownType <= WellKnownHostType_Last, "ThreadContext::SetWellKnownHostTypeId called on unknown type");
  1948. if (wellKnownType >= 0 && wellKnownType <= WellKnownHostType_Last)
  1949. {
  1950. this->wellKnownHostTypeIds[wellKnownType] = typeId;
  1951. #if ENABLE_NATIVE_CODEGEN
  1952. // The jit server really only needs to know about WellKnownHostType_HTMLAllCollection
  1953. if (this->m_remoteThreadContextInfo && wellKnownType == WellKnownHostType_HTMLAllCollection)
  1954. {
  1955. HRESULT hr = JITManager::GetJITManager()->SetWellKnownHostTypeId(this->m_remoteThreadContextInfo, (int)typeId);
  1956. JITManager::HandleServerCallResult(hr, RemoteCallType::StateUpdate);
  1957. }
  1958. #endif
  1959. }
  1960. }
  1961. #ifdef ENABLE_SCRIPT_DEBUGGING
  1962. void ThreadContext::EnsureDebugManager()
  1963. {
  1964. if (this->debugManager == nullptr)
  1965. {
  1966. this->debugManager = HeapNew(Js::DebugManager, this, this->GetAllocationPolicyManager());
  1967. }
  1968. InterlockedIncrement(&crefSContextForDiag);
  1969. Assert(this->debugManager != nullptr);
  1970. }
  1971. void ThreadContext::ReleaseDebugManager()
  1972. {
  1973. Assert(crefSContextForDiag > 0);
  1974. Assert(this->debugManager != nullptr);
  1975. LONG lref = InterlockedDecrement(&crefSContextForDiag);
  1976. if (lref == 0)
  1977. {
  1978. if (this->recyclableData != nullptr)
  1979. {
  1980. this->recyclableData->returnedValueList = nullptr;
  1981. }
  1982. if (this->debugManager != nullptr)
  1983. {
  1984. this->debugManager->Close();
  1985. HeapDelete(this->debugManager);
  1986. this->debugManager = nullptr;
  1987. }
  1988. }
  1989. }
  1990. #endif
  1991. Js::TempArenaAllocatorObject *
  1992. ThreadContext::GetTemporaryAllocator(LPCWSTR name)
  1993. {
  1994. AssertCanHandleOutOfMemory();
  1995. if (temporaryArenaAllocatorCount != 0)
  1996. {
  1997. temporaryArenaAllocatorCount--;
  1998. Js::TempArenaAllocatorObject * allocator = recyclableData->temporaryArenaAllocators[temporaryArenaAllocatorCount];
  1999. recyclableData->temporaryArenaAllocators[temporaryArenaAllocatorCount] = nullptr;
  2000. return allocator;
  2001. }
  2002. return Js::TempArenaAllocatorObject::Create(this);
  2003. }
  2004. void
  2005. ThreadContext::ReleaseTemporaryAllocator(Js::TempArenaAllocatorObject * tempAllocator)
  2006. {
  2007. if (temporaryArenaAllocatorCount < MaxTemporaryArenaAllocators)
  2008. {
  2009. tempAllocator->GetAllocator()->Reset();
  2010. recyclableData->temporaryArenaAllocators[temporaryArenaAllocatorCount] = tempAllocator;
  2011. temporaryArenaAllocatorCount++;
  2012. return;
  2013. }
  2014. tempAllocator->Dispose(false);
  2015. }
  2016. Js::TempGuestArenaAllocatorObject *
  2017. ThreadContext::GetTemporaryGuestAllocator(LPCWSTR name)
  2018. {
  2019. AssertCanHandleOutOfMemory();
  2020. if (temporaryGuestArenaAllocatorCount != 0)
  2021. {
  2022. temporaryGuestArenaAllocatorCount--;
  2023. Js::TempGuestArenaAllocatorObject * allocator = recyclableData->temporaryGuestArenaAllocators[temporaryGuestArenaAllocatorCount];
  2024. allocator->AdviseInUse();
  2025. recyclableData->temporaryGuestArenaAllocators[temporaryGuestArenaAllocatorCount] = nullptr;
  2026. return allocator;
  2027. }
  2028. return Js::TempGuestArenaAllocatorObject::Create(this);
  2029. }
  2030. void
  2031. ThreadContext::ReleaseTemporaryGuestAllocator(Js::TempGuestArenaAllocatorObject * tempGuestAllocator)
  2032. {
  2033. if (temporaryGuestArenaAllocatorCount < MaxTemporaryArenaAllocators)
  2034. {
  2035. tempGuestAllocator->AdviseNotInUse();
  2036. recyclableData->temporaryGuestArenaAllocators[temporaryGuestArenaAllocatorCount] = tempGuestAllocator;
  2037. temporaryGuestArenaAllocatorCount++;
  2038. return;
  2039. }
  2040. tempGuestAllocator->Dispose(false);
  2041. }
  2042. void
  2043. ThreadContext::AddToPendingScriptContextCloseList(Js::ScriptContext * scriptContext)
  2044. {
  2045. Assert(scriptContext != nullptr);
  2046. if (rootPendingClose == nullptr)
  2047. {
  2048. rootPendingClose = scriptContext;
  2049. return;
  2050. }
  2051. // Prepend to the list.
  2052. scriptContext->SetNextPendingClose(rootPendingClose);
  2053. rootPendingClose = scriptContext;
  2054. }
  2055. void
  2056. ThreadContext::RemoveFromPendingClose(Js::ScriptContext * scriptContext)
  2057. {
  2058. Assert(scriptContext != nullptr);
  2059. if (rootPendingClose == nullptr)
  2060. {
  2061. // We already sent a close message, ignore the notification.
  2062. return;
  2063. }
  2064. // Base case: The root is being removed. Move the root along.
  2065. if (scriptContext == rootPendingClose)
  2066. {
  2067. rootPendingClose = rootPendingClose->GetNextPendingClose();
  2068. return;
  2069. }
  2070. Js::ScriptContext * currScriptContext = rootPendingClose;
  2071. Js::ScriptContext * nextScriptContext = nullptr;
  2072. while (currScriptContext)
  2073. {
  2074. nextScriptContext = currScriptContext->GetNextPendingClose();
  2075. if (!nextScriptContext)
  2076. {
  2077. break;
  2078. }
  2079. if (nextScriptContext == scriptContext) {
  2080. // The next pending close ScriptContext is the one to be removed - set prev->next to next->next
  2081. currScriptContext->SetNextPendingClose(nextScriptContext->GetNextPendingClose());
  2082. return;
  2083. }
  2084. currScriptContext = nextScriptContext;
  2085. }
  2086. // We expect to find scriptContext in the pending close list.
  2087. Assert(false);
  2088. }
  2089. void ThreadContext::ClosePendingScriptContexts()
  2090. {
  2091. Js::ScriptContext * scriptContext = rootPendingClose;
  2092. if (scriptContext == nullptr)
  2093. {
  2094. return;
  2095. }
  2096. Js::ScriptContext * nextScriptContext;
  2097. do
  2098. {
  2099. nextScriptContext = scriptContext->GetNextPendingClose();
  2100. scriptContext->Close(false);
  2101. scriptContext = nextScriptContext;
  2102. }
  2103. while (scriptContext);
  2104. rootPendingClose = nullptr;
  2105. }
  2106. void
  2107. ThreadContext::AddToPendingProjectionContextCloseList(IProjectionContext *projectionContext)
  2108. {
  2109. pendingProjectionContextCloseList->Add(projectionContext);
  2110. }
  2111. void
  2112. ThreadContext::RemoveFromPendingClose(IProjectionContext* projectionContext)
  2113. {
  2114. pendingProjectionContextCloseList->Remove(projectionContext);
  2115. }
  2116. void ThreadContext::ClosePendingProjectionContexts()
  2117. {
  2118. IProjectionContext* projectionContext;
  2119. for (int i = 0 ; i < pendingProjectionContextCloseList->Count(); i++)
  2120. {
  2121. projectionContext = pendingProjectionContextCloseList->Item(i);
  2122. projectionContext->Close();
  2123. }
  2124. pendingProjectionContextCloseList->Clear();
  2125. }
  2126. void
  2127. ThreadContext::RegisterScriptContext(Js::ScriptContext *scriptContext)
  2128. {
  2129. // NOTE: ETW rundown thread may be reading the scriptContextList concurrently. We don't need to
  2130. // lock access because we only insert to the front here.
  2131. scriptContext->next = this->scriptContextList;
  2132. if (this->scriptContextList)
  2133. {
  2134. Assert(this->scriptContextList->prev == NULL);
  2135. this->scriptContextList->prev = scriptContext;
  2136. }
  2137. scriptContext->prev = NULL;
  2138. this->scriptContextList = scriptContext;
  2139. if(NoJIT())
  2140. {
  2141. scriptContext->ForceNoNative();
  2142. }
  2143. #if DBG || defined(RUNTIME_DATA_COLLECTION)
  2144. scriptContextCount++;
  2145. #endif
  2146. scriptContextEverRegistered = true;
  2147. }
  2148. void
  2149. ThreadContext::UnregisterScriptContext(Js::ScriptContext *scriptContext)
  2150. {
  2151. // NOTE: ETW rundown thread may be reading the scriptContextList concurrently. Since this function
  2152. // is only called by ~ScriptContext() which already synchronized to ETW rundown, we are safe here.
  2153. if (scriptContext == this->scriptContextList)
  2154. {
  2155. Assert(scriptContext->prev == NULL);
  2156. this->scriptContextList = scriptContext->next;
  2157. }
  2158. else
  2159. {
  2160. scriptContext->prev->next = scriptContext->next;
  2161. }
  2162. if (scriptContext->next)
  2163. {
  2164. scriptContext->next->prev = scriptContext->prev;
  2165. }
  2166. scriptContext->prev = nullptr;
  2167. scriptContext->next = nullptr;
  2168. #if DBG || defined(RUNTIME_DATA_COLLECTION)
  2169. scriptContextCount--;
  2170. #endif
  2171. }
  2172. ThreadContext::CollectCallBack *
  2173. ThreadContext::AddRecyclerCollectCallBack(RecyclerCollectCallBackFunction callback, void * context)
  2174. {
  2175. AutoCriticalSection autocs(&csCollectionCallBack);
  2176. CollectCallBack * collectCallBack = this->collectCallBackList.PrependNode(&HeapAllocator::Instance);
  2177. collectCallBack->callback = callback;
  2178. collectCallBack->context = context;
  2179. this->hasCollectionCallBack = true;
  2180. return collectCallBack;
  2181. }
  2182. void
  2183. ThreadContext::RemoveRecyclerCollectCallBack(ThreadContext::CollectCallBack * collectCallBack)
  2184. {
  2185. AutoCriticalSection autocs(&csCollectionCallBack);
  2186. this->collectCallBackList.RemoveElement(&HeapAllocator::Instance, collectCallBack);
  2187. this->hasCollectionCallBack = !this->collectCallBackList.Empty();
  2188. }
  2189. void
  2190. ThreadContext::PreCollectionCallBack(CollectionFlags flags)
  2191. {
  2192. #ifdef PERF_COUNTERS
  2193. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: deferparse - # of func: %d # deferparsed: %d\n"), PerfCounter::CodeCounterSet::GetTotalFunctionCounter().GetValue(), PerfCounter::CodeCounterSet::GetDeferredFunctionCounter().GetValue());
  2194. #endif
  2195. // This needs to be done before ClearInlineCaches since that method can empty the list of
  2196. // script contexts with inline caches
  2197. this->ClearScriptContextCaches();
  2198. // Clear up references to types to avoid keep them alive
  2199. this->ClearPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesCaches();
  2200. // Clean up unused memory before we start collecting
  2201. this->CleanNoCasePropertyMap();
  2202. this->TryEnterExpirableCollectMode();
  2203. const BOOL concurrent = flags & CollectMode_Concurrent;
  2204. const BOOL partial = flags & CollectMode_Partial;
  2205. if (!partial)
  2206. {
  2207. // Integrate allocated pages from background JIT threads
  2208. #if ENABLE_NATIVE_CODEGEN
  2209. #if !FLOATVAR
  2210. if (codeGenNumberThreadAllocator)
  2211. {
  2212. codeGenNumberThreadAllocator->Integrate();
  2213. }
  2214. if (this->xProcNumberPageSegmentManager)
  2215. {
  2216. this->xProcNumberPageSegmentManager->Integrate();
  2217. }
  2218. #endif
  2219. #endif
  2220. }
  2221. RecyclerCollectCallBackFlags callBackFlags = (RecyclerCollectCallBackFlags)
  2222. ((concurrent ? Collect_Begin_Concurrent : Collect_Begin) | (partial? Collect_Begin_Partial : Collect_Begin));
  2223. CollectionCallBack(callBackFlags);
  2224. }
  2225. void
  2226. ThreadContext::PreSweepCallback()
  2227. {
  2228. #ifdef PERSISTENT_INLINE_CACHES
  2229. ClearInlineCachesWithDeadWeakRefs();
  2230. #else
  2231. ClearInlineCaches();
  2232. #endif
  2233. ClearIsInstInlineCaches();
  2234. ClearEquivalentTypeCaches();
  2235. ClearForInCaches();
  2236. this->dynamicObjectEnumeratorCacheMap.Clear();
  2237. }
  2238. void
  2239. ThreadContext::CollectionCallBack(RecyclerCollectCallBackFlags flags)
  2240. {
  2241. DListBase<CollectCallBack>::Iterator i(&this->collectCallBackList);
  2242. while (i.Next())
  2243. {
  2244. i.Data().callback(i.Data().context, flags);
  2245. }
  2246. }
  2247. void
  2248. ThreadContext::WaitCollectionCallBack()
  2249. {
  2250. // Avoid taking the lock if there are no call back
  2251. if (hasCollectionCallBack)
  2252. {
  2253. AutoCriticalSection autocs(&csCollectionCallBack);
  2254. CollectionCallBack(Collect_Wait);
  2255. }
  2256. }
  2257. void
  2258. ThreadContext::PostCollectionCallBack()
  2259. {
  2260. CollectionCallBack(Collect_End);
  2261. TryExitExpirableCollectMode();
  2262. // Recycler is null in the case where the ThreadContext is in the process of creating the recycler and
  2263. // we have a GC triggered (say because the -recyclerStress flag is passed in)
  2264. if (this->recycler != NULL)
  2265. {
  2266. if (this->recycler->InCacheCleanupCollection())
  2267. {
  2268. this->recycler->ClearCacheCleanupCollection();
  2269. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext; scriptContext = scriptContext->next)
  2270. {
  2271. scriptContext->CleanupWeakReferenceDictionaries();
  2272. }
  2273. }
  2274. }
  2275. }
  2276. void
  2277. ThreadContext::PostSweepRedeferralCallBack()
  2278. {
  2279. if (this->DoTryRedeferral())
  2280. {
  2281. HRESULT hr = S_OK;
  2282. BEGIN_TRANSLATE_OOM_TO_HRESULT
  2283. {
  2284. this->TryRedeferral();
  2285. }
  2286. END_TRANSLATE_OOM_TO_HRESULT(hr);
  2287. }
  2288. this->UpdateRedeferralState();
  2289. }
  2290. bool
  2291. ThreadContext::DoTryRedeferral() const
  2292. {
  2293. if (PHASE_FORCE1(Js::RedeferralPhase) || PHASE_STRESS1(Js::RedeferralPhase))
  2294. {
  2295. return true;
  2296. }
  2297. if (PHASE_OFF1(Js::RedeferralPhase))
  2298. {
  2299. return false;
  2300. }
  2301. switch (this->redeferralState)
  2302. {
  2303. case InitialRedeferralState:
  2304. return false;
  2305. case StartupRedeferralState:
  2306. return gcSinceCallCountsCollected >= StartupRedeferralInactiveThreshold;
  2307. case MainRedeferralState:
  2308. return gcSinceCallCountsCollected >= MainRedeferralInactiveThreshold;
  2309. default:
  2310. Assert(0);
  2311. return false;
  2312. };
  2313. }
  2314. bool
  2315. ThreadContext::DoRedeferFunctionBodies() const
  2316. {
  2317. #if ENABLE_TTD
  2318. if (this->IsRuntimeInTTDMode())
  2319. {
  2320. return false;
  2321. }
  2322. #endif
  2323. if (PHASE_FORCE1(Js::RedeferralPhase) || PHASE_STRESS1(Js::RedeferralPhase))
  2324. {
  2325. return true;
  2326. }
  2327. if (PHASE_OFF1(Js::RedeferralPhase))
  2328. {
  2329. return false;
  2330. }
  2331. switch (this->redeferralState)
  2332. {
  2333. case InitialRedeferralState:
  2334. return false;
  2335. case StartupRedeferralState:
  2336. return gcSinceLastRedeferral >= StartupRedeferralCheckInterval;
  2337. case MainRedeferralState:
  2338. return gcSinceLastRedeferral >= MainRedeferralCheckInterval;
  2339. default:
  2340. Assert(0);
  2341. return false;
  2342. };
  2343. }
  2344. uint
  2345. ThreadContext::GetRedeferralCollectionInterval() const
  2346. {
  2347. switch(this->redeferralState)
  2348. {
  2349. case InitialRedeferralState:
  2350. return InitialRedeferralDelay;
  2351. case StartupRedeferralState:
  2352. return StartupRedeferralCheckInterval;
  2353. case MainRedeferralState:
  2354. return MainRedeferralCheckInterval;
  2355. default:
  2356. Assert(0);
  2357. return (uint)-1;
  2358. }
  2359. }
  2360. uint
  2361. ThreadContext::GetRedeferralInactiveThreshold() const
  2362. {
  2363. switch(this->redeferralState)
  2364. {
  2365. case InitialRedeferralState:
  2366. return InitialRedeferralDelay;
  2367. case StartupRedeferralState:
  2368. return StartupRedeferralInactiveThreshold;
  2369. case MainRedeferralState:
  2370. return MainRedeferralInactiveThreshold;
  2371. default:
  2372. Assert(0);
  2373. return (uint)-1;
  2374. }
  2375. }
  2376. void
  2377. ThreadContext::TryRedeferral()
  2378. {
  2379. bool doRedefer = this->DoRedeferFunctionBodies();
  2380. // Collect the set of active functions.
  2381. ActiveFunctionSet *pActiveFuncs = nullptr;
  2382. if (doRedefer)
  2383. {
  2384. pActiveFuncs = Anew(this->GetThreadAlloc(), ActiveFunctionSet, this->GetThreadAlloc());
  2385. this->GetActiveFunctions(pActiveFuncs);
  2386. #if DBG
  2387. this->redeferredFunctions = 0;
  2388. this->recoveredBytes = 0;
  2389. #endif
  2390. }
  2391. uint inactiveThreshold = this->GetRedeferralInactiveThreshold();
  2392. Js::ScriptContext *scriptContext;
  2393. for (scriptContext = GetScriptContextList(); scriptContext; scriptContext = scriptContext->next)
  2394. {
  2395. if (scriptContext->IsClosed())
  2396. {
  2397. continue;
  2398. }
  2399. scriptContext->RedeferFunctionBodies(pActiveFuncs, inactiveThreshold);
  2400. }
  2401. if (pActiveFuncs)
  2402. {
  2403. Adelete(this->GetThreadAlloc(), pActiveFuncs);
  2404. #if DBG
  2405. if (PHASE_STATS1(Js::RedeferralPhase) && this->redeferredFunctions)
  2406. {
  2407. Output::Print(_u("Redeferred: %d, Bytes: 0x%x\n"), this->redeferredFunctions, this->recoveredBytes);
  2408. }
  2409. #endif
  2410. }
  2411. }
  2412. void
  2413. ThreadContext::GetActiveFunctions(ActiveFunctionSet * pActiveFuncs)
  2414. {
  2415. if (!this->IsInScript() || this->entryExitRecord == nullptr)
  2416. {
  2417. return;
  2418. }
  2419. Js::JavascriptStackWalker walker(GetScriptContextList(), TRUE, NULL, true);
  2420. Js::JavascriptFunction *function = nullptr;
  2421. while (walker.GetCallerWithoutInlinedFrames(&function))
  2422. {
  2423. if (function->GetFunctionInfo()->HasBody())
  2424. {
  2425. Js::FunctionBody *body = function->GetFunctionInfo()->GetFunctionBody();
  2426. body->UpdateActiveFunctionSet(pActiveFuncs, nullptr);
  2427. }
  2428. }
  2429. }
  2430. void
  2431. ThreadContext::UpdateRedeferralState()
  2432. {
  2433. uint inactiveThreshold = this->GetRedeferralInactiveThreshold();
  2434. uint collectInterval = this->GetRedeferralCollectionInterval();
  2435. if (this->gcSinceCallCountsCollected >= inactiveThreshold)
  2436. {
  2437. this->gcSinceCallCountsCollected = 0;
  2438. if (this->gcSinceLastRedeferral >= collectInterval)
  2439. {
  2440. // Advance state
  2441. switch (this->redeferralState)
  2442. {
  2443. case InitialRedeferralState:
  2444. this->redeferralState = StartupRedeferralState;
  2445. break;
  2446. case StartupRedeferralState:
  2447. this->redeferralState = MainRedeferralState;
  2448. break;
  2449. case MainRedeferralState:
  2450. break;
  2451. default:
  2452. Assert(0);
  2453. break;
  2454. }
  2455. this->gcSinceLastRedeferral = 0;
  2456. }
  2457. }
  2458. else
  2459. {
  2460. this->gcSinceCallCountsCollected++;
  2461. this->gcSinceLastRedeferral++;
  2462. }
  2463. }
  2464. void
  2465. ThreadContext::PreDisposeObjectsCallBack()
  2466. {
  2467. this->expirableObjectDisposeList->Clear();
  2468. }
  2469. #ifdef FAULT_INJECTION
  2470. void
  2471. ThreadContext::DisposeScriptContextByFaultInjectionCallBack()
  2472. {
  2473. if (FAULTINJECT_SCRIPT_TERMINATION_ON_DISPOSE) {
  2474. int scriptContextToClose = -1;
  2475. /* inject only if we have more than 1 script context*/
  2476. uint totalScriptCount = GetScriptContextCount();
  2477. if (totalScriptCount > 1) {
  2478. if (Js::Configuration::Global.flags.FaultInjectionScriptContextToTerminateCount > 0)
  2479. {
  2480. scriptContextToClose = Js::Configuration::Global.flags.FaultInjectionScriptContextToTerminateCount % totalScriptCount;
  2481. for (Js::ScriptContext *scriptContext = GetScriptContextList(); scriptContext; scriptContext = scriptContext->next)
  2482. {
  2483. if (scriptContextToClose-- == 0)
  2484. {
  2485. scriptContext->DisposeScriptContextByFaultInjection();
  2486. break;
  2487. }
  2488. }
  2489. }
  2490. else
  2491. {
  2492. fwprintf(stderr, _u("***FI: FaultInjectionScriptContextToTerminateCount Failed, Value should be > 0. \n"));
  2493. }
  2494. }
  2495. }
  2496. }
  2497. #endif
  2498. #pragma region "Expirable Object Methods"
  2499. void
  2500. ThreadContext::TryExitExpirableCollectMode()
  2501. {
  2502. // If this feature is turned off or if we're already in profile collection mode, do nothing
  2503. // We also do nothing if expiration is explicitly disabled by someone lower down the stack
  2504. if (PHASE_OFF1(Js::ExpirableCollectPhase) || !InExpirableCollectMode() || this->disableExpiration)
  2505. {
  2506. return;
  2507. }
  2508. if (InExpirableCollectMode())
  2509. {
  2510. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Checking to see whether to complete Expirable Object Collection: GC Count is %d\n"), this->expirableCollectModeGcCount);
  2511. if (this->expirableCollectModeGcCount > 0)
  2512. {
  2513. this->expirableCollectModeGcCount--;
  2514. }
  2515. if (this->expirableCollectModeGcCount == 0 &&
  2516. (this->recycler->InCacheCleanupCollection() || CONFIG_FLAG(ForceExpireOnNonCacheCollect)))
  2517. {
  2518. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Completing Expirable Object Collection\n"));
  2519. ExpirableObjectList::Iterator expirableObjectIterator(this->expirableObjectList);
  2520. while (expirableObjectIterator.Next())
  2521. {
  2522. ExpirableObject* object = expirableObjectIterator.Data();
  2523. Assert(object);
  2524. if (!object->IsObjectUsed())
  2525. {
  2526. object->Expire();
  2527. }
  2528. }
  2529. // Leave expirable collection mode
  2530. expirableCollectModeGcCount = -1;
  2531. }
  2532. }
  2533. }
  2534. bool
  2535. ThreadContext::InExpirableCollectMode()
  2536. {
  2537. // We're in expirable collect if we have expirable objects registered,
  2538. // and expirableCollectModeGcCount is not negative
  2539. // and when debugger is attaching, it might have set the function to deferredParse.
  2540. return (expirableObjectList != nullptr &&
  2541. numExpirableObjects > 0 &&
  2542. expirableCollectModeGcCount >= 0
  2543. #ifdef ENABLE_SCRIPT_DEBUGGING
  2544. &&
  2545. (this->GetDebugManager() != nullptr &&
  2546. !this->GetDebugManager()->IsDebuggerAttaching())
  2547. #endif
  2548. );
  2549. }
  2550. void
  2551. ThreadContext::TryEnterExpirableCollectMode()
  2552. {
  2553. // If this feature is turned off or if we're already in profile collection mode, do nothing
  2554. if (PHASE_OFF1(Js::ExpirableCollectPhase) || InExpirableCollectMode())
  2555. {
  2556. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Not running Expirable Object Collection\n"));
  2557. return;
  2558. }
  2559. double entryPointCollectionThreshold = Js::Configuration::Global.flags.ExpirableCollectionTriggerThreshold / 100.0;
  2560. double currentThreadNativeCodeRatio = ((double) GetCodeSize()) / Js::Constants::MaxThreadJITCodeHeapSize;
  2561. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Current native code ratio: %f\n"), currentThreadNativeCodeRatio);
  2562. if (currentThreadNativeCodeRatio > entryPointCollectionThreshold)
  2563. {
  2564. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Setting up Expirable Object Collection\n"));
  2565. this->expirableCollectModeGcCount = Js::Configuration::Global.flags.ExpirableCollectionGCCount;
  2566. ExpirableObjectList::Iterator expirableObjectIterator(this->expirableObjectList);
  2567. while (expirableObjectIterator.Next())
  2568. {
  2569. ExpirableObject* object = expirableObjectIterator.Data();
  2570. Assert(object);
  2571. object->EnterExpirableCollectMode();
  2572. }
  2573. if (this->entryExitRecord != nullptr)
  2574. {
  2575. // If we're in script, we will do a stack walk, find the JavascriptFunction's on the stack
  2576. // and mark their entry points as being used so that we don't prematurely expire them
  2577. Js::ScriptContext* topScriptContext = this->entryExitRecord->scriptContext;
  2578. Js::JavascriptStackWalker walker(topScriptContext, TRUE);
  2579. Js::JavascriptFunction* javascriptFunction = nullptr;
  2580. while (walker.GetCallerWithoutInlinedFrames(&javascriptFunction))
  2581. {
  2582. if (javascriptFunction != nullptr && Js::ScriptFunction::Test(javascriptFunction))
  2583. {
  2584. Js::ScriptFunction* scriptFunction = (Js::ScriptFunction*) javascriptFunction;
  2585. Js::FunctionEntryPointInfo* entryPointInfo = scriptFunction->GetFunctionEntryPointInfo();
  2586. entryPointInfo->SetIsObjectUsed();
  2587. scriptFunction->GetFunctionBody()->MapEntryPoints([](int index, Js::FunctionEntryPointInfo* entryPoint){
  2588. entryPoint->SetIsObjectUsed();
  2589. });
  2590. }
  2591. }
  2592. }
  2593. }
  2594. }
  2595. void
  2596. ThreadContext::RegisterExpirableObject(ExpirableObject* object)
  2597. {
  2598. Assert(this->expirableObjectList);
  2599. Assert(object->registrationHandle == nullptr);
  2600. ExpirableObject** registrationData = this->expirableObjectList->PrependNode();
  2601. (*registrationData) = object;
  2602. object->registrationHandle = (void*) registrationData;
  2603. OUTPUT_VERBOSE_TRACE(Js::ExpirableCollectPhase, _u("Registered 0x%p\n"), object);
  2604. numExpirableObjects++;
  2605. }
  2606. void
  2607. ThreadContext::UnregisterExpirableObject(ExpirableObject* object)
  2608. {
  2609. Assert(this->expirableObjectList);
  2610. Assert(object->registrationHandle != nullptr);
  2611. ExpirableObject** registrationData = (ExpirableObject**)PointerValue(object->registrationHandle);
  2612. Assert(*registrationData == object);
  2613. this->expirableObjectList->MoveElementTo(registrationData, this->expirableObjectDisposeList);
  2614. object->registrationHandle = nullptr;
  2615. OUTPUT_VERBOSE_TRACE(Js::ExpirableCollectPhase, _u("Unregistered 0x%p\n"), object);
  2616. numExpirableObjects--;
  2617. }
  2618. #pragma endregion
  2619. void
  2620. ThreadContext::ClearScriptContextCaches()
  2621. {
  2622. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext != nullptr; scriptContext = scriptContext->next)
  2623. {
  2624. scriptContext->ClearScriptContextCaches();
  2625. }
  2626. }
  2627. #ifdef PERSISTENT_INLINE_CACHES
  2628. void
  2629. ThreadContext::ClearInlineCachesWithDeadWeakRefs()
  2630. {
  2631. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext != nullptr; scriptContext = scriptContext->next)
  2632. {
  2633. scriptContext->ClearInlineCachesWithDeadWeakRefs();
  2634. }
  2635. if (PHASE_TRACE1(Js::InlineCachePhase))
  2636. {
  2637. size_t size = 0;
  2638. size_t freeListSize = 0;
  2639. size_t polyInlineCacheSize = 0;
  2640. uint scriptContextCount = 0;
  2641. for (Js::ScriptContext *scriptContext = scriptContextList;
  2642. scriptContext;
  2643. scriptContext = scriptContext->next)
  2644. {
  2645. scriptContextCount++;
  2646. size += scriptContext->GetInlineCacheAllocator()->AllocatedSize();
  2647. freeListSize += scriptContext->GetInlineCacheAllocator()->FreeListSize();
  2648. #ifdef POLY_INLINE_CACHE_SIZE_STATS
  2649. polyInlineCacheSize += scriptContext->GetInlineCacheAllocator()->GetPolyInlineCacheSize();
  2650. #endif
  2651. };
  2652. printf("Inline cache arena: total = %5I64u KB, free list = %5I64u KB, poly caches = %5I64u KB, script contexts = %u\n",
  2653. static_cast<uint64>(size / 1024), static_cast<uint64>(freeListSize / 1024), static_cast<uint64>(polyInlineCacheSize / 1024), scriptContextCount);
  2654. }
  2655. }
  2656. #if ENABLE_NATIVE_CODEGEN
  2657. void
  2658. ThreadContext::ClearInvalidatedUniqueGuards()
  2659. {
  2660. // If a propertyGuard was invalidated, make sure to remove it's entry from unique property guard table of other property records.
  2661. PropertyGuardDictionary &guards = this->recyclableData->propertyGuards;
  2662. guards.Map([this](Js::PropertyRecord const * propertyRecord, PropertyGuardEntry* entry, const RecyclerWeakReference<const Js::PropertyRecord>* weakRef)
  2663. {
  2664. entry->uniqueGuards.MapAndRemoveIf([=](RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
  2665. {
  2666. Js::PropertyGuard* guard = guardWeakRef->Get();
  2667. bool shouldRemove = guard != nullptr && !guard->IsValid();
  2668. if (shouldRemove)
  2669. {
  2670. if (PHASE_TRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TRACE1(Js::FixedMethodsPhase))
  2671. {
  2672. Output::Print(_u("FixedFields: invalidating guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p\n"),
  2673. propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue());
  2674. Output::Flush();
  2675. }
  2676. if (PHASE_TESTTRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TESTTRACE1(Js::FixedMethodsPhase))
  2677. {
  2678. Output::Print(_u("FixedFields: invalidating guard: name: %s, value: 0x%p\n"),
  2679. propertyRecord->GetBuffer(), guard->GetValue());
  2680. Output::Flush();
  2681. }
  2682. }
  2683. return shouldRemove;
  2684. });
  2685. });
  2686. }
  2687. #endif
  2688. void
  2689. ThreadContext::ClearInlineCaches()
  2690. {
  2691. if (PHASE_TRACE1(Js::InlineCachePhase))
  2692. {
  2693. size_t size = 0;
  2694. size_t freeListSize = 0;
  2695. size_t polyInlineCacheSize = 0;
  2696. uint scriptContextCount = 0;
  2697. for (Js::ScriptContext *scriptContext = scriptContextList;
  2698. scriptContext;
  2699. scriptContext = scriptContext->next)
  2700. {
  2701. scriptContextCount++;
  2702. size += scriptContext->GetInlineCacheAllocator()->AllocatedSize();
  2703. freeListSize += scriptContext->GetInlineCacheAllocator()->FreeListSize();
  2704. #ifdef POLY_INLINE_CACHE_SIZE_STATS
  2705. polyInlineCacheSize += scriptContext->GetInlineCacheAllocator()->GetPolyInlineCacheSize();
  2706. #endif
  2707. };
  2708. printf("Inline cache arena: total = %5I64u KB, free list = %5I64u KB, poly caches = %5I64u KB, script contexts = %u\n",
  2709. static_cast<uint64>(size / 1024), static_cast<uint64>(freeListSize / 1024), static_cast<uint64>(polyInlineCacheSize / 1024), scriptContextCount);
  2710. }
  2711. Js::ScriptContext *scriptContext = this->scriptContextList;
  2712. while (scriptContext != nullptr)
  2713. {
  2714. scriptContext->ClearInlineCaches();
  2715. scriptContext = scriptContext->next;
  2716. }
  2717. inlineCacheThreadInfoAllocator.Reset();
  2718. protoInlineCacheByPropId.ResetNoDelete();
  2719. storeFieldInlineCacheByPropId.ResetNoDelete();
  2720. registeredInlineCacheCount = 0;
  2721. unregisteredInlineCacheCount = 0;
  2722. }
  2723. #endif //PERSISTENT_INLINE_CACHES
  2724. void
  2725. ThreadContext::ClearIsInstInlineCaches()
  2726. {
  2727. Js::ScriptContext *scriptContext = this->scriptContextList;
  2728. while (scriptContext != nullptr)
  2729. {
  2730. scriptContext->ClearIsInstInlineCaches();
  2731. scriptContext = scriptContext->next;
  2732. }
  2733. isInstInlineCacheThreadInfoAllocator.Reset();
  2734. isInstInlineCacheByFunction.ResetNoDelete();
  2735. }
  2736. void
  2737. ThreadContext::ClearForInCaches()
  2738. {
  2739. Js::ScriptContext *scriptContext = this->scriptContextList;
  2740. while (scriptContext != nullptr)
  2741. {
  2742. scriptContext->ClearForInCaches();
  2743. scriptContext = scriptContext->next;
  2744. }
  2745. }
  2746. void
  2747. ThreadContext::ClearEquivalentTypeCaches()
  2748. {
  2749. #if ENABLE_NATIVE_CODEGEN
  2750. // Called from PreSweepCallback to clear pointers to types that have no live object references left.
  2751. // The EquivalentTypeCache used to keep these types alive, but this caused memory growth in cases where
  2752. // entry points stayed around for a long time.
  2753. // In future we may want to pin the reference/guard type to the entry point, but that choice will depend
  2754. // on a use case where pinning the type helps us optimize. Lacking that, clearing the guard type is a
  2755. // simpler short-term solution.
  2756. // Note that clearing unmarked types from the cache and guard is needed for correctness if the cache doesn't keep
  2757. // the types alive.
  2758. FOREACH_DLISTBASE_ENTRY_EDITING(Js::EntryPointInfo *, entryPoint, &equivalentTypeCacheEntryPoints, iter)
  2759. {
  2760. bool isLive = entryPoint->ClearEquivalentTypeCaches();
  2761. if (!isLive)
  2762. {
  2763. iter.RemoveCurrent(&equivalentTypeCacheInfoAllocator);
  2764. }
  2765. }
  2766. NEXT_DLISTBASE_ENTRY_EDITING;
  2767. // Note: Don't reset the list, because we're only clearing the dead types from these caches.
  2768. // There may still be type references we need to keep an eye on.
  2769. #endif
  2770. }
  2771. Js::EntryPointInfo **
  2772. ThreadContext::RegisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo * entryPoint)
  2773. {
  2774. return equivalentTypeCacheEntryPoints.PrependNode(&equivalentTypeCacheInfoAllocator, entryPoint);
  2775. }
  2776. void
  2777. ThreadContext::UnregisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo ** entryPoint)
  2778. {
  2779. equivalentTypeCacheEntryPoints.RemoveElement(&equivalentTypeCacheInfoAllocator, entryPoint);
  2780. }
  2781. void
  2782. ThreadContext::RegisterProtoInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId)
  2783. {
  2784. if (PHASE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  2785. {
  2786. Output::Print(_u("InlineCacheInvalidation: registering proto cache 0x%p for property %s(%u)\n"),
  2787. inlineCache, GetPropertyName(propertyId)->GetBuffer(), propertyId);
  2788. Output::Flush();
  2789. }
  2790. RegisterInlineCache(protoInlineCacheByPropId, inlineCache, propertyId);
  2791. }
  2792. void
  2793. ThreadContext::RegisterStoreFieldInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId)
  2794. {
  2795. if (PHASE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  2796. {
  2797. Output::Print(_u("InlineCacheInvalidation: registering store field cache 0x%p for property %s(%u)\n"),
  2798. inlineCache, GetPropertyName(propertyId)->GetBuffer(), propertyId);
  2799. Output::Flush();
  2800. }
  2801. RegisterInlineCache(storeFieldInlineCacheByPropId, inlineCache, propertyId);
  2802. }
  2803. void
  2804. ThreadContext::RegisterInlineCache(InlineCacheListMapByPropertyId& inlineCacheMap, Js::InlineCache * inlineCache, Js::PropertyId propertyId)
  2805. {
  2806. InlineCacheList* inlineCacheList;
  2807. if (!inlineCacheMap.TryGetValue(propertyId, &inlineCacheList))
  2808. {
  2809. inlineCacheList = Anew(&this->inlineCacheThreadInfoAllocator, InlineCacheList, &this->inlineCacheThreadInfoAllocator);
  2810. inlineCacheMap.AddNew(propertyId, inlineCacheList);
  2811. }
  2812. Js::InlineCache** inlineCacheRef = inlineCacheList->PrependNode();
  2813. Assert(inlineCacheRef != nullptr);
  2814. *inlineCacheRef = inlineCache;
  2815. inlineCache->invalidationListSlotPtr = inlineCacheRef;
  2816. this->registeredInlineCacheCount++;
  2817. }
  2818. void ThreadContext::NotifyInlineCacheBatchUnregistered(uint count)
  2819. {
  2820. this->unregisteredInlineCacheCount += count;
  2821. // Negative or 0 InlineCacheInvalidationListCompactionThreshold forces compaction all the time.
  2822. if (CONFIG_FLAG(InlineCacheInvalidationListCompactionThreshold) <= 0 ||
  2823. this->registeredInlineCacheCount / this->unregisteredInlineCacheCount < (uint)CONFIG_FLAG(InlineCacheInvalidationListCompactionThreshold))
  2824. {
  2825. CompactInlineCacheInvalidationLists();
  2826. }
  2827. }
  2828. void
  2829. ThreadContext::InvalidateProtoInlineCaches(Js::PropertyId propertyId)
  2830. {
  2831. InlineCacheList* inlineCacheList;
  2832. if (protoInlineCacheByPropId.TryGetValueAndRemove(propertyId, &inlineCacheList))
  2833. {
  2834. if (PHASE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  2835. {
  2836. Output::Print(_u("InlineCacheInvalidation: invalidating proto caches for property %s(%u)\n"),
  2837. GetPropertyName(propertyId)->GetBuffer(), propertyId);
  2838. Output::Flush();
  2839. }
  2840. InvalidateAndDeleteInlineCacheList(inlineCacheList);
  2841. }
  2842. }
  2843. void
  2844. ThreadContext::InvalidateStoreFieldInlineCaches(Js::PropertyId propertyId)
  2845. {
  2846. InlineCacheList* inlineCacheList;
  2847. if (storeFieldInlineCacheByPropId.TryGetValueAndRemove(propertyId, &inlineCacheList))
  2848. {
  2849. if (PHASE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  2850. {
  2851. Output::Print(_u("InlineCacheInvalidation: invalidating store field caches for property %s(%u)\n"),
  2852. GetPropertyName(propertyId)->GetBuffer(), propertyId);
  2853. Output::Flush();
  2854. }
  2855. InvalidateAndDeleteInlineCacheList(inlineCacheList);
  2856. }
  2857. }
  2858. void
  2859. ThreadContext::InvalidateAndDeleteInlineCacheList(InlineCacheList* inlineCacheList)
  2860. {
  2861. Assert(inlineCacheList != nullptr);
  2862. uint cacheCount = 0;
  2863. uint nullCacheCount = 0;
  2864. FOREACH_SLISTBASE_ENTRY(Js::InlineCache*, inlineCache, inlineCacheList)
  2865. {
  2866. cacheCount++;
  2867. if (inlineCache != nullptr)
  2868. {
  2869. if (PHASE_VERBOSE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  2870. {
  2871. Output::Print(_u("InlineCacheInvalidation: invalidating cache 0x%p\n"), inlineCache);
  2872. Output::Flush();
  2873. }
  2874. memset(inlineCache, 0, sizeof(Js::InlineCache));
  2875. }
  2876. else
  2877. {
  2878. nullCacheCount++;
  2879. }
  2880. }
  2881. NEXT_SLISTBASE_ENTRY;
  2882. Adelete(&this->inlineCacheThreadInfoAllocator, inlineCacheList);
  2883. this->registeredInlineCacheCount = this->registeredInlineCacheCount > cacheCount ? this->registeredInlineCacheCount - cacheCount : 0;
  2884. this->unregisteredInlineCacheCount = this->unregisteredInlineCacheCount > nullCacheCount ? this->unregisteredInlineCacheCount - nullCacheCount : 0;
  2885. }
  2886. void
  2887. ThreadContext::CompactInlineCacheInvalidationLists()
  2888. {
  2889. #if DBG
  2890. uint countOfNodesToCompact = this->unregisteredInlineCacheCount;
  2891. this->totalUnregisteredCacheCount = 0;
  2892. #endif
  2893. Assert(this->unregisteredInlineCacheCount > 0);
  2894. CompactProtoInlineCaches();
  2895. if (this->unregisteredInlineCacheCount > 0)
  2896. {
  2897. CompactStoreFieldInlineCaches();
  2898. }
  2899. Assert(countOfNodesToCompact == this->totalUnregisteredCacheCount);
  2900. }
  2901. void
  2902. ThreadContext::CompactProtoInlineCaches()
  2903. {
  2904. protoInlineCacheByPropId.MapUntil([this](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  2905. {
  2906. CompactInlineCacheList(inlineCacheList);
  2907. return this->unregisteredInlineCacheCount == 0;
  2908. });
  2909. }
  2910. void
  2911. ThreadContext::CompactStoreFieldInlineCaches()
  2912. {
  2913. storeFieldInlineCacheByPropId.MapUntil([this](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  2914. {
  2915. CompactInlineCacheList(inlineCacheList);
  2916. return this->unregisteredInlineCacheCount == 0;
  2917. });
  2918. }
  2919. void
  2920. ThreadContext::CompactInlineCacheList(InlineCacheList* inlineCacheList)
  2921. {
  2922. Assert(inlineCacheList != nullptr);
  2923. uint cacheCount = 0;
  2924. FOREACH_SLISTBASE_ENTRY_EDITING(Js::InlineCache*, inlineCache, inlineCacheList, iterator)
  2925. {
  2926. if (inlineCache == nullptr)
  2927. {
  2928. iterator.RemoveCurrent();
  2929. cacheCount++;
  2930. }
  2931. }
  2932. NEXT_SLISTBASE_ENTRY_EDITING;
  2933. #if DBG
  2934. this->totalUnregisteredCacheCount += cacheCount;
  2935. #endif
  2936. if (cacheCount > 0)
  2937. {
  2938. AssertMsg(this->unregisteredInlineCacheCount >= cacheCount, "Some codepaths didn't unregistered the inlineCaches which might leak memory.");
  2939. this->unregisteredInlineCacheCount = this->unregisteredInlineCacheCount > cacheCount ?
  2940. this->unregisteredInlineCacheCount - cacheCount : 0;
  2941. AssertMsg(this->registeredInlineCacheCount >= cacheCount, "Some codepaths didn't registered the inlineCaches which might leak memory.");
  2942. this->registeredInlineCacheCount = this->registeredInlineCacheCount > cacheCount ?
  2943. this->registeredInlineCacheCount - cacheCount : 0;
  2944. }
  2945. }
  2946. #if DBG
  2947. bool
  2948. ThreadContext::IsProtoInlineCacheRegistered(const Js::InlineCache* inlineCache, Js::PropertyId propertyId)
  2949. {
  2950. return IsInlineCacheRegistered(protoInlineCacheByPropId, inlineCache, propertyId);
  2951. }
  2952. bool
  2953. ThreadContext::IsStoreFieldInlineCacheRegistered(const Js::InlineCache* inlineCache, Js::PropertyId propertyId)
  2954. {
  2955. return IsInlineCacheRegistered(storeFieldInlineCacheByPropId, inlineCache, propertyId);
  2956. }
  2957. bool
  2958. ThreadContext::IsInlineCacheRegistered(InlineCacheListMapByPropertyId& inlineCacheMap, const Js::InlineCache* inlineCache, Js::PropertyId propertyId)
  2959. {
  2960. InlineCacheList* inlineCacheList;
  2961. if (inlineCacheMap.TryGetValue(propertyId, &inlineCacheList))
  2962. {
  2963. return IsInlineCacheInList(inlineCache, inlineCacheList);
  2964. }
  2965. else
  2966. {
  2967. return false;
  2968. }
  2969. }
  2970. bool
  2971. ThreadContext::IsInlineCacheInList(const Js::InlineCache* inlineCache, const InlineCacheList* inlineCacheList)
  2972. {
  2973. Assert(inlineCache != nullptr);
  2974. Assert(inlineCacheList != nullptr);
  2975. FOREACH_SLISTBASE_ENTRY(Js::InlineCache*, curInlineCache, inlineCacheList)
  2976. {
  2977. if (curInlineCache == inlineCache)
  2978. {
  2979. return true;
  2980. }
  2981. }
  2982. NEXT_SLISTBASE_ENTRY;
  2983. return false;
  2984. }
  2985. #endif
  2986. #if ENABLE_NATIVE_CODEGEN
  2987. ThreadContext::PropertyGuardEntry*
  2988. ThreadContext::EnsurePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, bool& foundExistingEntry)
  2989. {
  2990. PropertyGuardDictionary &guards = this->recyclableData->propertyGuards;
  2991. PropertyGuardEntry* entry = nullptr;
  2992. foundExistingEntry = guards.TryGetValue(propertyRecord, &entry);
  2993. if (!foundExistingEntry)
  2994. {
  2995. entry = RecyclerNew(GetRecycler(), PropertyGuardEntry, GetRecycler());
  2996. guards.UncheckedAdd(CreatePropertyRecordWeakRef(propertyRecord), entry);
  2997. }
  2998. return entry;
  2999. }
  3000. Js::PropertyGuard*
  3001. ThreadContext::RegisterSharedPropertyGuard(Js::PropertyId propertyId)
  3002. {
  3003. Assert(IsActivePropertyId(propertyId));
  3004. const Js::PropertyRecord * propertyRecord = GetPropertyName(propertyId);
  3005. bool foundExistingGuard;
  3006. PropertyGuardEntry* entry = EnsurePropertyGuardEntry(propertyRecord, foundExistingGuard);
  3007. if (entry->sharedGuard == nullptr)
  3008. {
  3009. entry->sharedGuard = Js::PropertyGuard::New(GetRecycler());
  3010. }
  3011. Js::PropertyGuard* guard = entry->sharedGuard;
  3012. PHASE_PRINT_VERBOSE_TRACE1(Js::FixedMethodsPhase, _u("FixedFields: registered shared guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p, %s\n"),
  3013. propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue(), foundExistingGuard ? _u("existing") : _u("new"));
  3014. PHASE_PRINT_TESTTRACE1(Js::FixedMethodsPhase, _u("FixedFields: registered shared guard: name: %s, value: 0x%p, %s\n"),
  3015. propertyRecord->GetBuffer(), guard->GetValue(), foundExistingGuard ? _u("existing") : _u("new"));
  3016. return guard;
  3017. }
  3018. void
  3019. ThreadContext::RegisterLazyBailout(Js::PropertyId propertyId, Js::EntryPointInfo* entryPoint)
  3020. {
  3021. const Js::PropertyRecord * propertyRecord = GetPropertyName(propertyId);
  3022. bool foundExistingGuard;
  3023. PropertyGuardEntry* entry = EnsurePropertyGuardEntry(propertyRecord, foundExistingGuard);
  3024. if (!entry->entryPoints)
  3025. {
  3026. entry->entryPoints = RecyclerNew(recycler, PropertyGuardEntry::EntryPointDictionary, recycler, /*capacity*/ 3);
  3027. }
  3028. entry->entryPoints->UncheckedAdd(entryPoint, NULL);
  3029. }
  3030. void
  3031. ThreadContext::RegisterUniquePropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard* guard)
  3032. {
  3033. Assert(IsActivePropertyId(propertyId));
  3034. Assert(guard != nullptr);
  3035. RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef = this->recycler->CreateWeakReferenceHandle(guard);
  3036. RegisterUniquePropertyGuard(propertyId, guardWeakRef);
  3037. }
  3038. void
  3039. ThreadContext::RegisterUniquePropertyGuard(Js::PropertyId propertyId, RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
  3040. {
  3041. Assert(IsActivePropertyId(propertyId));
  3042. Assert(guardWeakRef != nullptr);
  3043. Js::PropertyGuard* guard = guardWeakRef->Get();
  3044. Assert(guard != nullptr);
  3045. const Js::PropertyRecord * propertyRecord = GetPropertyName(propertyId);
  3046. bool foundExistingGuard;
  3047. PropertyGuardEntry* entry = EnsurePropertyGuardEntry(propertyRecord, foundExistingGuard);
  3048. entry->uniqueGuards.Item(guardWeakRef);
  3049. if (PHASE_TRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TRACE1(Js::FixedMethodsPhase))
  3050. {
  3051. Output::Print(_u("FixedFields: registered unique guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p, %s entry\n"),
  3052. propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue(), foundExistingGuard ? _u("existing") : _u("new"));
  3053. Output::Flush();
  3054. }
  3055. if (PHASE_TESTTRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TESTTRACE1(Js::FixedMethodsPhase))
  3056. {
  3057. Output::Print(_u("FixedFields: registered unique guard: name: %s, value: 0x%p, %s entry\n"),
  3058. propertyRecord->GetBuffer(), guard->GetValue(), foundExistingGuard ? _u("existing") : _u("new"));
  3059. Output::Flush();
  3060. }
  3061. }
  3062. void
  3063. ThreadContext::RegisterConstructorCache(Js::PropertyId propertyId, Js::ConstructorCache* cache)
  3064. {
  3065. Assert(Js::ConstructorCache::GetOffsetOfGuardValue() == Js::PropertyGuard::GetOffsetOfValue());
  3066. Assert(Js::ConstructorCache::GetSizeOfGuardValue() == Js::PropertyGuard::GetSizeOfValue());
  3067. RegisterUniquePropertyGuard(propertyId, reinterpret_cast<Js::PropertyGuard*>(cache));
  3068. }
  3069. void
  3070. ThreadContext::InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry, bool isAllPropertyGuardsInvalidation)
  3071. {
  3072. Assert(entry != nullptr);
  3073. if (entry->sharedGuard != nullptr)
  3074. {
  3075. Js::PropertyGuard* guard = entry->sharedGuard;
  3076. if (PHASE_TRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TRACE1(Js::FixedMethodsPhase))
  3077. {
  3078. Output::Print(_u("FixedFields: invalidating guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p\n"),
  3079. propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue());
  3080. Output::Flush();
  3081. }
  3082. if (PHASE_TESTTRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TESTTRACE1(Js::FixedMethodsPhase))
  3083. {
  3084. Output::Print(_u("FixedFields: invalidating guard: name: %s, value: 0x%p\n"), propertyRecord->GetBuffer(), guard->GetValue());
  3085. Output::Flush();
  3086. }
  3087. guard->Invalidate();
  3088. }
  3089. uint count = 0;
  3090. entry->uniqueGuards.Map([&count, propertyRecord](RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
  3091. {
  3092. Js::PropertyGuard* guard = guardWeakRef->Get();
  3093. if (guard != nullptr)
  3094. {
  3095. if (PHASE_TRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TRACE1(Js::FixedMethodsPhase))
  3096. {
  3097. Output::Print(_u("FixedFields: invalidating guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p\n"),
  3098. propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue());
  3099. Output::Flush();
  3100. }
  3101. if (PHASE_TESTTRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TESTTRACE1(Js::FixedMethodsPhase))
  3102. {
  3103. Output::Print(_u("FixedFields: invalidating guard: name: %s, value: 0x%p\n"),
  3104. propertyRecord->GetBuffer(), guard->GetValue());
  3105. Output::Flush();
  3106. }
  3107. guard->Invalidate();
  3108. count++;
  3109. }
  3110. });
  3111. entry->uniqueGuards.Clear();
  3112. // Count no. of invalidations done so far. Exclude if this is all property guards invalidation in which case
  3113. // the unique Guards will be cleared anyway.
  3114. if (!isAllPropertyGuardsInvalidation)
  3115. {
  3116. this->recyclableData->constructorCacheInvalidationCount += count;
  3117. if (this->recyclableData->constructorCacheInvalidationCount > (uint)CONFIG_FLAG(ConstructorCacheInvalidationThreshold))
  3118. {
  3119. // TODO: In future, we should compact the uniqueGuards dictionary so this function can be called from PreCollectionCallback
  3120. // instead
  3121. this->ClearInvalidatedUniqueGuards();
  3122. this->recyclableData->constructorCacheInvalidationCount = 0;
  3123. }
  3124. }
  3125. if (entry->entryPoints && entry->entryPoints->Count() > 0)
  3126. {
  3127. Js::JavascriptStackWalker stackWalker(this->GetScriptContextList());
  3128. Js::JavascriptFunction* caller = nullptr;
  3129. while (stackWalker.GetCaller(&caller, /*includeInlineFrames*/ false))
  3130. {
  3131. // If the current frame is already from a bailout - we do not need to do on stack invalidation
  3132. if (caller != nullptr && Js::ScriptFunction::Test(caller) && !stackWalker.GetCurrentFrameFromBailout())
  3133. {
  3134. BYTE dummy;
  3135. Js::FunctionEntryPointInfo* functionEntryPoint = caller->GetFunctionBody()->GetDefaultFunctionEntryPointInfo();
  3136. if (functionEntryPoint->IsInNativeAddressRange((DWORD_PTR)stackWalker.GetInstructionPointer()))
  3137. {
  3138. if (entry->entryPoints->TryGetValue(functionEntryPoint, &dummy))
  3139. {
  3140. functionEntryPoint->DoLazyBailout(stackWalker.GetCurrentAddressOfInstructionPointer(),
  3141. caller->GetFunctionBody(), propertyRecord);
  3142. }
  3143. }
  3144. }
  3145. }
  3146. entry->entryPoints->Map([=](Js::EntryPointInfo* info, BYTE& dummy, const RecyclerWeakReference<Js::EntryPointInfo>* infoWeakRef)
  3147. {
  3148. OUTPUT_TRACE2(Js::LazyBailoutPhase, info->GetFunctionBody(), _u("Lazy bailout - Invalidation due to property: %s \n"), propertyRecord->GetBuffer());
  3149. info->Invalidate(true);
  3150. });
  3151. entry->entryPoints->Clear();
  3152. }
  3153. }
  3154. void
  3155. ThreadContext::InvalidatePropertyGuards(Js::PropertyId propertyId)
  3156. {
  3157. const Js::PropertyRecord* propertyRecord = GetPropertyName(propertyId);
  3158. PropertyGuardDictionary &guards = this->recyclableData->propertyGuards;
  3159. PropertyGuardEntry* entry = nullptr;
  3160. if (guards.TryGetValueAndRemove(propertyRecord, &entry))
  3161. {
  3162. InvalidatePropertyGuardEntry(propertyRecord, entry, false);
  3163. }
  3164. }
  3165. void
  3166. ThreadContext::InvalidateAllPropertyGuards()
  3167. {
  3168. PropertyGuardDictionary &guards = this->recyclableData->propertyGuards;
  3169. if (guards.Count() > 0)
  3170. {
  3171. guards.Map([this](Js::PropertyRecord const * propertyRecord, PropertyGuardEntry* entry, const RecyclerWeakReference<const Js::PropertyRecord>* weakRef)
  3172. {
  3173. InvalidatePropertyGuardEntry(propertyRecord, entry, true);
  3174. });
  3175. guards.Clear();
  3176. }
  3177. }
  3178. #endif
  3179. void
  3180. ThreadContext::InvalidateAllProtoInlineCaches()
  3181. {
  3182. protoInlineCacheByPropId.Map([this](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  3183. {
  3184. InvalidateAndDeleteInlineCacheList(inlineCacheList);
  3185. });
  3186. protoInlineCacheByPropId.Reset();
  3187. }
  3188. #if DBG
  3189. // Verifies if object is registered in any proto InlineCache
  3190. bool
  3191. ThreadContext::IsObjectRegisteredInProtoInlineCaches(Js::DynamicObject * object)
  3192. {
  3193. return protoInlineCacheByPropId.MapUntil([object](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  3194. {
  3195. FOREACH_SLISTBASE_ENTRY(Js::InlineCache*, inlineCache, inlineCacheList)
  3196. {
  3197. if (inlineCache != nullptr && !inlineCache->IsEmpty())
  3198. {
  3199. // Verify this object is not present in prototype chain of inlineCache's type
  3200. bool isObjectPresentOnPrototypeChain =
  3201. Js::JavascriptOperators::MapObjectAndPrototypesUntil<true>(inlineCache->GetType()->GetPrototype(), [=](Js::RecyclableObject* prototype)
  3202. {
  3203. return prototype == object;
  3204. });
  3205. if (isObjectPresentOnPrototypeChain) {
  3206. return true;
  3207. }
  3208. }
  3209. }
  3210. NEXT_SLISTBASE_ENTRY;
  3211. return false;
  3212. });
  3213. }
  3214. // Verifies if object is registered in any storeField InlineCache
  3215. bool
  3216. ThreadContext::IsObjectRegisteredInStoreFieldInlineCaches(Js::DynamicObject * object)
  3217. {
  3218. return storeFieldInlineCacheByPropId.MapUntil([object](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  3219. {
  3220. FOREACH_SLISTBASE_ENTRY(Js::InlineCache*, inlineCache, inlineCacheList)
  3221. {
  3222. if (inlineCache != nullptr && !inlineCache->IsEmpty())
  3223. {
  3224. // Verify this object is not present in prototype chain of inlineCache's type
  3225. bool isObjectPresentOnPrototypeChain =
  3226. Js::JavascriptOperators::MapObjectAndPrototypesUntil<true>(inlineCache->GetType()->GetPrototype(), [=](Js::RecyclableObject* prototype)
  3227. {
  3228. return prototype == object;
  3229. });
  3230. if (isObjectPresentOnPrototypeChain) {
  3231. return true;
  3232. }
  3233. }
  3234. }
  3235. NEXT_SLISTBASE_ENTRY;
  3236. return false;
  3237. });
  3238. }
  3239. #endif
  3240. bool
  3241. ThreadContext::AreAllProtoInlineCachesInvalidated()
  3242. {
  3243. return protoInlineCacheByPropId.Count() == 0;
  3244. }
  3245. void
  3246. ThreadContext::InvalidateAllStoreFieldInlineCaches()
  3247. {
  3248. storeFieldInlineCacheByPropId.Map([this](Js::PropertyId propertyId, InlineCacheList* inlineCacheList)
  3249. {
  3250. InvalidateAndDeleteInlineCacheList(inlineCacheList);
  3251. });
  3252. storeFieldInlineCacheByPropId.Reset();
  3253. }
  3254. bool
  3255. ThreadContext::AreAllStoreFieldInlineCachesInvalidated()
  3256. {
  3257. return storeFieldInlineCacheByPropId.Count() == 0;
  3258. }
  3259. #if DBG
  3260. bool
  3261. ThreadContext::IsIsInstInlineCacheRegistered(Js::IsInstInlineCache * inlineCache, Js::Var function)
  3262. {
  3263. Assert(inlineCache != nullptr);
  3264. Assert(function != nullptr);
  3265. Js::IsInstInlineCache* firstInlineCache;
  3266. if (this->isInstInlineCacheByFunction.TryGetValue(function, &firstInlineCache))
  3267. {
  3268. return IsIsInstInlineCacheInList(inlineCache, firstInlineCache);
  3269. }
  3270. else
  3271. {
  3272. return false;
  3273. }
  3274. }
  3275. #endif
  3276. void
  3277. ThreadContext::RegisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function)
  3278. {
  3279. Assert(function != nullptr);
  3280. Assert(inlineCache != nullptr);
  3281. // We should never cross-register or re-register a cache that is already on some invalidation list (for its function or some other function).
  3282. // Every cache must be first cleared and unregistered before being registered again.
  3283. AssertMsg(inlineCache->function == nullptr, "We should only register instance-of caches that have not yet been populated.");
  3284. Js::IsInstInlineCache** inlineCacheRef = nullptr;
  3285. if (this->isInstInlineCacheByFunction.TryGetReference(function, &inlineCacheRef))
  3286. {
  3287. AssertMsg(!IsIsInstInlineCacheInList(inlineCache, *inlineCacheRef), "Why are we registering a cache that is already registered?");
  3288. inlineCache->next = *inlineCacheRef;
  3289. *inlineCacheRef = inlineCache;
  3290. }
  3291. else
  3292. {
  3293. inlineCache->next = nullptr;
  3294. this->isInstInlineCacheByFunction.Add(function, inlineCache);
  3295. }
  3296. }
  3297. void
  3298. ThreadContext::UnregisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function)
  3299. {
  3300. Assert(inlineCache != nullptr);
  3301. Js::IsInstInlineCache** inlineCacheRef = nullptr;
  3302. if (this->isInstInlineCacheByFunction.TryGetReference(function, &inlineCacheRef))
  3303. {
  3304. Assert(*inlineCacheRef != nullptr);
  3305. if (inlineCache == *inlineCacheRef)
  3306. {
  3307. *inlineCacheRef = (*inlineCacheRef)->next;
  3308. if (*inlineCacheRef == nullptr)
  3309. {
  3310. this->isInstInlineCacheByFunction.Remove(function);
  3311. }
  3312. }
  3313. else
  3314. {
  3315. Js::IsInstInlineCache * prevInlineCache;
  3316. Js::IsInstInlineCache * curInlineCache;
  3317. for (prevInlineCache = *inlineCacheRef, curInlineCache = (*inlineCacheRef)->next; curInlineCache != nullptr;
  3318. prevInlineCache = curInlineCache, curInlineCache = curInlineCache->next)
  3319. {
  3320. if (curInlineCache == inlineCache)
  3321. {
  3322. prevInlineCache->next = curInlineCache->next;
  3323. return;
  3324. }
  3325. }
  3326. AssertMsg(false, "Why are we unregistering a cache that is not registered?");
  3327. }
  3328. }
  3329. }
  3330. void
  3331. ThreadContext::InvalidateIsInstInlineCacheList(Js::IsInstInlineCache* inlineCacheList)
  3332. {
  3333. Assert(inlineCacheList != nullptr);
  3334. Js::IsInstInlineCache* curInlineCache;
  3335. Js::IsInstInlineCache* nextInlineCache;
  3336. for (curInlineCache = inlineCacheList; curInlineCache != nullptr; curInlineCache = nextInlineCache)
  3337. {
  3338. if (PHASE_VERBOSE_TRACE1(Js::TraceInlineCacheInvalidationPhase))
  3339. {
  3340. Output::Print(_u("InlineCacheInvalidation: invalidating instanceof cache 0x%p\n"), curInlineCache);
  3341. Output::Flush();
  3342. }
  3343. // Stash away the next cache before we zero out the current one (including its next pointer).
  3344. nextInlineCache = curInlineCache->next;
  3345. // Clear the current cache to invalidate it.
  3346. memset(curInlineCache, 0, sizeof(Js::IsInstInlineCache));
  3347. }
  3348. }
  3349. void
  3350. ThreadContext::InvalidateIsInstInlineCachesForFunction(Js::Var function)
  3351. {
  3352. Js::IsInstInlineCache* inlineCacheList;
  3353. if (this->isInstInlineCacheByFunction.TryGetValueAndRemove(function, &inlineCacheList))
  3354. {
  3355. InvalidateIsInstInlineCacheList(inlineCacheList);
  3356. }
  3357. }
  3358. void
  3359. ThreadContext::InvalidateAllIsInstInlineCaches()
  3360. {
  3361. isInstInlineCacheByFunction.Map([this](const Js::Var function, Js::IsInstInlineCache* inlineCacheList)
  3362. {
  3363. InvalidateIsInstInlineCacheList(inlineCacheList);
  3364. });
  3365. isInstInlineCacheByFunction.Clear();
  3366. }
  3367. bool
  3368. ThreadContext::AreAllIsInstInlineCachesInvalidated() const
  3369. {
  3370. return isInstInlineCacheByFunction.Count() == 0;
  3371. }
  3372. #if DBG
  3373. bool
  3374. ThreadContext::IsIsInstInlineCacheInList(const Js::IsInstInlineCache* inlineCache, const Js::IsInstInlineCache* inlineCacheList)
  3375. {
  3376. Assert(inlineCache != nullptr);
  3377. Assert(inlineCacheList != nullptr);
  3378. for (const Js::IsInstInlineCache* curInlineCache = inlineCacheList; curInlineCache != nullptr; curInlineCache = curInlineCache->next)
  3379. {
  3380. if (curInlineCache == inlineCache)
  3381. {
  3382. return true;
  3383. }
  3384. }
  3385. return false;
  3386. }
  3387. #endif
  3388. void ThreadContext::RegisterTypeWithProtoPropertyCache(const Js::PropertyId propertyId, Js::Type *const type)
  3389. {
  3390. Assert(propertyId != Js::Constants::NoProperty);
  3391. Assert(IsActivePropertyId(propertyId));
  3392. Assert(type);
  3393. PropertyIdToTypeHashSetDictionary &typesWithProtoPropertyCache = recyclableData->typesWithProtoPropertyCache;
  3394. TypeHashSet *typeHashSet = nullptr;
  3395. if(!typesWithProtoPropertyCache.TryGetValue(propertyId, &typeHashSet))
  3396. {
  3397. typeHashSet = RecyclerNew(recycler, TypeHashSet, recycler);
  3398. typesWithProtoPropertyCache.Add(propertyId, typeHashSet);
  3399. }
  3400. typeHashSet->Item(type, false);
  3401. }
  3402. void ThreadContext::InvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId)
  3403. {
  3404. Assert(propertyId != Js::Constants::NoProperty);
  3405. Assert(IsActivePropertyId(propertyId));
  3406. InternalInvalidateProtoTypePropertyCaches(propertyId);
  3407. }
  3408. void ThreadContext::InternalInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId)
  3409. {
  3410. // Get the hash set of registered types associated with the property ID, invalidate each type in the hash set, and
  3411. // remove the property ID and its hash set from the map
  3412. PropertyIdToTypeHashSetDictionary &typesWithProtoPropertyCache = recyclableData->typesWithProtoPropertyCache;
  3413. TypeHashSet *typeHashSet = nullptr;
  3414. if(typesWithProtoPropertyCache.Count() != 0 && typesWithProtoPropertyCache.TryGetValueAndRemove(propertyId, &typeHashSet))
  3415. {
  3416. DoInvalidateProtoTypePropertyCaches(propertyId, typeHashSet);
  3417. }
  3418. }
  3419. void ThreadContext::InvalidateAllProtoTypePropertyCaches()
  3420. {
  3421. PropertyIdToTypeHashSetDictionary &typesWithProtoPropertyCache = recyclableData->typesWithProtoPropertyCache;
  3422. if (typesWithProtoPropertyCache.Count() > 0)
  3423. {
  3424. typesWithProtoPropertyCache.Map([this](Js::PropertyId propertyId, TypeHashSet * typeHashSet)
  3425. {
  3426. DoInvalidateProtoTypePropertyCaches(propertyId, typeHashSet);
  3427. });
  3428. typesWithProtoPropertyCache.Clear();
  3429. }
  3430. }
  3431. void ThreadContext::DoInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId, TypeHashSet *const typeHashSet)
  3432. {
  3433. Assert(propertyId != Js::Constants::NoProperty);
  3434. Assert(typeHashSet);
  3435. typeHashSet->Map(
  3436. [propertyId](Js::Type *const type, const bool unused, const RecyclerWeakReference<Js::Type>*)
  3437. {
  3438. type->GetPropertyCache()->ClearIfPropertyIsOnAPrototype(propertyId);
  3439. });
  3440. }
  3441. Js::ScriptContext **
  3442. ThreadContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext(Js::ScriptContext * scriptContext)
  3443. {
  3444. return prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext.PrependNode(&prototypeChainEnsuredToHaveOnlyWritableDataPropertiesAllocator, scriptContext);
  3445. }
  3446. void
  3447. ThreadContext::UnregisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext(Js::ScriptContext ** scriptContext)
  3448. {
  3449. prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext.RemoveElement(&prototypeChainEnsuredToHaveOnlyWritableDataPropertiesAllocator, scriptContext);
  3450. }
  3451. void
  3452. ThreadContext::ClearPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesCaches()
  3453. {
  3454. bool hasItem = false;
  3455. FOREACH_DLISTBASE_ENTRY(Js::ScriptContext *, scriptContext, &prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext)
  3456. {
  3457. scriptContext->ClearPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesCaches();
  3458. hasItem = true;
  3459. }
  3460. NEXT_DLISTBASE_ENTRY;
  3461. if (!hasItem)
  3462. {
  3463. return;
  3464. }
  3465. prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext.Reset();
  3466. prototypeChainEnsuredToHaveOnlyWritableDataPropertiesAllocator.Reset();
  3467. }
  3468. BOOL ThreadContext::HasPreviousHostScriptContext()
  3469. {
  3470. return hostScriptContextStack->Count() != 0;
  3471. }
  3472. HostScriptContext* ThreadContext::GetPreviousHostScriptContext()
  3473. {
  3474. return hostScriptContextStack->Peek();
  3475. }
  3476. void ThreadContext::PushHostScriptContext(HostScriptContext* topProvider)
  3477. {
  3478. // script engine can be created coming from GetDispID, so push/pop can be
  3479. // happening after the first round of enterscript as well. we might need to
  3480. // revisit the whole callRootLevel but probably not now.
  3481. // Assert(HasPreviousHostScriptContext() || callRootLevel == 0);
  3482. hostScriptContextStack->Push(topProvider);
  3483. }
  3484. HostScriptContext* ThreadContext::PopHostScriptContext()
  3485. {
  3486. return hostScriptContextStack->Pop();
  3487. // script engine can be created coming from GetDispID, so push/pop can be
  3488. // happening after the first round of enterscript as well. we might need to
  3489. // revisit the whole callRootLevel but probably not now.
  3490. // Assert(HasPreviousHostScriptContext() || callRootLevel == 0);
  3491. }
  3492. #if DBG || defined(PROFILE_EXEC)
  3493. bool
  3494. ThreadContext::AsyncHostOperationStart(void * suspendRecord)
  3495. {
  3496. bool wasInAsync = false;
  3497. Assert(!this->IsScriptActive());
  3498. Js::ScriptEntryExitRecord * lastRecord = this->entryExitRecord;
  3499. if (lastRecord != NULL)
  3500. {
  3501. if (!lastRecord->leaveForHost)
  3502. {
  3503. #if DBG
  3504. wasInAsync = !!lastRecord->leaveForAsyncHostOperation;
  3505. lastRecord->leaveForAsyncHostOperation = true;
  3506. #endif
  3507. #ifdef PROFILE_EXEC
  3508. lastRecord->scriptContext->ProfileSuspend(Js::RunPhase, (Js::Profiler::SuspendRecord *)suspendRecord);
  3509. #endif
  3510. }
  3511. else
  3512. {
  3513. Assert(!lastRecord->leaveForAsyncHostOperation);
  3514. }
  3515. }
  3516. return wasInAsync;
  3517. }
  3518. void
  3519. ThreadContext::AsyncHostOperationEnd(bool wasInAsync, void * suspendRecord)
  3520. {
  3521. Assert(!this->IsScriptActive());
  3522. Js::ScriptEntryExitRecord * lastRecord = this->entryExitRecord;
  3523. if (lastRecord != NULL)
  3524. {
  3525. if (!lastRecord->leaveForHost)
  3526. {
  3527. Assert(lastRecord->leaveForAsyncHostOperation);
  3528. #if DBG
  3529. lastRecord->leaveForAsyncHostOperation = wasInAsync;
  3530. #endif
  3531. #ifdef PROFILE_EXEC
  3532. lastRecord->scriptContext->ProfileResume((Js::Profiler::SuspendRecord *)suspendRecord);
  3533. #endif
  3534. }
  3535. else
  3536. {
  3537. Assert(!lastRecord->leaveForAsyncHostOperation);
  3538. Assert(!wasInAsync);
  3539. }
  3540. }
  3541. }
  3542. #endif
  3543. #ifdef RECYCLER_DUMP_OBJECT_GRAPH
  3544. void DumpRecyclerObjectGraph()
  3545. {
  3546. ThreadContext * threadContext = ThreadContext::GetContextForCurrentThread();
  3547. if (threadContext == nullptr)
  3548. {
  3549. Output::Print(_u("No thread context"));
  3550. }
  3551. threadContext->GetRecycler()->DumpObjectGraph();
  3552. }
  3553. #endif
  3554. #if ENABLE_NATIVE_CODEGEN
  3555. bool ThreadContext::IsNativeAddressHelper(void * pCodeAddr, Js::ScriptContext* currentScriptContext)
  3556. {
  3557. bool isNativeAddr = false;
  3558. if (currentScriptContext && currentScriptContext->GetJitFuncRangeCache() != nullptr)
  3559. {
  3560. isNativeAddr = currentScriptContext->GetJitFuncRangeCache()->IsNativeAddr(pCodeAddr);
  3561. }
  3562. for (Js::ScriptContext *scriptContext = scriptContextList; scriptContext && !isNativeAddr; scriptContext = scriptContext->next)
  3563. {
  3564. if (scriptContext == currentScriptContext || scriptContext->GetJitFuncRangeCache() == nullptr)
  3565. {
  3566. continue;
  3567. }
  3568. isNativeAddr = scriptContext->GetJitFuncRangeCache()->IsNativeAddr(pCodeAddr);
  3569. }
  3570. return isNativeAddr;
  3571. }
  3572. BOOL ThreadContext::IsNativeAddress(void * pCodeAddr, Js::ScriptContext* currentScriptContext)
  3573. {
  3574. #if ENABLE_OOP_NATIVE_CODEGEN
  3575. if (JITManager::GetJITManager()->IsOOPJITEnabled())
  3576. {
  3577. if (PreReservedVirtualAllocWrapper::IsInRange((void*)m_prereservedRegionAddr, pCodeAddr))
  3578. {
  3579. return true;
  3580. }
  3581. if (IsAllJITCodeInPreReservedRegion())
  3582. {
  3583. return false;
  3584. }
  3585. if (AutoSystemInfo::IsJscriptModulePointer(pCodeAddr))
  3586. {
  3587. return false;
  3588. }
  3589. #if DBG
  3590. boolean result;
  3591. HRESULT hr = JITManager::GetJITManager()->IsNativeAddr(this->m_remoteThreadContextInfo, (intptr_t)pCodeAddr, &result);
  3592. #endif
  3593. bool isNativeAddr = IsNativeAddressHelper(pCodeAddr, currentScriptContext);
  3594. #if DBG
  3595. Assert(FAILED(hr) || result == (isNativeAddr? TRUE:FALSE));
  3596. #endif
  3597. return isNativeAddr;
  3598. }
  3599. else
  3600. #endif
  3601. {
  3602. PreReservedVirtualAllocWrapper *preReservedVirtualAllocWrapper = this->GetPreReservedVirtualAllocator();
  3603. if (preReservedVirtualAllocWrapper->IsInRange(pCodeAddr))
  3604. {
  3605. return TRUE;
  3606. }
  3607. if (!this->IsAllJITCodeInPreReservedRegion())
  3608. {
  3609. #if DBG
  3610. AutoCriticalSection autoLock(&this->codePageAllocators.cs);
  3611. #endif
  3612. bool isNativeAddr = IsNativeAddressHelper(pCodeAddr, currentScriptContext);
  3613. #if DBG
  3614. Assert(this->codePageAllocators.IsInNonPreReservedPageAllocator(pCodeAddr) == isNativeAddr);
  3615. #endif
  3616. return isNativeAddr;
  3617. }
  3618. return FALSE;
  3619. }
  3620. }
  3621. #endif
  3622. #if ENABLE_PROFILE_INFO
  3623. void ThreadContext::EnsureSourceProfileManagersByUrlMap()
  3624. {
  3625. if(this->recyclableData->sourceProfileManagersByUrl == nullptr)
  3626. {
  3627. this->EnsureRecycler();
  3628. this->recyclableData->sourceProfileManagersByUrl = RecyclerNew(GetRecycler(), SourceProfileManagersByUrlMap, GetRecycler());
  3629. }
  3630. }
  3631. //
  3632. // Returns the cache profile manager for the URL and hash combination for a particular dynamic script. There is a ref count added for every script context
  3633. // that references the shared profile manager info.
  3634. //
  3635. Js::SourceDynamicProfileManager* ThreadContext::GetSourceDynamicProfileManager(_In_z_ const WCHAR* url, _In_ uint hash, _Inout_ bool* addRef)
  3636. {
  3637. EnsureSourceProfileManagersByUrlMap();
  3638. Js::SourceDynamicProfileManager* profileManager = nullptr;
  3639. SourceDynamicProfileManagerCache* managerCache = nullptr;
  3640. bool newCache = false;
  3641. if(!this->recyclableData->sourceProfileManagersByUrl->TryGetValue(url, &managerCache))
  3642. {
  3643. if(this->recyclableData->sourceProfileManagersByUrl->Count() >= INMEMORY_CACHE_MAX_URL)
  3644. {
  3645. return nullptr;
  3646. }
  3647. managerCache = RecyclerNewZ(this->GetRecycler(), SourceDynamicProfileManagerCache);
  3648. newCache = true;
  3649. }
  3650. bool createProfileManager = false;
  3651. if(!managerCache->sourceProfileManagerMap)
  3652. {
  3653. managerCache->sourceProfileManagerMap = RecyclerNew(this->GetRecycler(), SourceDynamicProfileManagerMap, this->GetRecycler());
  3654. createProfileManager = true;
  3655. }
  3656. else
  3657. {
  3658. createProfileManager = !managerCache->sourceProfileManagerMap->TryGetValue(hash, &profileManager);
  3659. }
  3660. if(createProfileManager)
  3661. {
  3662. if(managerCache->sourceProfileManagerMap->Count() < INMEMORY_CACHE_MAX_PROFILE_MANAGER)
  3663. {
  3664. profileManager = RecyclerNewZ(this->GetRecycler(), Js::SourceDynamicProfileManager, this->GetRecycler());
  3665. managerCache->sourceProfileManagerMap->Add(hash, profileManager);
  3666. }
  3667. }
  3668. else
  3669. {
  3670. profileManager->Reuse();
  3671. }
  3672. if(!*addRef)
  3673. {
  3674. managerCache->AddRef();
  3675. *addRef = true;
  3676. OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, _u("Addref dynamic source profile manger - Url: %s\n"), url);
  3677. }
  3678. if (newCache)
  3679. {
  3680. // Let's make a copy of the URL because there is no guarantee this URL will remain alive in the future.
  3681. size_t lengthInChars = wcslen(url) + 1;
  3682. WCHAR* urlCopy = RecyclerNewArrayLeaf(GetRecycler(), WCHAR, lengthInChars);
  3683. js_memcpy_s(urlCopy, lengthInChars * sizeof(WCHAR), url, lengthInChars * sizeof(WCHAR));
  3684. this->recyclableData->sourceProfileManagersByUrl->Add(urlCopy, managerCache);
  3685. }
  3686. return profileManager;
  3687. }
  3688. //
  3689. // Decrement the ref count for this URL and cleanup the corresponding record if there are no other references to it.
  3690. //
  3691. uint ThreadContext::ReleaseSourceDynamicProfileManagers(const WCHAR* url)
  3692. {
  3693. // If we've already freed the recyclable data, we're shutting down the thread context so skip clean up
  3694. if (this->recyclableData == nullptr) return 0;
  3695. SourceDynamicProfileManagerCache* managerCache = this->recyclableData->sourceProfileManagersByUrl->Lookup(url, nullptr);
  3696. uint refCount = 0;
  3697. if(managerCache) // manager cache may be null we exceeded -INMEMORY_CACHE_MAX_URL
  3698. {
  3699. refCount = managerCache->Release();
  3700. OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, _u("Release dynamic source profile manger %d Url: %s\n"), refCount, url);
  3701. Output::Flush();
  3702. if(refCount == 0)
  3703. {
  3704. this->recyclableData->sourceProfileManagersByUrl->Remove(url);
  3705. }
  3706. }
  3707. return refCount;
  3708. }
  3709. #endif
  3710. void ThreadContext::EnsureSymbolRegistrationMap()
  3711. {
  3712. if (this->recyclableData->symbolRegistrationMap == nullptr)
  3713. {
  3714. this->EnsureRecycler();
  3715. this->recyclableData->symbolRegistrationMap = RecyclerNew(GetRecycler(), SymbolRegistrationMap, GetRecycler());
  3716. }
  3717. }
  3718. const Js::PropertyRecord* ThreadContext::GetSymbolFromRegistrationMap(const char16* stringKey, charcount_t stringLength)
  3719. {
  3720. this->EnsureSymbolRegistrationMap();
  3721. Js::HashedCharacterBuffer<char16> propertyName = Js::HashedCharacterBuffer<char16>(stringKey, stringLength);
  3722. return this->recyclableData->symbolRegistrationMap->LookupWithKey(&propertyName, nullptr);
  3723. }
  3724. const Js::PropertyRecord* ThreadContext::AddSymbolToRegistrationMap(const char16* stringKey, charcount_t stringLength)
  3725. {
  3726. this->EnsureSymbolRegistrationMap();
  3727. const Js::PropertyRecord* propertyRecord = this->UncheckedAddPropertyId(stringKey, stringLength, /*bind*/false, /*isSymbol*/true);
  3728. Assert(propertyRecord);
  3729. // We need to support null characters in the Symbol names. For e.g. "A\0Z" is a valid symbol name and is different than "A\0Y".
  3730. // However, as the key contains a null character we need to hash the symbol name past the null character. The default implementation terminates
  3731. // at the null character, so we use the Js::HashedCharacterBuffer as key. We allocate the key in the recycler memory as it needs to be around
  3732. // for the lifetime of the map.
  3733. Js::HashedCharacterBuffer<char16> * propertyName = RecyclerNew(GetRecycler(), Js::HashedCharacterBuffer<char16>, propertyRecord->GetBuffer(), propertyRecord->GetLength());
  3734. this->recyclableData->symbolRegistrationMap->Add(propertyName, propertyRecord);
  3735. return propertyRecord;
  3736. }
  3737. #if ENABLE_TTD
  3738. JsUtil::BaseDictionary<Js::HashedCharacterBuffer<char16>*, const Js::PropertyRecord*, Recycler, PowerOf2SizePolicy, Js::PropertyRecordStringHashComparer>* ThreadContext::GetSymbolRegistrationMap_TTD()
  3739. {
  3740. //This adds a little memory but makes simplifies other logic -- maybe revise later
  3741. this->EnsureSymbolRegistrationMap();
  3742. return this->recyclableData->symbolRegistrationMap;
  3743. }
  3744. #endif
  3745. void ThreadContext::ClearImplicitCallFlags()
  3746. {
  3747. SetImplicitCallFlags(Js::ImplicitCall_None);
  3748. }
  3749. void ThreadContext::ClearImplicitCallFlags(Js::ImplicitCallFlags flags)
  3750. {
  3751. Assert((flags & Js::ImplicitCall_None) == 0);
  3752. SetImplicitCallFlags((Js::ImplicitCallFlags)(implicitCallFlags & ~flags));
  3753. }
  3754. void ThreadContext::CheckAndResetImplicitCallAccessorFlag()
  3755. {
  3756. Js::ImplicitCallFlags accessorCallFlag = (Js::ImplicitCallFlags)(Js::ImplicitCall_Accessor & ~Js::ImplicitCall_None);
  3757. if ((GetImplicitCallFlags() & accessorCallFlag) != 0)
  3758. {
  3759. ClearImplicitCallFlags(accessorCallFlag);
  3760. AddImplicitCallFlags(Js::ImplicitCall_NonProfiledAccessor);
  3761. }
  3762. }
  3763. bool ThreadContext::HasNoSideEffect(Js::RecyclableObject * function) const
  3764. {
  3765. Js::FunctionInfo::Attributes attributes = Js::FunctionInfo::GetAttributes(function);
  3766. return this->HasNoSideEffect(function, attributes);
  3767. }
  3768. bool ThreadContext::HasNoSideEffect(Js::RecyclableObject * function, Js::FunctionInfo::Attributes attributes) const
  3769. {
  3770. if (((attributes & Js::FunctionInfo::CanBeHoisted) != 0)
  3771. || ((attributes & Js::FunctionInfo::HasNoSideEffect) != 0 && !IsDisableImplicitException()))
  3772. {
  3773. Assert((attributes & Js::FunctionInfo::HasNoSideEffect) != 0);
  3774. return true;
  3775. }
  3776. return false;
  3777. }
  3778. bool
  3779. ThreadContext::RecordImplicitException()
  3780. {
  3781. // Record the exception in the implicit call flag
  3782. AddImplicitCallFlags(Js::ImplicitCall_Exception);
  3783. if (IsDisableImplicitException())
  3784. {
  3785. // Indicate that we shouldn't throw if ImplicitExceptions have been disabled
  3786. return false;
  3787. }
  3788. // Disabling implicit exception when disabling implicit calls can result in valid exceptions not being thrown.
  3789. // Instead we tell not to throw only if an implicit call happened and they are disabled. This is to cover the case
  3790. // of an exception being thrown because an implicit call not executed left the execution in a bad state.
  3791. // Since there is an implicit call, we expect to bailout and handle this operation in the interpreter instead.
  3792. bool hasImplicitCallHappened = IsDisableImplicitCall() && (GetImplicitCallFlags() & ~Js::ImplicitCall_Exception);
  3793. return !hasImplicitCallHappened;
  3794. }
  3795. void ThreadContext::SetThreadServiceWrapper(ThreadServiceWrapper* inThreadServiceWrapper)
  3796. {
  3797. AssertMsg(threadServiceWrapper == NULL || inThreadServiceWrapper == NULL, "double set ThreadServiceWrapper");
  3798. threadServiceWrapper = inThreadServiceWrapper;
  3799. }
  3800. ThreadServiceWrapper* ThreadContext::GetThreadServiceWrapper()
  3801. {
  3802. return threadServiceWrapper;
  3803. }
  3804. uint ThreadContext::GetRandomNumber()
  3805. {
  3806. #ifdef ENABLE_CUSTOM_ENTROPY
  3807. return (uint)GetEntropy().GetRand();
  3808. #else
  3809. uint randomNumber = 0;
  3810. errno_t e = rand_s(&randomNumber);
  3811. Assert(e == 0);
  3812. return randomNumber;
  3813. #endif
  3814. }
  3815. #if defined(ENABLE_JS_ETW) && defined(NTBUILD)
  3816. void ThreadContext::EtwLogPropertyIdList()
  3817. {
  3818. propertyMap->Map([&](const Js::PropertyRecord* propertyRecord){
  3819. EventWriteJSCRIPT_HOSTING_PROPERTYID_LIST(propertyRecord, propertyRecord->GetBuffer());
  3820. });
  3821. }
  3822. #endif
  3823. #ifdef ENABLE_PROJECTION
  3824. void ThreadContext::AddExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache)
  3825. {
  3826. this->externalWeakReferenceCacheList.Prepend(&HeapAllocator::Instance, externalWeakReferenceCache);
  3827. }
  3828. void ThreadContext::RemoveExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache)
  3829. {
  3830. Assert(!externalWeakReferenceCacheList.Empty());
  3831. this->externalWeakReferenceCacheList.Remove(&HeapAllocator::Instance, externalWeakReferenceCache);
  3832. }
  3833. void ThreadContext::MarkExternalWeakReferencedObjects(bool inPartialCollect)
  3834. {
  3835. SListBase<ExternalWeakReferenceCache *, HeapAllocator>::Iterator iteratorWeakRefCache(&this->externalWeakReferenceCacheList);
  3836. while (iteratorWeakRefCache.Next())
  3837. {
  3838. iteratorWeakRefCache.Data()->MarkNow(recycler, inPartialCollect);
  3839. }
  3840. }
  3841. void ThreadContext::ResolveExternalWeakReferencedObjects()
  3842. {
  3843. SListBase<ExternalWeakReferenceCache *, HeapAllocator>::Iterator iteratorWeakRefCache(&this->externalWeakReferenceCacheList);
  3844. while (iteratorWeakRefCache.Next())
  3845. {
  3846. iteratorWeakRefCache.Data()->ResolveNow(recycler);
  3847. }
  3848. }
  3849. #if DBG_DUMP
  3850. void ThreadContext::RegisterProjectionMemoryInformation(IProjectionContextMemoryInfo* projectionContextMemoryInfo)
  3851. {
  3852. Assert(this->projectionMemoryInformation == nullptr || this->projectionMemoryInformation == projectionContextMemoryInfo);
  3853. this->projectionMemoryInformation = projectionContextMemoryInfo;
  3854. }
  3855. void ThreadContext::DumpProjectionContextMemoryStats(LPCWSTR headerMsg, bool forceDetailed)
  3856. {
  3857. if (this->projectionMemoryInformation)
  3858. {
  3859. this->projectionMemoryInformation->DumpCurrentStats(headerMsg, forceDetailed);
  3860. }
  3861. }
  3862. IProjectionContextMemoryInfo* ThreadContext::GetProjectionContextMemoryInformation()
  3863. {
  3864. return this->projectionMemoryInformation;
  3865. }
  3866. #endif
  3867. #endif
  3868. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  3869. Js::Var ThreadContext::GetMemoryStat(Js::ScriptContext* scriptContext)
  3870. {
  3871. ScriptMemoryDumper dumper(scriptContext);
  3872. return dumper.Dump();
  3873. }
  3874. void ThreadContext::SetAutoProxyName(LPCWSTR objectName)
  3875. {
  3876. recyclableData->autoProxyName = objectName;
  3877. }
  3878. #endif
  3879. //
  3880. // Regex helpers
  3881. //
  3882. UnifiedRegex::StandardChars<uint8>* ThreadContext::GetStandardChars(__inout_opt uint8* dummy)
  3883. {
  3884. if (standardUTF8Chars == 0)
  3885. {
  3886. ArenaAllocator* allocator = GetThreadAlloc();
  3887. standardUTF8Chars = Anew(allocator, UnifiedRegex::UTF8StandardChars, allocator);
  3888. }
  3889. return standardUTF8Chars;
  3890. }
  3891. UnifiedRegex::StandardChars<char16>* ThreadContext::GetStandardChars(__inout_opt char16* dummy)
  3892. {
  3893. if (standardUnicodeChars == 0)
  3894. {
  3895. ArenaAllocator* allocator = GetThreadAlloc();
  3896. standardUnicodeChars = Anew(allocator, UnifiedRegex::UnicodeStandardChars, allocator);
  3897. }
  3898. return standardUnicodeChars;
  3899. }
  3900. void ThreadContext::CheckScriptInterrupt()
  3901. {
  3902. if (TestThreadContextFlag(ThreadContextFlagCanDisableExecution))
  3903. {
  3904. if (this->IsExecutionDisabled())
  3905. {
  3906. Assert(this->DoInterruptProbe());
  3907. throw Js::ScriptAbortException();
  3908. }
  3909. }
  3910. else
  3911. {
  3912. this->CheckInterruptPoll();
  3913. }
  3914. }
  3915. void ThreadContext::CheckInterruptPoll()
  3916. {
  3917. // Disable QC when implicit calls are disabled since the host can do anything before returning back, like servicing the
  3918. // message loop, which may in turn cause script code to be executed and implicit calls to be made
  3919. if (!IsDisableImplicitCall())
  3920. {
  3921. InterruptPoller *poller = this->interruptPoller;
  3922. if (poller)
  3923. {
  3924. poller->CheckInterruptPoll();
  3925. }
  3926. }
  3927. }
  3928. void *
  3929. ThreadContext::GetDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType)
  3930. {
  3931. void * data = nullptr;
  3932. return this->dynamicObjectEnumeratorCacheMap.TryGetValue(dynamicType, &data)? data : nullptr;
  3933. }
  3934. void
  3935. ThreadContext::AddDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType, void * cache)
  3936. {
  3937. this->dynamicObjectEnumeratorCacheMap.Item(dynamicType, cache);
  3938. }
  3939. InterruptPoller::InterruptPoller(ThreadContext *tc) :
  3940. threadContext(tc),
  3941. lastPollTick(0),
  3942. lastResetTick(0),
  3943. isDisabled(FALSE)
  3944. {
  3945. tc->SetInterruptPoller(this);
  3946. }
  3947. void InterruptPoller::CheckInterruptPoll()
  3948. {
  3949. if (!isDisabled)
  3950. {
  3951. Js::ScriptEntryExitRecord *entryExitRecord = this->threadContext->GetScriptEntryExit();
  3952. if (entryExitRecord)
  3953. {
  3954. Js::ScriptContext *scriptContext = entryExitRecord->scriptContext;
  3955. if (scriptContext)
  3956. {
  3957. this->TryInterruptPoll(scriptContext);
  3958. }
  3959. }
  3960. }
  3961. }
  3962. void InterruptPoller::GetStatementCount(ULONG *pluHi, ULONG *pluLo)
  3963. {
  3964. DWORD resetTick = this->lastResetTick;
  3965. DWORD pollTick = this->lastPollTick;
  3966. DWORD elapsed;
  3967. elapsed = pollTick - resetTick;
  3968. ULONGLONG statements = (ULONGLONG)elapsed * InterruptPoller::TicksToStatements;
  3969. *pluLo = (ULONG)statements;
  3970. *pluHi = (ULONG)(statements >> 32);
  3971. }
  3972. void ThreadContext::DisableExecution()
  3973. {
  3974. Assert(TestThreadContextFlag(ThreadContextFlagCanDisableExecution));
  3975. // Hammer the stack limit with a value that will cause script abort on the next stack probe.
  3976. this->SetStackLimitForCurrentThread(Js::Constants::StackLimitForScriptInterrupt);
  3977. return;
  3978. }
  3979. void ThreadContext::EnableExecution()
  3980. {
  3981. Assert(this->GetStackProber());
  3982. // Restore the normal stack limit.
  3983. this->SetStackLimitForCurrentThread(this->GetStackProber()->GetScriptStackLimit());
  3984. // It's possible that the host disabled execution after the script threw an exception
  3985. // of it's own, so we shouldn't clear that. Only exceptions for script termination
  3986. // should be cleared.
  3987. if (GetRecordedException() == GetPendingTerminatedErrorObject())
  3988. {
  3989. SetRecordedException(NULL);
  3990. }
  3991. }
  3992. bool ThreadContext::TestThreadContextFlag(ThreadContextFlags contextFlag) const
  3993. {
  3994. return (this->threadContextFlags & contextFlag) != 0;
  3995. }
  3996. void ThreadContext::SetThreadContextFlag(ThreadContextFlags contextFlag)
  3997. {
  3998. this->threadContextFlags = (ThreadContextFlags)(this->threadContextFlags | contextFlag);
  3999. }
  4000. void ThreadContext::ClearThreadContextFlag(ThreadContextFlags contextFlag)
  4001. {
  4002. this->threadContextFlags = (ThreadContextFlags)(this->threadContextFlags & ~contextFlag);
  4003. }
  4004. #ifdef ENABLE_GLOBALIZATION
  4005. Js::DelayLoadWinRtString * ThreadContext::GetWinRTStringLibrary()
  4006. {
  4007. delayLoadWinRtString.EnsureFromSystemDirOnly();
  4008. return &delayLoadWinRtString;
  4009. }
  4010. #ifdef ENABLE_PROJECTION
  4011. Js::DelayLoadWinRtError * ThreadContext::GetWinRTErrorLibrary()
  4012. {
  4013. delayLoadWinRtError.EnsureFromSystemDirOnly();
  4014. return &delayLoadWinRtError;
  4015. }
  4016. Js::DelayLoadWinRtTypeResolution* ThreadContext::GetWinRTTypeResolutionLibrary()
  4017. {
  4018. delayLoadWinRtTypeResolution.EnsureFromSystemDirOnly();
  4019. return &delayLoadWinRtTypeResolution;
  4020. }
  4021. Js::DelayLoadWinRtRoParameterizedIID* ThreadContext::GetWinRTRoParameterizedIIDLibrary()
  4022. {
  4023. delayLoadWinRtRoParameterizedIID.EnsureFromSystemDirOnly();
  4024. return &delayLoadWinRtRoParameterizedIID;
  4025. }
  4026. #endif
  4027. #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_ES6_CHAR_CLASSIFIER)
  4028. #ifdef INTL_WINGLOB
  4029. Js::WindowsGlobalizationAdapter* ThreadContext::GetWindowsGlobalizationAdapter()
  4030. {
  4031. return &windowsGlobalizationAdapter;
  4032. }
  4033. Js::DelayLoadWindowsGlobalization* ThreadContext::GetWindowsGlobalizationLibrary()
  4034. {
  4035. delayLoadWindowsGlobalizationLibrary.Ensure(this->GetWinRTStringLibrary());
  4036. return &delayLoadWindowsGlobalizationLibrary;
  4037. }
  4038. #endif // INTL_WINGLOB
  4039. #endif
  4040. #ifdef ENABLE_FOUNDATION_OBJECT
  4041. Js::WindowsFoundationAdapter* ThreadContext::GetWindowsFoundationAdapter()
  4042. {
  4043. return &windowsFoundationAdapter;
  4044. }
  4045. Js::DelayLoadWinRtFoundation* ThreadContext::GetWinRtFoundationLibrary()
  4046. {
  4047. delayLoadWinRtFoundationLibrary.EnsureFromSystemDirOnly();
  4048. return &delayLoadWinRtFoundationLibrary;
  4049. }
  4050. #endif
  4051. #endif // ENABLE_GLOBALIZATION
  4052. // Despite the name, callers expect this to return the highest propid + 1.
  4053. uint ThreadContext::GetHighestPropertyNameIndex() const
  4054. {
  4055. return propertyMap->GetLastIndex() + 1 + Js::InternalPropertyIds::Count;
  4056. }
  4057. #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
  4058. void ThreadContext::ReportAndCheckLeaksOnProcessDetach()
  4059. {
  4060. bool needReportOrCheck = false;
  4061. #ifdef LEAK_REPORT
  4062. needReportOrCheck = needReportOrCheck || Js::Configuration::Global.flags.IsEnabled(Js::LeakReportFlag);
  4063. #endif
  4064. #ifdef CHECK_MEMORY_LEAK
  4065. needReportOrCheck = needReportOrCheck ||
  4066. (Js::Configuration::Global.flags.CheckMemoryLeak && MemoryLeakCheck::IsEnableOutput());
  4067. #endif
  4068. if (!needReportOrCheck)
  4069. {
  4070. return;
  4071. }
  4072. // Report leaks even if this is a force termination and we have not clean up the thread
  4073. // This is call during process detach. No one should be creating new thread context.
  4074. // So don't need to take the lock
  4075. ThreadContext * current = GetThreadContextList();
  4076. while (current)
  4077. {
  4078. #if DBG
  4079. current->pageAllocator.ClearConcurrentThreadId();
  4080. #endif
  4081. Recycler * recycler = current->GetRecycler();
  4082. #ifdef LEAK_REPORT
  4083. if (Js::Configuration::Global.flags.IsEnabled(Js::LeakReportFlag))
  4084. {
  4085. AUTO_LEAK_REPORT_SECTION(Js::Configuration::Global.flags, _u("Thread Context (%p): Process Termination (TID: %d)"), current, current->threadId);
  4086. LeakReport::DumpUrl(current->threadId);
  4087. // Heuristically figure out which one is the root tracker script engine
  4088. // and force close on it
  4089. if (current->rootTrackerScriptContext != nullptr)
  4090. {
  4091. current->rootTrackerScriptContext->Close(false);
  4092. }
  4093. recycler->ReportLeaksOnProcessDetach();
  4094. }
  4095. #endif
  4096. #ifdef CHECK_MEMORY_LEAK
  4097. recycler->CheckLeaksOnProcessDetach(_u("Process Termination"));
  4098. #endif
  4099. current = current->Next();
  4100. }
  4101. }
  4102. #endif
  4103. #ifdef LEAK_REPORT
  4104. void
  4105. ThreadContext::SetRootTrackerScriptContext(Js::ScriptContext * scriptContext)
  4106. {
  4107. Assert(this->rootTrackerScriptContext == nullptr);
  4108. this->rootTrackerScriptContext = scriptContext;
  4109. scriptContext->isRootTrackerScriptContext = true;
  4110. }
  4111. void
  4112. ThreadContext::ClearRootTrackerScriptContext(Js::ScriptContext * scriptContext)
  4113. {
  4114. Assert(this->rootTrackerScriptContext == scriptContext);
  4115. this->rootTrackerScriptContext->isRootTrackerScriptContext = false;
  4116. this->rootTrackerScriptContext = nullptr;
  4117. }
  4118. #endif
  4119. AutoTagNativeLibraryEntry::AutoTagNativeLibraryEntry(Js::RecyclableObject* function, Js::CallInfo callInfo, PCWSTR name, void* addr)
  4120. {
  4121. // Save function/callInfo values (for StackWalker). Compiler may stackpack/optimize them for built-in native functions.
  4122. entry.function = function;
  4123. entry.callInfo = callInfo;
  4124. entry.name = name;
  4125. entry.addr = addr;
  4126. ThreadContext* threadContext = function->GetScriptContext()->GetThreadContext();
  4127. threadContext->PushNativeLibraryEntry(&entry);
  4128. }
  4129. AutoTagNativeLibraryEntry::~AutoTagNativeLibraryEntry()
  4130. {
  4131. ThreadContext* threadContext = entry.function->GetScriptContext()->GetThreadContext();
  4132. Assert(threadContext->PeekNativeLibraryEntry() == &entry);
  4133. threadContext->PopNativeLibraryEntry();
  4134. }