ThreadContext.h 76 KB

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