ThreadContext.h 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. class ScriptContext;
  9. struct InlineCache;
  10. class CodeGenRecyclableData;
  11. #ifdef ENABLE_SCRIPT_DEBUGGING
  12. class DebugManager;
  13. struct ReturnedValue;
  14. typedef JsUtil::List<ReturnedValue*> ReturnedValueList;
  15. #endif
  16. class DelayedFreeArrayBuffer;
  17. }
  18. typedef BVSparse<ArenaAllocator> ActiveFunctionSet;
  19. using namespace PlatformAgnostic;
  20. struct IAuthorFileContext;
  21. class HostScriptContext;
  22. class ScriptSite;
  23. class ThreadServiceWrapper;
  24. struct IActiveScriptProfilerHeapEnum;
  25. class DynamicProfileMutator;
  26. class StackProber;
  27. enum DisableImplicitFlags : BYTE
  28. {
  29. DisableImplicitNoFlag = 0x00,
  30. DisableImplicitCallFlag = 0x01,
  31. DisableImplicitExceptionFlag = 0x02,
  32. DisableImplicitCallAndExceptionFlag = DisableImplicitCallFlag | DisableImplicitExceptionFlag
  33. };
  34. enum ThreadContextFlags
  35. {
  36. ThreadContextFlagNoFlag = 0x00000000,
  37. ThreadContextFlagCanDisableExecution = 0x00000001,
  38. ThreadContextFlagEvalDisabled = 0x00000002,
  39. ThreadContextFlagNoJIT = 0x00000004,
  40. ThreadContextFlagDisableFatalOnOOM = 0x00000008,
  41. ThreadContextFlagNoDynamicThunks = 0x00000010,
  42. };
  43. const int LS_MAX_STACK_SIZE_KB = 300;
  44. struct IProjectionContext
  45. {
  46. public:
  47. virtual HRESULT Close() = 0;
  48. };
  49. class ThreadContext;
  50. class InterruptPoller
  51. {
  52. // Interface with a polling object located in the hosting layer.
  53. public:
  54. InterruptPoller(ThreadContext *tc);
  55. virtual ~InterruptPoller() { }
  56. void CheckInterruptPoll();
  57. void GetStatementCount(ULONG *pluHi, ULONG *pluLo);
  58. void ResetStatementCount() { lastResetTick = lastPollTick; }
  59. void StartScript() { lastResetTick = lastPollTick = ::GetTickCount(); }
  60. void EndScript() { lastResetTick = lastPollTick = 0;}
  61. bool IsDisabled() const { return isDisabled; }
  62. void SetDisabled(bool disable) { isDisabled = disable; }
  63. virtual void TryInterruptPoll(Js::ScriptContext *scriptContext) = 0;
  64. // Default: throw up QC dialog after 5M statements == 2 minutes
  65. static const DWORD TicksToStatements = (5000000 / 120000);
  66. protected:
  67. ThreadContext *threadContext;
  68. DWORD lastPollTick;
  69. DWORD lastResetTick;
  70. bool isDisabled;
  71. };
  72. #define PROBE_STACK(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext))
  73. #define PROBE_STACK_NO_DISPOSE(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStackNoDispose(size, scriptContext))
  74. #define PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext, _ReturnAddress()))
  75. #define PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(scriptContext, size, returnAddress) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext, returnAddress))
  76. #define PROBE_STACK_CALL(scriptContext, obj, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, obj, scriptContext))
  77. #define AssertInScript() Assert(ThreadContext::GetContextForCurrentThread()->IsScriptActive());
  78. #define AssertNotInScript() Assert(!ThreadContext::GetContextForCurrentThread()->IsScriptActive());
  79. #define LEAVE_SCRIPT_START_EX(scriptContext, stackProbe, leaveForHost, isFPUControlRestoreNeeded) \
  80. { \
  81. void * __frameAddr = nullptr; \
  82. GET_CURRENT_FRAME_ID(__frameAddr); \
  83. Js::LeaveScriptObject<stackProbe, leaveForHost, isFPUControlRestoreNeeded> __leaveScriptObject(scriptContext, __frameAddr); \
  84. AutoReentrancyHandler autoReentrancyHandler(scriptContext->GetThreadContext());
  85. #define LEAVE_SCRIPT_END_EX(scriptContext) \
  86. if (scriptContext != nullptr) \
  87. { \
  88. scriptContext->GetThreadContext()->DisposeOnLeaveScript(); \
  89. }\
  90. }
  91. #define LEAVE_SCRIPT_IF_ACTIVE(scriptContext, externalCall) \
  92. if (scriptContext->GetThreadContext()->IsScriptActive()) \
  93. { \
  94. BEGIN_LEAVE_SCRIPT(scriptContext); \
  95. externalCall \
  96. END_LEAVE_SCRIPT(scriptContext); \
  97. } \
  98. else \
  99. { \
  100. DECLARE_EXCEPTION_CHECK_DATA \
  101. SAVE_EXCEPTION_CHECK \
  102. externalCall \
  103. RESTORE_EXCEPTION_CHECK \
  104. }
  105. #define ENTER_SCRIPT_IF(scriptContext, doCleanup, isCallRoot, hasCaller, condition, block) \
  106. if (condition) \
  107. { \
  108. BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, isCallRoot, hasCaller); \
  109. block \
  110. END_ENTER_SCRIPT(scriptContext, doCleanup, isCallRoot, hasCaller); \
  111. } \
  112. else \
  113. { \
  114. block \
  115. }
  116. #define BEGIN_LEAVE_SCRIPT(scriptContext) \
  117. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ false)
  118. #define BEGIN_LEAVE_SCRIPT_SAVE_FPU_CONTROL(scriptContext) \
  119. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ true)
  120. // BEGIN_LEAVE_SCRIPT_INTERNAL is used when there are no explicit external call after leave script,
  121. // but we might have external call when allocation memory doing QC or GC Dispose, which may enter script again.
  122. // This will record the reentry as an implicit call (ImplicitCall_AsyncHostOperation)
  123. #define BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext) \
  124. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ false, /* isFPUControlRestoreNeeded */ false)
  125. #define BEGIN_LEAVE_SCRIPT_NO_STACK_PROBE(scriptContext) \
  126. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ false, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ false)
  127. #define END_LEAVE_SCRIPT(scriptContext) \
  128. LEAVE_SCRIPT_END_EX(scriptContext)
  129. #define END_LEAVE_SCRIPT_RESTORE_FPU_CONTROL(scriptContext) \
  130. LEAVE_SCRIPT_END_EX(scriptContext)
  131. #define END_LEAVE_SCRIPT_INTERNAL(scriptContext) \
  132. LEAVE_SCRIPT_END_EX(scriptContext)
  133. #define END_LEAVE_SCRIPT_NO_STACK_PROBE(scriptContext) \
  134. LEAVE_SCRIPT_END_EX(scriptContext)
  135. #define BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) \
  136. BEGIN_LEAVE_SCRIPT(scriptContext)
  137. #define END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) \
  138. Assert(!scriptContext->HasRecordedException()); \
  139. END_LEAVE_SCRIPT(scriptContext)
  140. #define BEGIN_SAFE_REENTRANT_CALL(threadContext) \
  141. { \
  142. AutoReentrancyHandler autoReentrancyHandler(threadContext);
  143. #define END_SAFE_REENTRANT_CALL }
  144. #define BEGIN_SAFE_REENTRANT_REGION(threadContext) \
  145. { \
  146. AutoReentrancySafeRegion autoReentrancySafeRegion(threadContext);
  147. #define END_SAFE_REENTRANT_REGION }
  148. // Keep in sync with CollectGarbageCallBackFlags in scriptdirect.idl
  149. enum RecyclerCollectCallBackFlags
  150. {
  151. Collect_Begin = 0x01,
  152. Collect_Begin_Concurrent = 0x11,
  153. Collect_Begin_Partial = 0x21,
  154. Collect_Begin_Concurrent_Partial = Collect_Begin_Concurrent | Collect_Begin_Partial,
  155. Collect_End = 0x02,
  156. Collect_Wait = 0x04 // callback can be from another thread
  157. };
  158. typedef void (__cdecl *RecyclerCollectCallBackFunction)(void * context, RecyclerCollectCallBackFlags flags);
  159. #ifdef ENABLE_PROJECTION
  160. class ExternalWeakReferenceCache
  161. {
  162. public:
  163. virtual void MarkNow(Recycler *recycler, bool inPartialCollect) = 0;
  164. virtual void ResolveNow(Recycler *recycler) = 0;
  165. };
  166. #if DBG_DUMP
  167. class IProjectionContextMemoryInfo abstract
  168. {
  169. public:
  170. virtual void DumpCurrentStats(LPCWSTR headerMsg, bool forceDetailed) = 0;
  171. virtual void Release() = 0;
  172. };
  173. #endif
  174. #endif
  175. #ifdef NTBUILD
  176. struct ThreadContextWatsonTelemetryBlock
  177. {
  178. FILETIME lastScriptStartTime;
  179. FILETIME lastScriptEndTime;
  180. };
  181. #endif
  182. class NativeLibraryEntryRecord
  183. {
  184. public:
  185. struct Entry
  186. {
  187. Js::RecyclableObject* function;
  188. Js::CallInfo callInfo;
  189. PCWSTR name;
  190. PVOID addr;
  191. Entry* next;
  192. };
  193. private:
  194. Entry* head;
  195. public:
  196. NativeLibraryEntryRecord() : head(nullptr)
  197. {
  198. }
  199. const Entry* Peek() const
  200. {
  201. return head;
  202. }
  203. void Push(_In_ Entry* e)
  204. {
  205. e->next = head;
  206. head = e;
  207. }
  208. void Pop()
  209. {
  210. head = head->next;
  211. }
  212. };
  213. class AutoTagNativeLibraryEntry
  214. {
  215. private:
  216. NativeLibraryEntryRecord::Entry entry;
  217. public:
  218. AutoTagNativeLibraryEntry(Js::RecyclableObject* function, Js::CallInfo callInfo, PCWSTR name, void* addr);
  219. ~AutoTagNativeLibraryEntry();
  220. };
  221. #define AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, name) \
  222. AutoTagNativeLibraryEntry __tag(function, callInfo, name, _AddressOfReturnAddress())
  223. class ThreadConfiguration
  224. {
  225. public:
  226. ThreadConfiguration(bool enableExperimentalFeatures)
  227. {
  228. CopyGlobalFlags();
  229. if (enableExperimentalFeatures)
  230. {
  231. EnableExperimentalFeatures();
  232. ResetExperimentalFeaturesFromConfig();
  233. }
  234. }
  235. #define DEFINE_FLAG(threadFlag, globalFlag) \
  236. public: \
  237. inline bool threadFlag() const { return m_##globalFlag##; } \
  238. \
  239. private: \
  240. bool m_##globalFlag##;
  241. #define FLAG(threadFlag, globalFlag) DEFINE_FLAG(threadFlag, globalFlag)
  242. #define FLAG_RELEASE(threadFlag, globalFlag) DEFINE_FLAG(threadFlag, globalFlag)
  243. #include "ThreadConfigFlagsList.h"
  244. #undef FLAG_RELEASE
  245. #undef FLAG
  246. #undef DEFINE_FLAG
  247. private:
  248. void CopyGlobalFlags()
  249. {
  250. AutoCriticalSection autocs(&Js::Configuration::Global.flags.csExperimentalFlags);
  251. #define FLAG(threadFlag, globalFlag) m_##globalFlag## = CONFIG_FLAG(globalFlag);
  252. #define FLAG_RELEASE(threadFlag, globalFlag) m_##globalFlag## = CONFIG_FLAG_RELEASE(globalFlag);
  253. #include "ThreadConfigFlagsList.h"
  254. #undef FLAG_RELEASE
  255. #undef FLAG
  256. }
  257. void EnableExperimentalFeatures()
  258. {
  259. // If a ES6 flag is disabled using compile flag don't enable it
  260. #define FLAG_REGOVR_EXP(type, name, ...) m_##name## = COMPILE_DISABLE_##name## ? false : true;
  261. #include "ConfigFlagsList.h"
  262. #undef FLAG_REGOVR_EXP
  263. }
  264. void ResetExperimentalFeaturesFromConfig()
  265. {
  266. // If a flag was overridden using config/command line it should take precedence
  267. #define FLAG_REGOVR_EXP(type, name, ...) if(CONFIG_ISENABLED(Js::Flag::##name##Flag)) { m_##name## = CONFIG_FLAG_RELEASE(##name##); }
  268. #include "ConfigFlagsList.h"
  269. #undef FLAG_REGOVR_EXP
  270. }
  271. };
  272. class AutoReentrancyHandler;
  273. class ThreadContext sealed :
  274. public DefaultRecyclerCollectionWrapper,
  275. public JsUtil::DoublyLinkedListElement<ThreadContext>,
  276. public ThreadContextInfo
  277. {
  278. public:
  279. static void GlobalInitialize();
  280. static const DWORD NoThread = 0xFFFFFFFF;
  281. struct CollectCallBack
  282. {
  283. RecyclerCollectCallBackFunction callback;
  284. void * context;
  285. };
  286. struct WorkerThread
  287. {
  288. // Abstract notion to hold onto threadHandle of worker thread
  289. HANDLE threadHandle;
  290. WorkerThread(HANDLE handle = nullptr) :threadHandle(handle){};
  291. };
  292. void SetCurrentThreadId(DWORD threadId) { this->currentThreadId = threadId; }
  293. DWORD GetCurrentThreadId() const { return this->currentThreadId; }
  294. void SetIsThreadBound()
  295. {
  296. if (this->recycler)
  297. {
  298. this->recycler->SetIsThreadBound();
  299. }
  300. this->isThreadBound = true;
  301. }
  302. bool IsJSRT() const { return !this->isThreadBound; }
  303. virtual bool IsThreadBound() const override { return this->isThreadBound; }
  304. void SetStackProber(StackProber * stackProber);
  305. static DWORD GetStackLimitForCurrentThreadOffset() { return offsetof(ThreadContext, stackLimitForCurrentThread); }
  306. template <class Fn>
  307. Js::ImplicitCallFlags TryWithDisabledImplicitCall(Fn fn)
  308. {
  309. DisableImplicitFlags prevDisableImplicitFlags = this->GetDisableImplicitFlags();
  310. Js::ImplicitCallFlags savedImplicitCallFlags = this->GetImplicitCallFlags();
  311. this->DisableImplicitCall();
  312. this->SetImplicitCallFlags(Js::ImplicitCallFlags::ImplicitCall_None);
  313. fn();
  314. Js::ImplicitCallFlags curImplicitCallFlags = this->GetImplicitCallFlags();
  315. this->SetDisableImplicitFlags(prevDisableImplicitFlags);
  316. this->SetImplicitCallFlags(savedImplicitCallFlags);
  317. return curImplicitCallFlags;
  318. }
  319. void * GetAddressOfStackLimitForCurrentThread() const
  320. {
  321. FAULTINJECT_SCRIPT_TERMINATION
  322. return &this->stackLimitForCurrentThread;
  323. }
  324. void InitAvailableCommit();
  325. // This is always on for JSRT APIs.
  326. bool IsRentalThreadingEnabledInJSRT() const { return true; }
  327. IActiveScriptProfilerHeapEnum* GetHeapEnum();
  328. void SetHeapEnum(IActiveScriptProfilerHeapEnum* newHeapEnum);
  329. void ClearHeapEnum();
  330. Js::PropertyRecord const * GetPropertyRecord(Js::PropertyId propertyId);
  331. virtual bool IsNumericProperty(Js::PropertyId propertyId) override;
  332. #ifdef ENABLE_WASM_SIMD
  333. #if _M_IX86 || _M_AMD64
  334. // auxiliary SIMD values in memory to help JIT'ed code. E.g. used for Int8x16 shuffle.
  335. _x86_SIMDValue X86_TEMP_SIMD[SIMD_TEMP_SIZE];
  336. _x86_SIMDValue * GetSimdTempArea() { return X86_TEMP_SIMD; }
  337. #endif
  338. #endif
  339. public:
  340. Js::PropertyRecord const * GetEmptyStringPropertyRecord()
  341. {
  342. if (!emptyStringPropertyRecord)
  343. {
  344. emptyStringPropertyRecord = propertyMap->LookupWithKey(Js::HashedCharacterBuffer<char16>(_u(""), 0));
  345. if (emptyStringPropertyRecord == nullptr)
  346. {
  347. emptyStringPropertyRecord = this->UncheckedAddPropertyId(_u(""), 0, true);
  348. }
  349. }
  350. return emptyStringPropertyRecord;
  351. }
  352. Js::PropertyId GetEmptyStringPropertyId()
  353. {
  354. return GetEmptyStringPropertyRecord()->GetPropertyId();
  355. }
  356. private:
  357. const Js::PropertyRecord * emptyStringPropertyRecord;
  358. bool noScriptScope;
  359. #ifdef ENABLE_SCRIPT_DEBUGGING
  360. Js::DebugManager * debugManager;
  361. #endif
  362. static uint const MaxTemporaryArenaAllocators = 5;
  363. static CriticalSection s_csThreadContext;
  364. StackProber * GetStackProber() const { return this->stackProber; }
  365. size_t GetStackLimitForCurrentThread() const;
  366. void SetStackLimitForCurrentThread(size_t limit);
  367. // The current heap enumeration object being used during enumeration.
  368. IActiveScriptProfilerHeapEnum* heapEnum;
  369. struct PropertyGuardEntry
  370. {
  371. public:
  372. typedef JsUtil::BaseHashSet<RecyclerWeakReference<Js::PropertyGuard>*, Recycler, PowerOf2SizePolicy> PropertyGuardHashSet;
  373. // we do not have WeaklyReferencedKeyHashSet - hence use BYTE as a dummy value.
  374. typedef JsUtil::WeaklyReferencedKeyDictionary<Js::EntryPointInfo, BYTE> EntryPointDictionary;
  375. // The sharedGuard is strongly referenced and will be kept alive by ThreadContext::propertyGuards until it's invalidated or
  376. // the property record itself is collected. If the code using the guard needs access to it after it's been invalidated, it
  377. // (the code) is responsible for keeping it alive.
  378. // Each unique guard, is weakly referenced, such that it can be reclaimed if not referenced elsewhere even without being
  379. // invalidated. The entry of a unique guard is removed from the table once the corresponding cache is invalidated.
  380. Field(Js::PropertyGuard*) sharedGuard;
  381. Field(PropertyGuardHashSet) uniqueGuards;
  382. Field(EntryPointDictionary*) entryPoints;
  383. PropertyGuardEntry(Recycler* recycler) : sharedGuard(nullptr), uniqueGuards(recycler), entryPoints(nullptr) {}
  384. };
  385. public:
  386. typedef JsUtil::BaseHashSet<const Js::PropertyRecord *, HeapAllocator, PowerOf2SizePolicy, const Js::PropertyRecord *,
  387. Js::PropertyRecordStringHashComparer, JsUtil::SimpleHashedEntry, JsUtil::AsymetricResizeLock> PropertyMap;
  388. PropertyMap * propertyMap;
  389. typedef JsUtil::BaseHashSet<Js::CaseInvariantPropertyListWithHashCode*, Recycler, PowerOf2SizePolicy, Js::CaseInvariantPropertyListWithHashCode*, JsUtil::NoCaseComparer, JsUtil::SimpleDictionaryEntry>
  390. PropertyNoCaseSetType;
  391. typedef JsUtil::WeaklyReferencedKeyDictionary<Js::Type, bool> TypeHashSet;
  392. typedef JsUtil::BaseDictionary<Js::PropertyId, TypeHashSet *, Recycler, PowerOf2SizePolicy> PropertyIdToTypeHashSetDictionary;
  393. typedef JsUtil::WeaklyReferencedKeyDictionary<const Js::PropertyRecord, PropertyGuardEntry*, Js::PropertyRecordPointerComparer> PropertyGuardDictionary;
  394. private:
  395. PTHREADCONTEXT_HANDLE m_remoteThreadContextInfo;
  396. intptr_t m_prereservedRegionAddr;
  397. intptr_t m_jitThunkStartAddr;
  398. #if ENABLE_NATIVE_CODEGEN
  399. BVSparse<HeapAllocator> * m_jitNumericProperties;
  400. bool m_jitNeedsPropertyUpdate;
  401. public:
  402. intptr_t GetPreReservedRegionAddr()
  403. {
  404. return m_prereservedRegionAddr;
  405. }
  406. intptr_t GetJITThunkStartAddr()
  407. {
  408. return m_jitThunkStartAddr;
  409. }
  410. BVSparse<HeapAllocator> * GetJITNumericProperties() const
  411. {
  412. return m_jitNumericProperties;
  413. }
  414. bool JITNeedsPropUpdate() const
  415. {
  416. return m_jitNeedsPropertyUpdate;
  417. }
  418. void ResetJITNeedsPropUpdate()
  419. {
  420. m_jitNeedsPropertyUpdate = false;
  421. }
  422. static void SetJITConnectionInfo(HANDLE processHandle, void* serverSecurityDescriptor, UUID connectionId);
  423. bool EnsureJITThreadContext(bool allowPrereserveAlloc);
  424. PTHREADCONTEXT_HANDLE GetRemoteThreadContextAddr()
  425. {
  426. Assert(m_remoteThreadContextInfo);
  427. return m_remoteThreadContextInfo;
  428. }
  429. #endif
  430. private:
  431. typedef JsUtil::BaseDictionary<uint, Js::SourceDynamicProfileManager*, Recycler, PowerOf2SizePolicy> SourceDynamicProfileManagerMap;
  432. typedef JsUtil::BaseDictionary<Js::HashedCharacterBuffer<char16>*, const Js::PropertyRecord*, Recycler, PowerOf2SizePolicy, Js::PropertyRecordStringHashComparer> SymbolRegistrationMap;
  433. class SourceDynamicProfileManagerCache
  434. {
  435. public:
  436. SourceDynamicProfileManagerCache() : refCount(0), sourceProfileManagerMap(nullptr) {}
  437. Field(SourceDynamicProfileManagerMap*) sourceProfileManagerMap;
  438. void AddRef() { refCount++; }
  439. uint Release() { Assert(refCount > 0); return --refCount; }
  440. private:
  441. Field(uint) refCount; // For every script context using this cache, there is a ref count added.
  442. };
  443. typedef JsUtil::BaseDictionary<const WCHAR*, SourceDynamicProfileManagerCache*, Recycler, PowerOf2SizePolicy> SourceProfileManagersByUrlMap;
  444. struct RecyclableData
  445. {
  446. RecyclableData(Recycler *const recycler);
  447. Field(Js::TempArenaAllocatorObject *) temporaryArenaAllocators[MaxTemporaryArenaAllocators];
  448. Field(Js::TempGuestArenaAllocatorObject *) temporaryGuestArenaAllocators[MaxTemporaryArenaAllocators];
  449. Field(Js::JavascriptExceptionObject *) pendingFinallyException;
  450. Field(Js::JavascriptExceptionObject *) exceptionObject;
  451. Field(bool) propagateException;
  452. // We throw a JS catchable SO exception if we detect we might overflow the stack. Allocating this (JS)
  453. // object though might really overflow the stack. So use this thread global to identify them from the throw point
  454. // to where they are caught; where the stack has been unwound and it is safer to allocate the real exception
  455. // object and throw.
  456. Field(Js::JavascriptExceptionObject) soErrorObject;
  457. // We can't allocate an out of memory object... So use this static as a way to identify
  458. // them from the throw point to where they are caught.
  459. Field(Js::JavascriptExceptionObject) oomErrorObject;
  460. // This is for JsRT scenario where a runtime is not usable after a suspend request, before a resume runtime call is made
  461. Field(Js::JavascriptExceptionObject) terminatedErrorObject;
  462. Field(Js::JavascriptExceptionObject*) unhandledExceptionObject;
  463. // Used to temporarily keep throwing exception object alive (thrown but not yet caught)
  464. Field(Js::JavascriptExceptionObject*) tempUncaughtException;
  465. // Contains types that have property caches that need to be tracked, as the caches may need to be cleared. Types that
  466. // contain a property cache for a property that is on a prototype object will be tracked in this map since those caches
  467. // need to be cleared if for instance, the property is deleted from the prototype object.
  468. //
  469. // It is expected that over time, types that are deleted will eventually be removed by the weak reference hash sets when
  470. // they're searching through a bucket while registering a type or enumerating types to invalidate, or when a property ID
  471. // is reclaimed. If none of those happen, then this collection may contain weak reference handles to deleted objects
  472. // that would not get removed, but it would also not get any bigger.
  473. Field(PropertyIdToTypeHashSetDictionary) typesWithProtoPropertyCache;
  474. #if ENABLE_NATIVE_CODEGEN
  475. // The property guard dictionary contains property guards which need to be invalidated in response to properties changing
  476. // from writable to read-only and vice versa, properties being shadowed or unshadowed on prototypes, etc. The dictionary
  477. // holds only weak references to property guards and their lifetimes are controlled by their creators (typically entry points).
  478. // When a guard is no longer needed it is garbage collected, but the weak references and dictionary entries remain, until
  479. // the guards for a given property get invalidated.
  480. // TODO: Create and use a self-cleaning weak reference dictionary, which would periodically remove any unused weak references.
  481. Field(PropertyGuardDictionary) propertyGuards;
  482. #endif
  483. Field(PropertyNoCaseSetType *) caseInvariantPropertySet;
  484. Field(JsUtil::List<Js::PropertyRecord const*>*) boundPropertyStrings; // Recycler allocated list of property strings that we need to strongly reference so that they're not reclaimed
  485. Field(SourceProfileManagersByUrlMap*) sourceProfileManagersByUrl;
  486. // Used to register recyclable data that needs to be kept alive while jitting
  487. typedef JsUtil::DoublyLinkedList<Js::CodeGenRecyclableData, Recycler> CodeGenRecyclableDataList;
  488. Field(CodeGenRecyclableDataList) codeGenRecyclableDatas;
  489. // Used to root old entry points so that they're not prematurely collected
  490. Field(Js::FunctionEntryPointInfo*) oldEntryPointInfo;
  491. // Used to store a mapping of string to Symbol for cross-realm Symbol registration
  492. // See ES6 (draft 22) 19.4.2.2
  493. Field(SymbolRegistrationMap*) symbolRegistrationMap;
  494. #ifdef ENABLE_SCRIPT_DEBUGGING
  495. // Just holding the reference to the returnedValueList of the stepController. This way that list will not get recycled prematurely.
  496. Field(Js::ReturnedValueList *) returnedValueList;
  497. #endif
  498. Field(uint) constructorCacheInvalidationCount;
  499. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  500. // use for autoProxy called from Debug.setAutoProxyName. we need to keep the buffer from GetSz() alive.
  501. Field(LPCWSTR) autoProxyName;
  502. #endif
  503. };
  504. static ThreadContext * globalListLast;
  505. ThreadContextFlags threadContextFlags;
  506. DWORD currentThreadId;
  507. mutable size_t stackLimitForCurrentThread;
  508. StackProber * stackProber;
  509. bool isThreadBound;
  510. bool hasThrownPendingException;
  511. bool * hasBailedOutBitPtr;
  512. #if ENABLE_JS_REENTRANCY_CHECK
  513. bool noJsReentrancy;
  514. #endif
  515. private:
  516. bool reentrancySafeOrHandled;
  517. bool isInReentrancySafeRegion;
  518. AllocationPolicyManager * allocationPolicyManager;
  519. JsUtil::ThreadService threadService;
  520. #if ENABLE_NATIVE_CODEGEN
  521. PreReservedVirtualAllocWrapper preReservedVirtualAllocator;
  522. #endif
  523. uint callRootLevel;
  524. #if ENABLE_BACKGROUND_PAGE_FREEING
  525. // The thread page allocator is used by the recycler and need the background page queue
  526. PageAllocator::BackgroundPageQueue backgroundPageQueue;
  527. #endif
  528. IdleDecommitPageAllocator pageAllocator;
  529. Recycler* recycler;
  530. // This instance holds list of delay-free array buffer - this will be used in
  531. // scanning the stack in order to release any delay-free buffer.
  532. Js::DelayedFreeArrayBuffer delayFreeCallback;
  533. // Fake RecyclerWeakReference for built-in properties
  534. class StaticPropertyRecordReference : public RecyclerWeakReference<const Js::PropertyRecord>
  535. {
  536. public:
  537. StaticPropertyRecordReference(const Js::PropertyRecord* propertyRecord)
  538. {
  539. strongRef = (char*)propertyRecord;
  540. strongRefHeapBlock = &CollectedRecyclerWeakRefHeapBlock::Instance;
  541. }
  542. };
  543. static const Js::PropertyRecord * const builtInPropertyRecords[];
  544. PropertyNoCaseSetType * caseInvariantPropertySet;
  545. Js::ScriptContext * rootPendingClose;
  546. JsUtil::List<IProjectionContext *, ArenaAllocator>* pendingProjectionContextCloseList;
  547. Js::ScriptEntryExitRecord * entryExitRecord;
  548. Js::InterpreterStackFrame* leafInterpreterFrame;
  549. const Js::PropertyRecord * propertyNamesDirect[128];
  550. ArenaAllocator threadAlloc;
  551. ThreadServiceWrapper* threadServiceWrapper;
  552. uint functionCount;
  553. uint sourceInfoCount;
  554. void * tryHandlerAddrOfReturnAddr;
  555. enum RedeferralState
  556. {
  557. InitialRedeferralState,
  558. StartupRedeferralState,
  559. MainRedeferralState
  560. };
  561. RedeferralState redeferralState;
  562. uint gcSinceLastRedeferral;
  563. uint gcSinceCallCountsCollected;
  564. static const uint InitialRedeferralDelay = 5;
  565. static const uint StartupRedeferralCheckInterval = 10;
  566. static const uint StartupRedeferralInactiveThreshold = 5;
  567. static const uint MainRedeferralCheckInterval = 20;
  568. static const uint MainRedeferralInactiveThreshold = 10;
  569. Js::TypeId nextTypeId;
  570. uint32 polymorphicCacheState;
  571. #ifdef ENABLE_PROJECTION
  572. SListBase<ExternalWeakReferenceCache *, HeapAllocator> externalWeakReferenceCacheList;
  573. #if DBG_DUMP
  574. IProjectionContextMemoryInfo *projectionMemoryInformation;
  575. #endif
  576. #endif
  577. #if ENABLE_NATIVE_CODEGEN
  578. JsUtil::JobProcessor *jobProcessor;
  579. Js::Var * bailOutRegisterSaveSpace;
  580. #if !FLOATVAR
  581. CodeGenNumberThreadAllocator * codeGenNumberThreadAllocator;
  582. XProcNumberPageSegmentManager * xProcNumberPageSegmentManager;
  583. #endif
  584. #if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
  585. CustomHeap::InProcCodePageAllocators thunkPageAllocators;
  586. #endif
  587. CustomHeap::InProcCodePageAllocators codePageAllocators;
  588. #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)
  589. InProcJITThunkEmitter jitThunkEmitter;
  590. #endif
  591. #endif
  592. RecyclerRootPtr<RecyclableData> recyclableData;
  593. uint temporaryArenaAllocatorCount;
  594. uint temporaryGuestArenaAllocatorCount;
  595. #if DBG_DUMP || defined(PROFILE_EXEC)
  596. ScriptSite* topLevelScriptSite;
  597. #endif
  598. Js::ScriptContext *scriptContextList;
  599. bool scriptContextEverRegistered;
  600. static size_t processNativeCodeSize;
  601. size_t nativeCodeSize;
  602. size_t sourceCodeSize;
  603. DateTime::HiResTimer hTimer;
  604. int stackProbeCount;
  605. // Count stack probes and poll for continuation every n probes
  606. static const int StackProbePollThreshold = 1000;
  607. EXCEPTION_POINTERS exceptionInfo;
  608. uint32 exceptionCode;
  609. ArenaAllocator inlineCacheThreadInfoAllocator;
  610. ArenaAllocator isInstInlineCacheThreadInfoAllocator;
  611. ArenaAllocator equivalentTypeCacheInfoAllocator;
  612. DListBase<Js::EntryPointInfo *> equivalentTypeCacheEntryPoints;
  613. typedef SList<Js::InlineCache*> InlineCacheList;
  614. typedef JsUtil::BaseDictionary<Js::PropertyId, InlineCacheList*, ArenaAllocator, PrimeSizePolicy> InlineCacheListMapByPropertyId;
  615. InlineCacheListMapByPropertyId protoInlineCacheByPropId;
  616. InlineCacheListMapByPropertyId storeFieldInlineCacheByPropId;
  617. uint registeredInlineCacheCount;
  618. uint unregisteredInlineCacheCount;
  619. #if DBG
  620. uint totalUnregisteredCacheCount;
  621. uint arrayMutationSeed; // This is mostly to aid in debugging.
  622. #endif
  623. typedef JsUtil::BaseDictionary<Js::Var, Js::IsInstInlineCache*, ArenaAllocator, PrimeSizePolicy> IsInstInlineCacheListMapByFunction;
  624. IsInstInlineCacheListMapByFunction isInstInlineCacheByFunction;
  625. Js::IsConcatSpreadableCache isConcatSpreadableCache;
  626. Js::NoSpecialPropertyThreadRegistry noSpecialPropertyRegistry;
  627. Js::OnlyWritablePropertyThreadRegistry onlyWritablePropertyRegistry;
  628. DListBase<CollectCallBack> collectCallBackList;
  629. CriticalSection csCollectionCallBack;
  630. bool hasCollectionCallBack;
  631. bool isOptimizedForManyInstances;
  632. bool bgJit;
  633. // We report library code to profiler only if called directly by user code. Not if called by library implementation.
  634. bool isProfilingUserCode;
  635. void* jsrtRuntime;
  636. bool hasUnhandledException;
  637. bool hasCatchHandler;
  638. DisableImplicitFlags disableImplicitFlags;
  639. // Used for identifying that any particular time, the caller chain has try/catch blocks belong to the user code.
  640. // If all try/catch blocks in the current stack marked as non-user code then this member will remain false.
  641. bool hasCatchHandlerToUserCode;
  642. #ifdef ENABLE_GLOBALIZATION
  643. Js::DelayLoadWinRtString delayLoadWinRtString;
  644. #ifdef ENABLE_PROJECTION
  645. Js::DelayLoadWinRtError delayLoadWinRtError;
  646. Js::DelayLoadWinRtTypeResolution delayLoadWinRtTypeResolution;
  647. Js::DelayLoadWinRtRoParameterizedIID delayLoadWinRtRoParameterizedIID;
  648. #endif
  649. #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_ES6_CHAR_CLASSIFIER)
  650. #ifdef INTL_WINGLOB
  651. Js::DelayLoadWindowsGlobalization delayLoadWindowsGlobalizationLibrary;
  652. Js::WindowsGlobalizationAdapter windowsGlobalizationAdapter;
  653. #endif
  654. #endif
  655. #ifdef ENABLE_FOUNDATION_OBJECT
  656. Js::DelayLoadWinRtFoundation delayLoadWinRtFoundationLibrary;
  657. Js::WindowsFoundationAdapter windowsFoundationAdapter;
  658. #endif
  659. #endif
  660. // Number of script context attached with probe manager.
  661. // This counter will be used as addref when the script context is created, this way we maintain the life of diagnostic object.
  662. // Once no script context available , diagnostic will go away.
  663. LONG crefSContextForDiag;
  664. Entropy entropy;
  665. JsUtil::Stack<HostScriptContext*>* hostScriptContextStack;
  666. //
  667. // Regex globals
  668. //
  669. UnifiedRegex::StandardChars<uint8>* standardUTF8Chars;
  670. UnifiedRegex::StandardChars<char16>* standardUnicodeChars;
  671. Js::ImplicitCallFlags implicitCallFlags;
  672. THREAD_LOCAL static uint activeScriptSiteCount;
  673. bool isScriptActive;
  674. // When ETW rundown in background thread which needs to walk scriptContext/functionBody/entryPoint lists,
  675. // or when JIT thread is getting auxPtrs from function body, we should not be modifying the list of
  676. // functionBody/entrypoints, or expanding the auxPtrs
  677. CriticalSection csFunctionBody;
  678. #ifdef _M_X64
  679. friend class Js::Amd64StackFrame;
  680. Js::Amd64ContextsManager amd64ContextsManager;
  681. Js::Amd64ContextsManager* GetAmd64ContextsManager() { return &amd64ContextsManager; }
  682. #endif
  683. typedef JsUtil::BaseDictionary<Js::DynamicType const *, void *, HeapAllocator, PowerOf2SizePolicy> DynamicObjectEnumeratorCacheMap;
  684. DynamicObjectEnumeratorCacheMap dynamicObjectEnumeratorCacheMap;
  685. #ifdef NTBUILD
  686. ThreadContextWatsonTelemetryBlock localTelemetryBlock;
  687. ThreadContextWatsonTelemetryBlock * telemetryBlock;
  688. #endif
  689. NativeLibraryEntryRecord nativeLibraryEntry;
  690. UCrtC99MathApis ucrtC99MathApis;
  691. // Indicates the current loop depth as observed by the interpreter. The interpreter causes this value to be updated upon
  692. // entering and leaving a loop.
  693. uint8 loopDepth;
  694. const ThreadConfiguration configuration;
  695. public:
  696. static ThreadContext * globalListFirst;
  697. static uint GetScriptSiteHolderCount() { return activeScriptSiteCount; }
  698. static uint IncrementActiveScriptSiteCount() { return ++activeScriptSiteCount; }
  699. static uint DecrementActiveScriptSiteCount() { return --activeScriptSiteCount; }
  700. static ThreadContext * GetThreadContextList() { return globalListFirst; }
  701. void ValidateThreadContext();
  702. bool IsInScript() const { return callRootLevel != 0; }
  703. uint GetCallRootLevel() const { return callRootLevel; }
  704. PageAllocator * GetPageAllocator() { return &pageAllocator; }
  705. AllocationPolicyManager * GetAllocationPolicyManager() { return allocationPolicyManager; }
  706. // used for diagnosing abnormally high number of closed, but still formally reachable script contexts
  707. // at the time of failfast due to allocation limits.
  708. // high number may indicate that context leaks have occured.
  709. uint closedScriptContextCount;
  710. enum VisibilityState : BYTE
  711. {
  712. Undefined = 0,
  713. Visible = 1,
  714. NotVisible = 2
  715. };
  716. // indicates the visibility state of the hosting application/window/tab if known.
  717. VisibilityState visibilityState;
  718. #if ENABLE_NATIVE_CODEGEN
  719. PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() { return &preReservedVirtualAllocator; }
  720. #if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
  721. CustomHeap::InProcCodePageAllocators * GetThunkPageAllocators() { return &thunkPageAllocators; }
  722. #endif
  723. CustomHeap::InProcCodePageAllocators * GetCodePageAllocators() { return &codePageAllocators; }
  724. #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)
  725. InProcJITThunkEmitter * GetJITThunkEmitter() { return &jitThunkEmitter; }
  726. #endif
  727. #endif // ENABLE_NATIVE_CODEGEN
  728. CriticalSection* GetFunctionBodyLock() { return &csFunctionBody; }
  729. UCrtC99MathApis* GetUCrtC99MathApis() { return &ucrtC99MathApis; }
  730. Js::IsConcatSpreadableCache* GetIsConcatSpreadableCache() { return &isConcatSpreadableCache; }
  731. #ifdef ENABLE_GLOBALIZATION
  732. Js::DelayLoadWinRtString *GetWinRTStringLibrary();
  733. #ifdef ENABLE_PROJECTION
  734. Js::DelayLoadWinRtError *GetWinRTErrorLibrary();
  735. Js::DelayLoadWinRtTypeResolution* GetWinRTTypeResolutionLibrary();
  736. Js::DelayLoadWinRtRoParameterizedIID* GetWinRTRoParameterizedIIDLibrary();
  737. #endif
  738. #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_ES6_CHAR_CLASSIFIER)
  739. #ifdef INTL_WINGLOB
  740. Js::DelayLoadWindowsGlobalization *GetWindowsGlobalizationLibrary();
  741. Js::WindowsGlobalizationAdapter *GetWindowsGlobalizationAdapter();
  742. #endif
  743. #endif
  744. #ifdef ENABLE_FOUNDATION_OBJECT
  745. Js::DelayLoadWinRtFoundation *GetWinRtFoundationLibrary();
  746. Js::WindowsFoundationAdapter *GetWindowsFoundationAdapter();
  747. #endif
  748. #endif
  749. void SetAbnormalExceptionRecord(EXCEPTION_POINTERS *exceptionInfo) { this->exceptionInfo = *exceptionInfo; }
  750. void SetAbnormalExceptionCode(uint32 exceptionInfo) { this->exceptionCode = exceptionInfo; }
  751. uint32 GetAbnormalExceptionCode() const { return this->exceptionCode; }
  752. #ifdef ENABLE_BASIC_TELEMETRY
  753. GUID activityId;
  754. LPFILETIME GetLastScriptExecutionEndTime() const;
  755. #endif
  756. void *tridentLoadAddress;
  757. void* GetTridentLoadAddress() const { return tridentLoadAddress; }
  758. void SetTridentLoadAddress(void *loadAddress) { tridentLoadAddress = loadAddress; }
  759. Js::NoSpecialPropertyThreadRegistry* GetNoSpecialPropertyRegistry() { return &this->noSpecialPropertyRegistry; }
  760. Js::OnlyWritablePropertyThreadRegistry* GetOnlyWritablePropertyRegistry() { return &this->onlyWritablePropertyRegistry; }
  761. Js::DelayedFreeArrayBuffer * GetScanStackCallback()
  762. {
  763. return &this->delayFreeCallback;
  764. }
  765. #ifdef ENABLE_DIRECTCALL_TELEMETRY
  766. DirectCallTelemetry directCallTelemetry;
  767. #endif
  768. BOOL HasPreviousHostScriptContext();
  769. HostScriptContext* GetPreviousHostScriptContext() ;
  770. void PushHostScriptContext(HostScriptContext* topProvider);
  771. HostScriptContext* PopHostScriptContext();
  772. void SetInterruptPoller(InterruptPoller *poller) { interruptPoller = poller; }
  773. InterruptPoller *GetInterruptPoller() const { return interruptPoller; }
  774. BOOL HasInterruptPoller() const { return interruptPoller != nullptr; }
  775. void CheckScriptInterrupt();
  776. void CheckInterruptPoll();
  777. bool DoInterruptProbe(Js::FunctionBody *const func) const
  778. {
  779. return
  780. (this->TestThreadContextFlag(ThreadContextFlagCanDisableExecution) &&
  781. !PHASE_OFF(Js::InterruptProbePhase, func)) ||
  782. PHASE_ON(Js::InterruptProbePhase, func);
  783. }
  784. bool DoInterruptProbe() const
  785. {
  786. return
  787. (this->TestThreadContextFlag(ThreadContextFlagCanDisableExecution) &&
  788. !PHASE_OFF1(Js::InterruptProbePhase)) ||
  789. PHASE_ON1(Js::InterruptProbePhase);
  790. }
  791. bool EvalDisabled() const
  792. {
  793. return this->TestThreadContextFlag(ThreadContextFlagEvalDisabled);
  794. }
  795. bool NoJIT() const
  796. {
  797. return this->TestThreadContextFlag(ThreadContextFlagNoJIT);
  798. }
  799. bool NoDynamicThunks() const
  800. {
  801. return this->TestThreadContextFlag(ThreadContextFlagNoDynamicThunks);
  802. }
  803. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  804. Js::Var GetMemoryStat(Js::ScriptContext* scriptContext);
  805. void SetAutoProxyName(LPCWSTR objectName);
  806. LPCWSTR GetAutoProxyName() const { return recyclableData->autoProxyName; }
  807. Js::PropertyId handlerPropertyId = Js::Constants::NoProperty;
  808. #endif
  809. #ifdef ENABLE_SCRIPT_DEBUGGING
  810. void SetReturnedValueList(Js::ReturnedValueList *returnedValueList)
  811. {
  812. Assert(this->recyclableData != nullptr);
  813. this->recyclableData->returnedValueList = returnedValueList;
  814. }
  815. #if DBG
  816. void EnsureNoReturnedValueList()
  817. {
  818. Assert(this->recyclableData == nullptr || this->recyclableData->returnedValueList == nullptr);
  819. }
  820. #endif
  821. #endif
  822. #if DBG || defined(RUNTIME_DATA_COLLECTION)
  823. uint GetScriptContextCount() const { return this->scriptContextCount; }
  824. #endif
  825. Js::ScriptContext* GetScriptContextList() const { return this->scriptContextList; }
  826. bool WasAnyScriptContextEverRegistered() const { return this->scriptContextEverRegistered; }
  827. #if DBG_DUMP || defined(PROFILE_EXEC)
  828. void SetTopLevelScriptSite(ScriptSite* topScriptSite) { this->topLevelScriptSite = topScriptSite; }
  829. ScriptSite* GetTopLevelScriptSite () { return this->topLevelScriptSite; }
  830. #endif
  831. #if DBG || defined(PROFILE_EXEC)
  832. virtual bool AsyncHostOperationStart(void *) override;
  833. virtual void AsyncHostOperationEnd(bool wasInAsync, void *) override;
  834. #endif
  835. #if DBG
  836. virtual void CheckJsReentrancyOnDispose() override;
  837. bool IsInAsyncHostOperation() const;
  838. #endif
  839. #if ENABLE_TTD
  840. //The class that holds info on the TTD state for the thread context
  841. TTD::ThreadContextTTD* TTDContext;
  842. //The class that holds information on TTD <-> debugger interaction state
  843. TTD::ExecutionInfoManager* TTDExecutionInfo;
  844. //The event log for time-travel (or null if TTD is not turned on)
  845. TTD::EventLog* TTDLog;
  846. //Keep track of the number of re-entrant calls currently pending (i.e., if we make an external call it may call back into Chakra)
  847. int32 TTDRootNestingCount;
  848. bool IsRuntimeInTTDMode() const
  849. {
  850. return this->TTDLog != nullptr;
  851. }
  852. //Initialize the context for time-travel
  853. void InitTimeTravel(ThreadContext* threadContext, void* runtimeHandle, uint32 snapInterval, uint32 snapHistoryLength);
  854. void InitHostFunctionsAndTTData(bool record, bool replay, bool debug, size_t optTTUriLength, const char* optTTUri,
  855. TTD::TTDOpenResourceStreamCallback openResourceStreamfp, TTD::TTDReadBytesFromStreamCallback readBytesFromStreamfp,
  856. TTD::TTDWriteBytesToStreamCallback writeBytesToStreamfp, TTD::TTDFlushAndCloseStreamCallback flushAndCloseStreamfp,
  857. TTD::TTDCreateExternalObjectCallback createExternalObjectfp,
  858. TTD::TTDCreateJsRTContextCallback createJsRTContextCallbackfp, TTD::TTDReleaseJsRTContextCallback releaseJsRTContextCallbackfp, TTD::TTDSetActiveJsRTContext fpSetActiveJsRTContext);
  859. #endif
  860. BOOL ReserveStaticTypeIds(__in int first, __in int last);
  861. Js::TypeId ReserveTypeIds(int count);
  862. Js::TypeId CreateTypeId();
  863. Js::TypeId GetNextTypeId() { return nextTypeId; }
  864. // Lookup the well known type registered with a Js::TypeId.
  865. // wellKnownType: The well known type which we should register
  866. // typeId: The type id to match
  867. // returns: true if the typeid is the wellKnownType
  868. template<WellKnownHostType wellKnownType>
  869. bool IsWellKnownHostType(Js::TypeId typeId)
  870. {
  871. CompileAssert(wellKnownType <= WellKnownHostType_Last);
  872. return wellKnownHostTypeIds[wellKnownType] == typeId;
  873. }
  874. // Register a well known type to a Js::TypeId.
  875. // wellKnownType: The well known type which we should register
  876. // typeId: The type id which matches to the well known type
  877. void SetWellKnownHostTypeId(WellKnownHostType wellKnownType, Js::TypeId typeId);
  878. uint32 GetNextPolymorphicCacheState()
  879. {
  880. return ++polymorphicCacheState;
  881. };
  882. ~ThreadContext();
  883. void CloseForJSRT();
  884. //Call back is called for one or more handles
  885. //It does multiple callbacks (For example: separate call back for GC thread handle & JIT thread handles)
  886. // template<class Fn>
  887. //void ShutdownThreads(Fn callback);
  888. void ShutdownThreads()
  889. {
  890. #if ENABLE_NATIVE_CODEGEN
  891. if (jobProcessor)
  892. {
  893. jobProcessor->Close();
  894. }
  895. if (JITManager::GetJITManager()->IsOOPJITEnabled() && JITManager::GetJITManager()->IsConnected() && m_remoteThreadContextInfo)
  896. {
  897. if (JITManager::GetJITManager()->CleanupThreadContext(&m_remoteThreadContextInfo) == S_OK)
  898. {
  899. Assert(m_remoteThreadContextInfo == nullptr);
  900. }
  901. m_remoteThreadContextInfo = nullptr;
  902. }
  903. #endif
  904. #if ENABLE_CONCURRENT_GC
  905. if (this->recycler != nullptr)
  906. {
  907. this->recycler->ShutdownThread();
  908. }
  909. #endif
  910. }
  911. DateTime::HiResTimer * GetHiResTimer() { return &hTimer; }
  912. ArenaAllocator* GetThreadAlloc() { return &threadAlloc; }
  913. static CriticalSection * GetCriticalSection() { return &s_csThreadContext; }
  914. ThreadContext(AllocationPolicyManager * allocationPolicyManager = nullptr, JsUtil::ThreadService::ThreadServiceCallback threadServiceCallback = nullptr, bool enableExperimentalFeatures = false);
  915. static void Add(ThreadContext *threadContext);
  916. ThreadConfiguration const * GetConfig() const { return &configuration; }
  917. public:
  918. #ifdef NTBUILD
  919. void SetTelemetryBlock(ThreadContextWatsonTelemetryBlock * telemetryBlock) { this->telemetryBlock = telemetryBlock; }
  920. #endif
  921. static ThreadContext* GetContextForCurrentThread();
  922. Recycler* GetRecycler() { return recycler; }
  923. Recycler* EnsureRecycler();
  924. ThreadContext::CollectCallBack * AddRecyclerCollectCallBack(RecyclerCollectCallBackFunction callback, void * context);
  925. void RemoveRecyclerCollectCallBack(ThreadContext::CollectCallBack * collectCallBack);
  926. void AddToPendingProjectionContextCloseList(IProjectionContext *projectionContext);
  927. void RemoveFromPendingClose(IProjectionContext *projectionContext);
  928. void ClosePendingProjectionContexts();
  929. void AddToPendingScriptContextCloseList(Js::ScriptContext * scriptContext);
  930. void RemoveFromPendingClose(Js::ScriptContext * scriptContext);
  931. void ClosePendingScriptContexts();
  932. Js::PropertyRecord const * GetPropertyName(Js::PropertyId propertyId);
  933. Js::PropertyRecord const * GetPropertyNameLocked(Js::PropertyId propertyId);
  934. private:
  935. template <bool locked> Js::PropertyRecord const * GetPropertyNameImpl(Js::PropertyId propertyId);
  936. public:
  937. void FindPropertyRecord(Js::JavascriptString *pstName, Js::PropertyRecord const ** propertyRecord);
  938. void FindPropertyRecord(__in LPCWCH propertyName, __in int propertyNameLength, Js::PropertyRecord const ** propertyRecord);
  939. const Js::PropertyRecord * FindPropertyRecord(const char16 * propertyName, int propertyNameLength);
  940. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>* FindPropertyIdNoCase(Js::ScriptContext * scriptContext, LPCWSTR propertyName, int propertyNameLength);
  941. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>* FindPropertyIdNoCase(Js::ScriptContext * scriptContext, JsUtil::CharacterBuffer<WCHAR> const& propertyName);
  942. bool FindExistingPropertyRecord(_In_ JsUtil::CharacterBuffer<WCHAR> const& propertyName, Js::CaseInvariantPropertyListWithHashCode** propertyRecord);
  943. void CleanNoCasePropertyMap();
  944. void ForceCleanPropertyMap();
  945. const Js::PropertyRecord * GetOrAddPropertyRecord(JsUtil::CharacterBuffer<char16> propertyName)
  946. {
  947. return GetOrAddPropertyRecordImpl(propertyName, false);
  948. }
  949. const Js::PropertyRecord * GetOrAddPropertyRecordBind(JsUtil::CharacterBuffer<char16> propertyName)
  950. {
  951. return GetOrAddPropertyRecordImpl(propertyName, true);
  952. }
  953. void AddBuiltInPropertyRecord(const Js::PropertyRecord *propertyRecord);
  954. void GetOrAddPropertyId(_In_ LPCWSTR propertyName, _In_ int propertyNameLength, _Out_ Js::PropertyRecord const** propertyRecord);
  955. void GetOrAddPropertyId(_In_ JsUtil::CharacterBuffer<WCHAR> const& propertyName, _Out_ Js::PropertyRecord const** propertyRecord);
  956. Js::PropertyRecord const * UncheckedAddPropertyId(JsUtil::CharacterBuffer<WCHAR> const& propertyName, bool bind, bool isSymbol = false);
  957. Js::PropertyRecord const * UncheckedAddPropertyId(__in LPCWSTR propertyName, __in int propertyNameLength, bool bind = false, bool isSymbol = false);
  958. #ifdef ENABLE_JS_ETW
  959. void EtwLogPropertyIdList();
  960. #endif
  961. private:
  962. const Js::PropertyRecord * GetOrAddPropertyRecordImpl(JsUtil::CharacterBuffer<char16> propertyName, bool bind);
  963. void AddPropertyRecordInternal(const Js::PropertyRecord * propertyRecord);
  964. void BindPropertyRecord(const Js::PropertyRecord * propertyRecord);
  965. bool IsDirectPropertyName(const char16 * propertyName, int propertyNameLength);
  966. RecyclerWeakReference<const Js::PropertyRecord> * CreatePropertyRecordWeakRef(const Js::PropertyRecord * propertyRecord);
  967. void AddCaseInvariantPropertyRecord(const Js::PropertyRecord * propertyRecord);
  968. #if DBG || defined(RUNTIME_DATA_COLLECTION)
  969. uint scriptContextCount;
  970. #endif
  971. public:
  972. void UncheckedAddBuiltInPropertyId();
  973. BOOL IsNumericPropertyId(Js::PropertyId propertyId, uint32* value);
  974. bool IsActivePropertyId(Js::PropertyId pid);
  975. void InvalidatePropertyRecord(const Js::PropertyRecord * propertyRecord);
  976. Js::PropertyId GetNextPropertyId();
  977. Js::PropertyId GetMaxPropertyId();
  978. uint GetHighestPropertyNameIndex() const;
  979. void SetThreadServiceWrapper(ThreadServiceWrapper*);
  980. ThreadServiceWrapper* GetThreadServiceWrapper();
  981. #ifdef ENABLE_PROJECTION
  982. void AddExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache);
  983. void RemoveExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache);
  984. virtual void MarkExternalWeakReferencedObjects(bool inPartialCollect) override;
  985. virtual void ResolveExternalWeakReferencedObjects() override;
  986. #if DBG_DUMP
  987. void RegisterProjectionMemoryInformation(IProjectionContextMemoryInfo* projectionContextMemoryInfo);
  988. void DumpProjectionContextMemoryStats(LPCWSTR headerMsg, bool forceDetailed = false);
  989. IProjectionContextMemoryInfo* GetProjectionContextMemoryInformation();
  990. #endif
  991. #endif
  992. uint NewFunctionNumber() { return ++functionCount; }
  993. uint PeekNewFunctionNumber() { return functionCount + 1; }
  994. uint NewSourceInfoNumber() { return ++sourceInfoCount; }
  995. void AddCodeSize(size_t newCode)
  996. {
  997. ::InterlockedExchangeAdd(&nativeCodeSize, newCode);
  998. ::InterlockedExchangeAdd(&processNativeCodeSize, newCode);
  999. }
  1000. void AddSourceSize(size_t newCode) { sourceCodeSize += newCode; }
  1001. void SubCodeSize(size_t deadCode)
  1002. {
  1003. Assert(nativeCodeSize >= deadCode);
  1004. Assert(processNativeCodeSize >= deadCode);
  1005. ::InterlockedExchangeSubtract(&nativeCodeSize, deadCode);
  1006. ::InterlockedExchangeSubtract(&processNativeCodeSize, deadCode);
  1007. }
  1008. void SubSourceSize(size_t deadCode) { Assert(sourceCodeSize >= deadCode); sourceCodeSize -= deadCode; }
  1009. size_t GetCodeSize() { return nativeCodeSize; }
  1010. static size_t GetProcessCodeSize() { return processNativeCodeSize; }
  1011. size_t GetSourceSize() { return sourceCodeSize; }
  1012. bool DoTryRedeferral() const;
  1013. void TryRedeferral();
  1014. bool DoRedeferFunctionBodies() const;
  1015. void UpdateRedeferralState();
  1016. uint GetRedeferralCollectionInterval() const;
  1017. uint GetRedeferralInactiveThreshold() const;
  1018. void GetActiveFunctions(ActiveFunctionSet * pActive);
  1019. #if DBG
  1020. uint redeferredFunctions;
  1021. uint recoveredBytes;
  1022. #endif
  1023. Js::ScriptEntryExitRecord * GetScriptEntryExit() const { return entryExitRecord; }
  1024. void RegisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData);
  1025. void UnregisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData);
  1026. #if ENABLE_NATIVE_CODEGEN
  1027. bool IsNativeAddressHelper(void * pCodeAddr, Js::ScriptContext* currentScriptContext);
  1028. BOOL IsNativeAddress(void * pCodeAddr, Js::ScriptContext* currentScriptContext = nullptr);
  1029. JsUtil::JobProcessor *GetJobProcessor();
  1030. Js::Var * GetBailOutRegisterSaveSpace() const { return bailOutRegisterSaveSpace; }
  1031. virtual intptr_t GetBailOutRegisterSaveSpaceAddr() const override { return (intptr_t)bailOutRegisterSaveSpace; }
  1032. #if !FLOATVAR
  1033. CodeGenNumberThreadAllocator * GetCodeGenNumberThreadAllocator() const
  1034. {
  1035. return codeGenNumberThreadAllocator;
  1036. }
  1037. XProcNumberPageSegmentManager * GetXProcNumberPageSegmentManager() const
  1038. {
  1039. return this->xProcNumberPageSegmentManager;
  1040. }
  1041. #endif
  1042. #endif
  1043. void ResetFunctionCount() { Assert(this->GetScriptSiteHolderCount() == 0); this->functionCount = 0; }
  1044. void PushEntryExitRecord(Js::ScriptEntryExitRecord *);
  1045. void PopEntryExitRecord(Js::ScriptEntryExitRecord *);
  1046. uint EnterScriptStart(Js::ScriptEntryExitRecord *, bool doCleanup);
  1047. void EnterScriptEnd(Js::ScriptEntryExitRecord *, bool doCleanup);
  1048. void * GetTryHandlerAddrOfReturnAddr() { return this->tryHandlerAddrOfReturnAddr; }
  1049. void SetTryHandlerAddrOfReturnAddr(void * addrOfReturnAddr) { this->tryHandlerAddrOfReturnAddr = addrOfReturnAddr; }
  1050. template <bool leaveForHost>
  1051. void LeaveScriptStart(void *);
  1052. template <bool leaveForHost>
  1053. void LeaveScriptEnd(void *);
  1054. void DisposeOnLeaveScript();
  1055. void PushInterpreterFrame(Js::InterpreterStackFrame *interpreterFrame);
  1056. Js::InterpreterStackFrame *PopInterpreterFrame();
  1057. Js::InterpreterStackFrame *GetLeafInterpreterFrame() const { return leafInterpreterFrame; }
  1058. Js::TempArenaAllocatorObject * GetTemporaryAllocator(LPCWSTR name);
  1059. void ReleaseTemporaryAllocator(Js::TempArenaAllocatorObject * tempAllocator);
  1060. Js::TempGuestArenaAllocatorObject * GetTemporaryGuestAllocator(LPCWSTR name);
  1061. void ReleaseTemporaryGuestAllocator(Js::TempGuestArenaAllocatorObject * tempAllocator);
  1062. #ifdef ENABLE_SCRIPT_DEBUGGING
  1063. // Should be called from script context, at the time when construction for scriptcontext is just done.
  1064. void EnsureDebugManager();
  1065. // Should be called from script context 's destructor,
  1066. void ReleaseDebugManager();
  1067. #endif
  1068. void RegisterScriptContext(Js::ScriptContext *scriptContext);
  1069. void UnregisterScriptContext(Js::ScriptContext *scriptContext);
  1070. // NoScriptScope
  1071. void SetNoScriptScope(bool noScriptScope) { this->noScriptScope = noScriptScope; }
  1072. bool IsNoScriptScope() { return this->noScriptScope; }
  1073. void SetPendingFinallyException(Js::JavascriptExceptionObject * exceptionObj)
  1074. {
  1075. recyclableData->pendingFinallyException = exceptionObj;
  1076. }
  1077. Js::JavascriptExceptionObject * GetPendingFinallyException()
  1078. {
  1079. return recyclableData->pendingFinallyException;
  1080. }
  1081. Js::EntryPointInfo ** RegisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo * entryPoint);
  1082. void UnregisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo ** entryPoint);
  1083. void RegisterProtoInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  1084. void RegisterStoreFieldInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  1085. void NotifyInlineCacheBatchUnregistered(uint count);
  1086. #if DBG
  1087. bool IsProtoInlineCacheRegistered(const Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  1088. bool IsStoreFieldInlineCacheRegistered(const Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  1089. #endif
  1090. #if ENABLE_NATIVE_CODEGEN
  1091. Js::PropertyGuard* RegisterSharedPropertyGuard(Js::PropertyId propertyId);
  1092. void RegisterLazyBailout(Js::PropertyId propertyId, Js::EntryPointInfo* entryPoint);
  1093. void RegisterUniquePropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard* guard);
  1094. void RegisterUniquePropertyGuard(Js::PropertyId propertyId, RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef);
  1095. void RegisterConstructorCache(Js::PropertyId propertyId, Js::ConstructorCache* cache);
  1096. #endif
  1097. virtual size_t GetScriptStackLimit() const override;
  1098. virtual HANDLE GetProcessHandle() const override;
  1099. virtual intptr_t GetThreadStackLimitAddr() const override;
  1100. #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_WASM_SIMD)
  1101. virtual intptr_t GetSimdTempAreaAddr(uint8 tempIndex) const override;
  1102. #endif
  1103. virtual intptr_t GetDisableImplicitFlagsAddr() const override;
  1104. virtual intptr_t GetImplicitCallFlagsAddr() const override;
  1105. virtual ptrdiff_t GetChakraBaseAddressDifference() const override;
  1106. virtual ptrdiff_t GetCRTBaseAddressDifference() const override;
  1107. private:
  1108. void RegisterInlineCache(InlineCacheListMapByPropertyId& inlineCacheMap, Js::InlineCache* inlineCache, Js::PropertyId propertyId);
  1109. static bool IsInlineCacheRegistered(InlineCacheListMapByPropertyId& inlineCacheMap, const Js::InlineCache* inlineCache, Js::PropertyId propertyId);
  1110. void InvalidateAndDeleteInlineCacheList(InlineCacheList *inlineCacheList);
  1111. void CompactInlineCacheList(InlineCacheList *inlineCacheList);
  1112. void CompactInlineCacheInvalidationLists();
  1113. void CompactProtoInlineCaches();
  1114. void CompactStoreFieldInlineCaches();
  1115. #if DBG
  1116. static bool IsInlineCacheInList(const Js::InlineCache* inlineCache, const InlineCacheList* inlineCacheChain);
  1117. #endif
  1118. #if ENABLE_NATIVE_CODEGEN
  1119. void InvalidateFixedFieldGuard(Js::PropertyGuard* guard);
  1120. PropertyGuardEntry* EnsurePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, bool& foundExistingEntry);
  1121. void InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry, bool isAllPropertyGuardsInvalidation);
  1122. #endif
  1123. public:
  1124. class AutoDisableExpiration
  1125. {
  1126. public:
  1127. AutoDisableExpiration(ThreadContext* threadContext):
  1128. _threadContext(threadContext),
  1129. _oldExpirationDisabled(threadContext->disableExpiration)
  1130. {
  1131. _threadContext->disableExpiration = true;
  1132. }
  1133. ~AutoDisableExpiration()
  1134. {
  1135. _threadContext->disableExpiration = _oldExpirationDisabled;
  1136. }
  1137. private:
  1138. ThreadContext* _threadContext;
  1139. bool _oldExpirationDisabled;
  1140. };
  1141. void InvalidateProtoInlineCaches(Js::PropertyId propertyId);
  1142. void InvalidateStoreFieldInlineCaches(Js::PropertyId propertyId);
  1143. void InvalidateAllProtoInlineCaches();
  1144. #if DBG
  1145. bool IsObjectRegisteredInProtoInlineCaches(Js::DynamicObject * object);
  1146. bool IsObjectRegisteredInStoreFieldInlineCaches(Js::DynamicObject * object);
  1147. #endif
  1148. bool AreAllProtoInlineCachesInvalidated();
  1149. void InvalidateAllStoreFieldInlineCaches();
  1150. bool AreAllStoreFieldInlineCachesInvalidated();
  1151. void InvalidatePropertyGuards(Js::PropertyId propertyId);
  1152. void InvalidateAllPropertyGuards();
  1153. void RegisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1154. void UnregisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1155. #if DBG
  1156. bool IsIsInstInlineCacheRegistered(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1157. #endif
  1158. private:
  1159. void InvalidateIsInstInlineCacheList(Js::IsInstInlineCache* inlineCacheList);
  1160. #if DBG
  1161. bool IsIsInstInlineCacheInList(const Js::IsInstInlineCache* inlineCache, const Js::IsInstInlineCache* inlineCacheList);
  1162. #endif
  1163. public:
  1164. void InvalidateIsInstInlineCachesForFunction(Js::Var function);
  1165. void InvalidateAllIsInstInlineCaches();
  1166. bool AreAllIsInstInlineCachesInvalidated() const;
  1167. #ifdef PERSISTENT_INLINE_CACHES
  1168. void ClearInlineCachesWithDeadWeakRefs();
  1169. #endif
  1170. void ClearInvalidatedUniqueGuards();
  1171. void ClearInlineCaches();
  1172. void ClearIsInstInlineCaches();
  1173. void ClearEnumeratorCaches();
  1174. void ClearEquivalentTypeCaches();
  1175. void ClearScriptContextCaches();
  1176. void RegisterTypeWithProtoPropertyCache(const Js::PropertyId propertyId, Js::Type *const type);
  1177. void InvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId);
  1178. void InternalInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId);
  1179. void InvalidateAllProtoTypePropertyCaches();
  1180. BOOL HasUnhandledException() const { return hasUnhandledException; }
  1181. void SetHasUnhandledException() {hasUnhandledException = TRUE; }
  1182. void ResetHasUnhandledException() {hasUnhandledException = FALSE; }
  1183. void SetUnhandledExceptionObject(Js::JavascriptExceptionObject* exceptionObject) {recyclableData->unhandledExceptionObject = exceptionObject; }
  1184. Js::JavascriptExceptionObject* GetUnhandledExceptionObject() const { return recyclableData->unhandledExceptionObject; };
  1185. // To temporarily keep throwing exception object alive (thrown but not yet caught)
  1186. void SaveTempUncaughtException(Js::JavascriptExceptionObject* exceptionObject)
  1187. {
  1188. Js::JavascriptExceptionObject::Insert(&recyclableData->tempUncaughtException, exceptionObject);
  1189. }
  1190. void ClearTempUncaughtException(Js::JavascriptExceptionObject* exceptionObject)
  1191. {
  1192. Js::JavascriptExceptionObject::Remove(&recyclableData->tempUncaughtException, exceptionObject);
  1193. }
  1194. public:
  1195. bool HasCatchHandler() const { return hasCatchHandler; }
  1196. void SetHasCatchHandler(bool hasCatchHandler) { this->hasCatchHandler = hasCatchHandler; }
  1197. bool IsUserCode() const { return this->hasCatchHandlerToUserCode; }
  1198. void SetIsUserCode(bool set) { this->hasCatchHandlerToUserCode = set; }
  1199. void QueueFreeOldEntryPointInfoIfInScript(Js::FunctionEntryPointInfo* oldEntryPointInfo)
  1200. {
  1201. if (this->IsInScript())
  1202. {
  1203. // Add it to the list only if it's not already in it
  1204. if (oldEntryPointInfo->nextEntryPoint == nullptr && !oldEntryPointInfo->IsCleanedUp())
  1205. {
  1206. oldEntryPointInfo->nextEntryPoint = recyclableData->oldEntryPointInfo;
  1207. recyclableData->oldEntryPointInfo = oldEntryPointInfo;
  1208. }
  1209. }
  1210. }
  1211. bool IsOldEntryPointInfo(Js::ProxyEntryPointInfo* entryPointInfo)
  1212. {
  1213. Js::FunctionEntryPointInfo* current = this->recyclableData->oldEntryPointInfo;
  1214. while (current != nullptr)
  1215. {
  1216. if (current == entryPointInfo)
  1217. return true;
  1218. current = current->nextEntryPoint;
  1219. }
  1220. return false;
  1221. }
  1222. static bool IsOnStack(void const *ptr);
  1223. _NOINLINE bool IsStackAvailable(size_t size, bool* isInterrupt = nullptr);
  1224. _NOINLINE bool IsStackAvailableNoThrow(size_t size = Js::Constants::MinStackDefault);
  1225. static bool IsCurrentStackAvailable(size_t size);
  1226. void ProbeStackNoDispose(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress = nullptr);
  1227. void ProbeStack(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress = nullptr);
  1228. void ProbeStack(size_t size, Js::RecyclableObject * obj, Js::ScriptContext *scriptContext);
  1229. void ProbeStack(size_t size);
  1230. static void __stdcall ProbeCurrentStackNoDispose(size_t size, Js::ScriptContext *scriptContext);
  1231. static void __stdcall ProbeCurrentStack(size_t size, Js::ScriptContext *scriptContext);
  1232. static void __stdcall ProbeCurrentStack2(size_t size, Js::ScriptContext *scriptContext, uint32 u1, uint32 u2)
  1233. {
  1234. ProbeCurrentStack(size, scriptContext);
  1235. }
  1236. #if ENABLE_PROFILE_INFO
  1237. void EnsureSourceProfileManagersByUrlMap();
  1238. Js::SourceDynamicProfileManager* GetSourceDynamicProfileManager(_In_z_ const WCHAR* url, _In_ uint hash, _Inout_ bool* addref);
  1239. uint ReleaseSourceDynamicProfileManagers(const WCHAR* url);
  1240. #endif
  1241. void EnsureSymbolRegistrationMap();
  1242. const Js::PropertyRecord* GetSymbolFromRegistrationMap(const char16* stringKey, charcount_t stringLength);
  1243. const Js::PropertyRecord* AddSymbolToRegistrationMap(const char16* stringKey, charcount_t stringLength);
  1244. #if ENABLE_TTD
  1245. JsUtil::BaseDictionary<Js::HashedCharacterBuffer<char16>*, const Js::PropertyRecord*, Recycler, PowerOf2SizePolicy, Js::PropertyRecordStringHashComparer>* GetSymbolRegistrationMap_TTD();
  1246. #endif
  1247. inline void ClearPendingSOError()
  1248. {
  1249. this->GetPendingSOErrorObject()->ClearError();
  1250. }
  1251. inline void ClearPendingOOMError()
  1252. {
  1253. this->GetPendingOOMErrorObject()->ClearError();
  1254. }
  1255. Js::JavascriptExceptionObject *GetPendingSOErrorObject()
  1256. {
  1257. Assert(recyclableData->soErrorObject.IsPendingExceptionObject());
  1258. return &recyclableData->soErrorObject;
  1259. }
  1260. Js::JavascriptExceptionObject *GetPendingOOMErrorObject()
  1261. {
  1262. Assert(recyclableData->oomErrorObject.IsPendingExceptionObject());
  1263. return &recyclableData->oomErrorObject;
  1264. }
  1265. Js::JavascriptExceptionObject *GetPendingTerminatedErrorObject()
  1266. {
  1267. return &recyclableData->terminatedErrorObject;
  1268. }
  1269. Js::JavascriptExceptionObject* GetRecordedException()
  1270. {
  1271. return recyclableData->exceptionObject;
  1272. }
  1273. bool GetPropagateException()
  1274. {
  1275. return recyclableData->propagateException;
  1276. }
  1277. void SetHasThrownPendingException()
  1278. {
  1279. Assert(this->IsInScript());
  1280. this->hasThrownPendingException = true;
  1281. }
  1282. bool * GetHasBailedOutBitPtr()
  1283. {
  1284. return this->hasBailedOutBitPtr;
  1285. }
  1286. void SetHasBailedOutBitPtr(bool *setValue)
  1287. {
  1288. this->hasBailedOutBitPtr = setValue;
  1289. }
  1290. void SetRecordedException(Js::JavascriptExceptionObject* exceptionObject, bool propagateToDebugger = false)
  1291. {
  1292. this->recyclableData->exceptionObject = exceptionObject;
  1293. this->recyclableData->propagateException = propagateToDebugger;
  1294. }
  1295. #ifdef ENABLE_CUSTOM_ENTROPY
  1296. Entropy& GetEntropy()
  1297. {
  1298. return entropy;
  1299. }
  1300. #endif
  1301. Js::ImplicitCallFlags * GetAddressOfImplicitCallFlags()
  1302. {
  1303. return &implicitCallFlags;
  1304. }
  1305. DisableImplicitFlags * GetAddressOfDisableImplicitFlags()
  1306. {
  1307. return &disableImplicitFlags;
  1308. }
  1309. Js::ImplicitCallFlags GetImplicitCallFlags()
  1310. {
  1311. return implicitCallFlags;
  1312. }
  1313. void SetImplicitCallFlags(Js::ImplicitCallFlags flags)
  1314. {
  1315. //Note: this action is inlined into JITed code in Lowerer::GenerateCallProfiling.
  1316. // if you change this, you might want to add it there too.
  1317. implicitCallFlags = flags;
  1318. }
  1319. void ClearImplicitCallFlags();
  1320. void ClearImplicitCallFlags(Js::ImplicitCallFlags flags);
  1321. void AddImplicitCallFlags(Js::ImplicitCallFlags flags)
  1322. {
  1323. SetImplicitCallFlags((Js::ImplicitCallFlags)(implicitCallFlags | flags));
  1324. }
  1325. void CheckAndResetImplicitCallAccessorFlag();
  1326. template <class Fn>
  1327. inline Js::Var ExecuteImplicitCall(Js::RecyclableObject * function, Js::ImplicitCallFlags flags, Fn implicitCall)
  1328. {
  1329. AutoReentrancyHandler autoReentrancyHandler(this);
  1330. Js::FunctionInfo::Attributes attributes = Js::FunctionInfo::GetAttributes(function);
  1331. // we can hoist out const method if we know the function doesn't have side effect,
  1332. // and the value can be hoisted.
  1333. if (this->HasNoSideEffect(function, attributes))
  1334. {
  1335. // Has no side effect means the function does not change global value or
  1336. // will check for implicit call flags
  1337. Js::Var result = implicitCall();
  1338. // If the value is on stack we need to bailout so that it can be boxed.
  1339. // Instead of putting this in valueOf (or other builtins which have no side effect) adding
  1340. // the check here to cover any other scenario we might miss.
  1341. if (IsOnStack(result))
  1342. {
  1343. AddImplicitCallFlags(flags);
  1344. }
  1345. return result;
  1346. }
  1347. // Don't call the implicit call if disable implicit call
  1348. if (IsDisableImplicitCall())
  1349. {
  1350. AddImplicitCallFlags(flags);
  1351. // Return "undefined" just so we have a valid var, in case subsequent instructions are executed
  1352. // before we bail out.
  1353. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1354. }
  1355. if ((attributes & Js::FunctionInfo::HasNoSideEffect) != 0)
  1356. {
  1357. // Has no side effect means the function does not change global value or
  1358. // will check for implicit call flags
  1359. Js::Var result = implicitCall();
  1360. // If the value is on stack we need to bailout so that it can be boxed.
  1361. // Instead of putting this in valueOf (or other builtins which have no side effect) adding
  1362. // the check here to cover any other scenario we might miss.
  1363. if (IsOnStack(result))
  1364. {
  1365. AddImplicitCallFlags(flags);
  1366. }
  1367. return result;
  1368. }
  1369. // Save and restore implicit flags around the implicit call
  1370. struct RestoreFlags
  1371. {
  1372. ThreadContext * const ctx;
  1373. const Js::ImplicitCallFlags flags;
  1374. const Js::ImplicitCallFlags savedFlags;
  1375. RestoreFlags(ThreadContext *ctx, Js::ImplicitCallFlags flags) :
  1376. ctx(ctx),
  1377. flags(flags),
  1378. savedFlags(ctx->GetImplicitCallFlags())
  1379. {
  1380. }
  1381. ~RestoreFlags()
  1382. {
  1383. ctx->SetImplicitCallFlags(static_cast<Js::ImplicitCallFlags>(savedFlags | flags));
  1384. }
  1385. };
  1386. RestoreFlags restoreFlags(this, flags);
  1387. return implicitCall();
  1388. }
  1389. bool HasNoSideEffect(Js::RecyclableObject * function) const;
  1390. bool HasNoSideEffect(Js::RecyclableObject * function, Js::FunctionInfo::Attributes attr) const;
  1391. bool RecordImplicitException();
  1392. DisableImplicitFlags GetDisableImplicitFlags() const { return disableImplicitFlags; }
  1393. void SetDisableImplicitFlags(DisableImplicitFlags flags) { disableImplicitFlags = flags; }
  1394. bool IsDisableImplicitCall() const { return (disableImplicitFlags & DisableImplicitCallFlag) != 0; }
  1395. bool IsDisableImplicitException() const { return (disableImplicitFlags & DisableImplicitExceptionFlag) != 0; }
  1396. void DisableImplicitCall() { disableImplicitFlags = (DisableImplicitFlags)(disableImplicitFlags | DisableImplicitCallFlag); }
  1397. void ClearDisableImplicitFlags() { disableImplicitFlags = DisableImplicitNoFlag; }
  1398. virtual uint GetRandomNumber() override;
  1399. virtual bool DoSpecialMarkOnScanStack() override { return this->DoRedeferFunctionBodies(); }
  1400. virtual void OnScanStackCallback(void ** stackTop, size_t byteCount, void ** registers, size_t registersByteCount) override;
  1401. virtual void PostSweepRedeferralCallBack() override;
  1402. // DefaultCollectWrapper
  1403. virtual void PreCollectionCallBack(CollectionFlags flags) override;
  1404. virtual void PreSweepCallback() override;
  1405. virtual void PreRescanMarkCallback() override;
  1406. virtual void WaitCollectionCallBack() override;
  1407. virtual void PostCollectionCallBack() override;
  1408. virtual BOOL ExecuteRecyclerCollectionFunction(Recycler * recycler, CollectionFunction function, CollectionFlags flags) override;
  1409. #ifdef FAULT_INJECTION
  1410. virtual void DisposeScriptContextByFaultInjectionCallBack() override;
  1411. #endif
  1412. virtual void DisposeObjects(Recycler * recycler) override;
  1413. virtual void PreDisposeObjectsCallBack() override;
  1414. void DoExpirableCollectModeStackWalk();
  1415. typedef DList<ExpirableObject*, ArenaAllocator> ExpirableObjectList;
  1416. ExpirableObjectList* expirableObjectList;
  1417. ExpirableObjectList* expirableObjectDisposeList;
  1418. int numExpirableObjects;
  1419. int expirableCollectModeGcCount;
  1420. bool disableExpiration;
  1421. bool callDispose;
  1422. bool InExpirableCollectMode();
  1423. void TryEnterExpirableCollectMode();
  1424. void TryExitExpirableCollectMode();
  1425. void RegisterExpirableObject(ExpirableObject* object);
  1426. void UnregisterExpirableObject(ExpirableObject* object);
  1427. void * GetDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType);
  1428. void AddDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType, void * cache);
  1429. public:
  1430. bool IsScriptActive() const { return isScriptActive; }
  1431. void SetIsScriptActive(bool isActive) { isScriptActive = isActive; }
  1432. bool IsExecutionDisabled() const
  1433. {
  1434. return this->GetStackLimitForCurrentThread() == Js::Constants::StackLimitForScriptInterrupt;
  1435. }
  1436. void DisableExecution();
  1437. void EnableExecution();
  1438. bool TestThreadContextFlag(ThreadContextFlags threadContextFlag) const;
  1439. void SetThreadContextFlag(ThreadContextFlags threadContextFlag);
  1440. void ClearThreadContextFlag(ThreadContextFlags threadContextFlag);
  1441. void SetForceOneIdleCollection();
  1442. bool IsInThreadServiceCallback() const { return threadService.IsInCallback(); }
  1443. #ifdef ENABLE_SCRIPT_DEBUGGING
  1444. Js::DebugManager * GetDebugManager() const { return this->debugManager; }
  1445. #endif
  1446. const NativeLibraryEntryRecord::Entry* PeekNativeLibraryEntry() const { return this->nativeLibraryEntry.Peek(); }
  1447. void PushNativeLibraryEntry(_In_ NativeLibraryEntryRecord::Entry* entry) { this->nativeLibraryEntry.Push(entry); }
  1448. void PopNativeLibraryEntry() { this->nativeLibraryEntry.Pop(); }
  1449. bool IsProfilingUserCode() const { return isProfilingUserCode; }
  1450. void SetIsProfilingUserCode(bool value) { isProfilingUserCode = value; }
  1451. #if DBG_DUMP
  1452. uint scriptSiteCount;
  1453. #endif
  1454. #ifdef BAILOUT_INJECTION
  1455. uint bailOutByteCodeLocationCount;
  1456. #endif
  1457. #ifdef DYNAMIC_PROFILE_MUTATOR
  1458. DynamicProfileMutator * dynamicProfileMutator;
  1459. #endif
  1460. //
  1461. // Regex helpers
  1462. //
  1463. UnifiedRegex::StandardChars<uint8>* GetStandardChars(__inout_opt uint8* dummy);
  1464. UnifiedRegex::StandardChars<char16>* GetStandardChars(__inout_opt char16* dummy);
  1465. bool IsOptimizedForManyInstances() const { return isOptimizedForManyInstances; }
  1466. void OptimizeForManyInstances(const bool optimizeForManyInstances)
  1467. {
  1468. Assert(!recycler || optimizeForManyInstances == isOptimizedForManyInstances); // mode cannot be changed after recycler is created
  1469. isOptimizedForManyInstances = optimizeForManyInstances;
  1470. }
  1471. #if ENABLE_NATIVE_CODEGEN
  1472. bool IsBgJitEnabled() const { return bgJit; }
  1473. void EnableBgJit(const bool enableBgJit)
  1474. {
  1475. Assert(!jobProcessor || enableBgJit == bgJit);
  1476. bgJit = enableBgJit;
  1477. }
  1478. #endif
  1479. void* GetJSRTRuntime() const { return jsrtRuntime; }
  1480. void SetJSRTRuntime(void* runtime);
  1481. private:
  1482. BOOL ExecuteRecyclerCollectionFunctionCommon(Recycler * recycler, CollectionFunction function, CollectionFlags flags);
  1483. void DoInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId, TypeHashSet *const typeHashSet);
  1484. void InitializePropertyMaps();
  1485. void CreateNoCasePropertyMap();
  1486. InterruptPoller *interruptPoller;
  1487. void CollectionCallBack(RecyclerCollectCallBackFlags flags);
  1488. // Cache used by HostDispatch::GetBuiltInOperationFromEntryPoint
  1489. private:
  1490. JsUtil::BaseDictionary<Js::JavascriptMethod, uint, ArenaAllocator, PowerOf2SizePolicy> entryPointToBuiltInOperationIdCache;
  1491. #if ENABLE_JS_REENTRANCY_CHECK
  1492. public:
  1493. void SetNoJsReentrancy(bool val) { noJsReentrancy = val; }
  1494. bool GetNoJsReentrancy() { return noJsReentrancy; }
  1495. void AssertJsReentrancy()
  1496. {
  1497. if (GetNoJsReentrancy())
  1498. {
  1499. Js::Throw::FatalJsReentrancyError();
  1500. }
  1501. }
  1502. #else
  1503. void AssertJsReentrancy() {}
  1504. #endif
  1505. public:
  1506. void CheckAndResetReentrancySafeOrHandled()
  1507. {
  1508. AssertOrFailFast(reentrancySafeOrHandled || isInReentrancySafeRegion);
  1509. SetReentrancySafeOrHandled(false);
  1510. }
  1511. void SetReentrancySafeOrHandled(bool val) { reentrancySafeOrHandled = val; }
  1512. bool GetReentrancySafeOrHandled() { return reentrancySafeOrHandled; }
  1513. void SetIsInReentrancySafeRegion(bool val) { isInReentrancySafeRegion = val; }
  1514. bool GetIsInReentrancySafeRegion() { return isInReentrancySafeRegion; }
  1515. template <typename Fn>
  1516. Js::Var SafeReentrantCall(Fn fn)
  1517. {
  1518. AutoReentrancyHandler autoReentrancyHandler(this);
  1519. return fn();
  1520. }
  1521. bool IsEntryPointToBuiltInOperationIdCacheInitialized()
  1522. {
  1523. return entryPointToBuiltInOperationIdCache.Count() != 0;
  1524. }
  1525. bool GetBuiltInOperationIdFromEntryPoint(Js::JavascriptMethod entryPoint, uint * id)
  1526. {
  1527. return entryPointToBuiltInOperationIdCache.TryGetValue(entryPoint, id);
  1528. }
  1529. void SetBuiltInOperationIdForEntryPoint(Js::JavascriptMethod entryPoint, uint id)
  1530. {
  1531. entryPointToBuiltInOperationIdCache.Add(entryPoint, id);
  1532. }
  1533. void ResetEntryPointToBuiltInOperationIdCache()
  1534. {
  1535. entryPointToBuiltInOperationIdCache.ResetNoDelete();
  1536. }
  1537. uint8 LoopDepth() const
  1538. {
  1539. return loopDepth;
  1540. }
  1541. void SetLoopDepth(const uint8 loopDepth)
  1542. {
  1543. this->loopDepth = loopDepth;
  1544. }
  1545. void IncrementLoopDepth()
  1546. {
  1547. if(loopDepth != UCHAR_MAX)
  1548. {
  1549. ++loopDepth;
  1550. }
  1551. }
  1552. void DecrementLoopDepth()
  1553. {
  1554. if(loopDepth != 0)
  1555. {
  1556. --loopDepth;
  1557. }
  1558. }
  1559. #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
  1560. static void ReportAndCheckLeaksOnProcessDetach();
  1561. #endif
  1562. #ifdef LEAK_REPORT
  1563. void SetRootTrackerScriptContext(Js::ScriptContext * scriptContext);
  1564. void ClearRootTrackerScriptContext(Js::ScriptContext * scriptContext);
  1565. private:
  1566. Js::ScriptContext * rootTrackerScriptContext;
  1567. DWORD threadId;
  1568. #endif
  1569. private:
  1570. class ThreadContextRecyclerTelemetryHostInterface : public RecyclerTelemetryHostInterface
  1571. {
  1572. public:
  1573. ThreadContextRecyclerTelemetryHostInterface(ThreadContext* tc) :
  1574. tc(tc)
  1575. {
  1576. }
  1577. virtual LPFILETIME GetLastScriptExecutionEndTime() const;
  1578. virtual bool TransmitGCTelemetryStats(RecyclerTelemetryInfo& rti);
  1579. virtual bool TransmitTelemetryError(const RecyclerTelemetryInfo& rti, const char * msg);
  1580. virtual bool TransmitHeapUsage(size_t totalHeapBytes, size_t usedHeapBytes, double heapUsedRatio);
  1581. virtual bool ThreadContextRecyclerTelemetryHostInterface::IsThreadBound() const;
  1582. virtual DWORD ThreadContextRecyclerTelemetryHostInterface::GetCurrentScriptThreadID() const;
  1583. virtual bool IsTelemetryProviderEnabled() const;
  1584. virtual uint GetClosedContextCount() const;
  1585. private:
  1586. ThreadContext * tc;
  1587. };
  1588. ThreadContextRecyclerTelemetryHostInterface recyclerTelemetryHostInterface;
  1589. };
  1590. extern void(*InitializeAdditionalProperties)(ThreadContext *threadContext);
  1591. // This is for protecting a region of code, where we can't recover and be consistent upon failures (mainly due to OOM and SO).
  1592. // FailFast on that.
  1593. class AutoDisableInterrupt
  1594. {
  1595. public:
  1596. AutoDisableInterrupt(ThreadContext *threadContext, bool explicitCompletion = true)
  1597. : m_operationCompleted(false), m_interruptDisableState(false), m_threadContext(threadContext), m_explicitCompletion(explicitCompletion)
  1598. {
  1599. if (m_threadContext->HasInterruptPoller())
  1600. {
  1601. m_interruptDisableState = m_threadContext->GetInterruptPoller()->IsDisabled();
  1602. m_threadContext->GetInterruptPoller()->SetDisabled(true);
  1603. }
  1604. }
  1605. ~AutoDisableInterrupt()
  1606. {
  1607. if (m_threadContext->HasInterruptPoller())
  1608. {
  1609. m_threadContext->GetInterruptPoller()->SetDisabled(m_interruptDisableState);
  1610. }
  1611. if (m_explicitCompletion && !m_operationCompleted)
  1612. {
  1613. AssertOrFailFast(false);
  1614. }
  1615. }
  1616. void RequireExplicitCompletion() { m_explicitCompletion = true; }
  1617. void Completed() { m_operationCompleted = true; }
  1618. private:
  1619. ThreadContext * m_threadContext;
  1620. bool m_operationCompleted;
  1621. bool m_interruptDisableState;
  1622. bool m_explicitCompletion;
  1623. };
  1624. class AutoReentrancyHandler
  1625. {
  1626. ThreadContext * m_threadContext;
  1627. bool m_savedReentrancySafeOrHandled;
  1628. public:
  1629. AutoReentrancyHandler(ThreadContext * threadContext)
  1630. {
  1631. m_threadContext = threadContext;
  1632. m_savedReentrancySafeOrHandled = threadContext->GetReentrancySafeOrHandled();
  1633. threadContext->SetReentrancySafeOrHandled(true);
  1634. }
  1635. ~AutoReentrancyHandler()
  1636. {
  1637. m_threadContext->SetReentrancySafeOrHandled(m_savedReentrancySafeOrHandled);
  1638. }
  1639. };
  1640. class AutoReentrancySafeRegion
  1641. {
  1642. ThreadContext * m_threadContext;
  1643. bool m_savedIsInReentrancySafeRegion;
  1644. public:
  1645. AutoReentrancySafeRegion(ThreadContext * threadContext)
  1646. {
  1647. m_threadContext = threadContext;
  1648. m_savedIsInReentrancySafeRegion = threadContext->GetIsInReentrancySafeRegion();
  1649. threadContext->SetIsInReentrancySafeRegion(true);
  1650. }
  1651. ~AutoReentrancySafeRegion()
  1652. {
  1653. m_threadContext->SetIsInReentrancySafeRegion(m_savedIsInReentrancySafeRegion);
  1654. }
  1655. };
  1656. #if ENABLE_JS_REENTRANCY_CHECK
  1657. class JsReentLock
  1658. {
  1659. ThreadContext *m_threadContext;
  1660. #if DBG
  1661. Js::Var m_arrayObject;
  1662. Js::Var m_arrayObject2; // This is for adding the second object in the mutation equation.
  1663. #endif
  1664. bool m_savedNoJsReentrancy;
  1665. public:
  1666. JsReentLock(ThreadContext *threadContext)
  1667. #if DBG
  1668. : m_arrayObject(nullptr), m_arrayObject2(nullptr)
  1669. #endif
  1670. {
  1671. m_savedNoJsReentrancy = threadContext->GetNoJsReentrancy();
  1672. threadContext->SetNoJsReentrancy(true);
  1673. m_threadContext = threadContext;
  1674. }
  1675. void unlock() { m_threadContext->SetNoJsReentrancy(m_savedNoJsReentrancy); }
  1676. void relock() { m_threadContext->SetNoJsReentrancy(true); }
  1677. #if DBG
  1678. void setObjectForMutation(Js::Var object);
  1679. void setSecondObjectForMutation(Js::Var object);
  1680. void MutateArrayObject();
  1681. #endif
  1682. ~JsReentLock()
  1683. {
  1684. m_threadContext->SetNoJsReentrancy(m_savedNoJsReentrancy);
  1685. }
  1686. #if DBG
  1687. private:
  1688. static void MutateArrayObject(Js::Var arrayObject);
  1689. #endif
  1690. };
  1691. #endif