ThreadContext.h 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679
  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 DebugManager;
  11. class CodeGenRecyclableData;
  12. struct ReturnedValue;
  13. typedef JsUtil::List<ReturnedValue*> ReturnedValueList;
  14. }
  15. struct IAuthorFileContext;
  16. class HostScriptContext;
  17. class ScriptSite;
  18. class ThreadServiceWrapper;
  19. struct IActiveScriptProfilerHeapEnum;
  20. class DynamicProfileMutator;
  21. class StackProber;
  22. enum DisableImplicitFlags : BYTE
  23. {
  24. DisableImplicitNoFlag = 0x00,
  25. DisableImplicitCallFlag = 0x01,
  26. DisableImplicitExceptionFlag = 0x02,
  27. DisableImplicitCallAndExceptionFlag = DisableImplicitCallFlag | DisableImplicitExceptionFlag
  28. };
  29. enum ThreadContextFlags
  30. {
  31. ThreadContextFlagNoFlag = 0x00000000,
  32. ThreadContextFlagCanDisableExecution = 0x00000001,
  33. ThreadContextFlagEvalDisabled = 0x00000002,
  34. ThreadContextFlagNoJIT = 0x00000004,
  35. };
  36. const int LS_MAX_STACK_SIZE_KB = 300;
  37. struct IProjectionContext
  38. {
  39. public:
  40. virtual HRESULT Close() = 0;
  41. };
  42. class ThreadContext;
  43. class InterruptPoller abstract
  44. {
  45. // Interface with a polling object located in the hosting layer.
  46. public:
  47. InterruptPoller(ThreadContext *tc);
  48. void CheckInterruptPoll();
  49. void GetStatementCount(ULONG *pluHi, ULONG *pluLo);
  50. void ResetStatementCount() { lastResetTick = lastPollTick; }
  51. void StartScript() { lastResetTick = lastPollTick = ::GetTickCount(); }
  52. void EndScript() { lastResetTick = lastPollTick = 0;}
  53. bool IsDisabled() const { return isDisabled; }
  54. void SetDisabled(bool disable) { isDisabled = disable; }
  55. virtual void TryInterruptPoll(Js::ScriptContext *scriptContext) = 0;
  56. // Default: throw up QC dialog after 5M statements == 2 minutes
  57. static const DWORD TicksToStatements = (5000000 / 120000);
  58. protected:
  59. ThreadContext *threadContext;
  60. DWORD lastPollTick;
  61. DWORD lastResetTick;
  62. bool isDisabled;
  63. };
  64. class AutoDisableInterrupt
  65. {
  66. private:
  67. InterruptPoller* interruptPoller;
  68. bool previousState;
  69. public:
  70. AutoDisableInterrupt(InterruptPoller* interruptPoller, bool disable)
  71. : interruptPoller(interruptPoller)
  72. {
  73. if (interruptPoller != nullptr)
  74. {
  75. previousState = interruptPoller->IsDisabled();
  76. interruptPoller->SetDisabled(disable);
  77. }
  78. }
  79. ~AutoDisableInterrupt()
  80. {
  81. if (interruptPoller != nullptr)
  82. {
  83. interruptPoller->SetDisabled(previousState);
  84. }
  85. }
  86. };
  87. // This function is called before we step out of script (currently only for WinRT callout).
  88. // Debugger would put a breakpoint on this function if they want to detect the point at which we step
  89. // over the boundary.
  90. // It is intentionally left blank and the next operation should be the callout.
  91. extern "C" void* MarkerForExternalDebugStep();
  92. #define PROBE_STACK(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext))
  93. #define PROBE_STACK_NO_DISPOSE(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStackNoDispose(size, scriptContext))
  94. #define PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(scriptContext, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext, _ReturnAddress()))
  95. #define PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(scriptContext, size, returnAddress) ((scriptContext)->GetThreadContext()->ProbeStack(size, scriptContext, returnAddress))
  96. #define PROBE_STACK_CALL(scriptContext, obj, size) ((scriptContext)->GetThreadContext()->ProbeStack(size, obj, scriptContext))
  97. #define AssertInScript() Assert(ThreadContext::GetContextForCurrentThread()->IsScriptActive());
  98. #define AssertNotInScript() Assert(!ThreadContext::GetContextForCurrentThread()->IsScriptActive());
  99. #define LEAVE_SCRIPT_START_EX(scriptContext, stackProbe, leaveForHost, isFPUControlRestoreNeeded) \
  100. { \
  101. void * __frameAddr = nullptr; \
  102. GET_CURRENT_FRAME_ID(__frameAddr); \
  103. Js::LeaveScriptObject<stackProbe, leaveForHost, isFPUControlRestoreNeeded> __leaveScriptObject(scriptContext, __frameAddr);
  104. #define LEAVE_SCRIPT_END_EX(scriptContext) \
  105. if (scriptContext != nullptr) \
  106. { \
  107. scriptContext->GetThreadContext()->DisposeOnLeaveScript(); \
  108. }\
  109. }
  110. #define BEGIN_LEAVE_SCRIPT(scriptContext) \
  111. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ false)
  112. #define BEGIN_LEAVE_SCRIPT_SAVE_FPU_CONTROL(scriptContext) \
  113. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ true)
  114. // BEGIN_LEAVE_SCRIPT_INTERNAL is used when there are no explicit external call after leave script,
  115. // but we might have external call when allocation memory doing QC or GC Dispose, which may enter script again.
  116. // This will record the reentry as an implicit call (ImplicitCall_AsyncHostOperation)
  117. #define BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext) \
  118. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ true, /* leaveForHost */ false, /* isFPUControlRestoreNeeded */ false)
  119. #define BEGIN_LEAVE_SCRIPT_NO_STACK_PROBE(scriptContext) \
  120. LEAVE_SCRIPT_START_EX(scriptContext, /* stackProbe */ false, /* leaveForHost */ true, /* isFPUControlRestoreNeeded */ false)
  121. #define END_LEAVE_SCRIPT(scriptContext) \
  122. LEAVE_SCRIPT_END_EX(scriptContext)
  123. #define END_LEAVE_SCRIPT_RESTORE_FPU_CONTROL(scriptContext) \
  124. LEAVE_SCRIPT_END_EX(scriptContext)
  125. #define END_LEAVE_SCRIPT_INTERNAL(scriptContext) \
  126. LEAVE_SCRIPT_END_EX(scriptContext)
  127. #define END_LEAVE_SCRIPT_NO_STACK_PROBE(scriptContext) \
  128. LEAVE_SCRIPT_END_EX(scriptContext)
  129. #define BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) \
  130. BEGIN_LEAVE_SCRIPT(scriptContext)
  131. #define END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) \
  132. Assert(!scriptContext->HasRecordedException()); \
  133. END_LEAVE_SCRIPT(scriptContext)
  134. // Keep in sync with CollectGarbageCallBackFlags in scriptdirect.idl
  135. enum RecyclerCollectCallBackFlags
  136. {
  137. Collect_Begin = 0x01,
  138. Collect_Begin_Concurrent = 0x11,
  139. Collect_Begin_Partial = 0x21,
  140. Collect_Begin_Concurrent_Partial = Collect_Begin_Concurrent | Collect_Begin_Partial,
  141. Collect_End = 0x02,
  142. Collect_Wait = 0x04 // callback can be from another thread
  143. };
  144. typedef void (__cdecl *RecyclerCollectCallBackFunction)(void * context, RecyclerCollectCallBackFlags flags);
  145. // Keep in sync with WellKnownType in scriptdirect.idl
  146. typedef enum WellKnownHostType
  147. {
  148. WellKnownHostType_HTMLAllCollection = 0,
  149. WellKnownHostType_Last = WellKnownHostType_HTMLAllCollection,
  150. WellKnownHostType_Invalid = WellKnownHostType_Last+1
  151. } WellKnownHostType;
  152. #ifdef ENABLE_PROJECTION
  153. class ExternalWeakReferenceCache
  154. {
  155. public:
  156. virtual void MarkNow(Recycler *recycler, bool inPartialCollect) = 0;
  157. virtual void ResolveNow(Recycler *recycler) = 0;
  158. };
  159. #if DBG_DUMP
  160. class IProjectionContextMemoryInfo abstract
  161. {
  162. public:
  163. virtual void DumpCurrentStats(LPCWSTR headerMsg, bool forceDetailed) = 0;
  164. virtual void Release() = 0;
  165. };
  166. #endif
  167. #endif
  168. struct ThreadContextWatsonTelemetryBlock
  169. {
  170. FILETIME lastScriptStartTime;
  171. FILETIME lastScriptEndTime;
  172. };
  173. class NativeLibraryEntryRecord
  174. {
  175. public:
  176. struct Entry
  177. {
  178. Js::RecyclableObject* function;
  179. Js::CallInfo callInfo;
  180. PCWSTR name;
  181. PVOID addr;
  182. Entry* next;
  183. };
  184. private:
  185. Entry* head;
  186. public:
  187. NativeLibraryEntryRecord() : head(nullptr)
  188. {
  189. }
  190. const Entry* Peek() const
  191. {
  192. return head;
  193. }
  194. void Push(_In_ Entry* e)
  195. {
  196. e->next = head;
  197. head = e;
  198. }
  199. void Pop()
  200. {
  201. head = head->next;
  202. }
  203. };
  204. class AutoTagNativeLibraryEntry
  205. {
  206. private:
  207. NativeLibraryEntryRecord::Entry entry;
  208. public:
  209. AutoTagNativeLibraryEntry(Js::RecyclableObject* function, Js::CallInfo callInfo, PCWSTR name, void* addr);
  210. ~AutoTagNativeLibraryEntry();
  211. };
  212. struct JITStats
  213. {
  214. uint lessThan5ms;
  215. uint within5And10ms;
  216. uint within10And20ms;
  217. uint within20And50ms;
  218. uint within50And100ms;
  219. uint within100And300ms;
  220. uint greaterThan300ms;
  221. };
  222. struct ParserStats
  223. {
  224. uint64 lessThan1ms;
  225. uint64 within1And3ms;
  226. uint64 within3And10ms;
  227. uint64 within10And20ms;
  228. uint64 within20And50ms;
  229. uint64 within50And100ms;
  230. uint64 within100And300ms;
  231. uint64 greaterThan300ms;
  232. };
  233. class ParserTimer
  234. {
  235. private:
  236. Js::HiResTimer timer;
  237. ParserStats stats;
  238. public:
  239. ParserTimer();
  240. ParserStats GetStats();
  241. void Reset();
  242. double Now();
  243. void LogTime(double ms);
  244. };
  245. class JITTimer
  246. {
  247. private:
  248. Js::HiResTimer timer;
  249. JITStats stats;
  250. public:
  251. JITTimer();
  252. JITStats GetStats();
  253. void Reset();
  254. double Now();
  255. void LogTime(double ms);
  256. };
  257. #define AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, name) \
  258. AutoTagNativeLibraryEntry __tag(function, callInfo, name, _AddressOfReturnAddress())
  259. class ThreadConfiguration
  260. {
  261. public:
  262. ThreadConfiguration(bool enableExperimentalFeatures)
  263. {
  264. CopyGlobalFlags();
  265. if (enableExperimentalFeatures)
  266. {
  267. EnableExperimentalFeatures();
  268. }
  269. }
  270. #define DEFINE_FLAG(threadFlag, globalFlag) \
  271. public: \
  272. inline bool threadFlag() const { return m_##globalFlag##; } \
  273. \
  274. private: \
  275. bool m_##globalFlag##;
  276. #define FLAG(threadFlag, globalFlag) DEFINE_FLAG(threadFlag, globalFlag)
  277. #define FLAG_RELEASE(threadFlag, globalFlag) DEFINE_FLAG(threadFlag, globalFlag)
  278. #include "ThreadConfigFlagsList.h"
  279. #undef FLAG_RELEASE
  280. #undef FLAG
  281. #undef DEFINE_FLAG
  282. private:
  283. void CopyGlobalFlags()
  284. {
  285. AutoCriticalSection autocs(&Js::Configuration::Global.flags.csExperimentalFlags);
  286. #define FLAG(threadFlag, globalFlag) m_##globalFlag## = CONFIG_FLAG(globalFlag);
  287. #define FLAG_RELEASE(threadFlag, globalFlag) m_##globalFlag## = CONFIG_FLAG_RELEASE(globalFlag);
  288. #include "ThreadConfigFlagsList.h"
  289. #undef FLAG_RELEASE
  290. #undef FLAG
  291. }
  292. void EnableExperimentalFeatures()
  293. {
  294. #define FLAG_REGOVR_EXP(type, name, ...) m_##name## = true;
  295. #include "ConfigFlagsList.h"
  296. #undef FLAG_REGOVR_EXP
  297. }
  298. };
  299. class ThreadContext sealed :
  300. public DefaultRecyclerCollectionWrapper,
  301. public JsUtil::DoublyLinkedListElement<ThreadContext>
  302. {
  303. public:
  304. static void GlobalInitialize();
  305. static const DWORD NoThread = 0xFFFFFFFF;
  306. struct CollectCallBack
  307. {
  308. RecyclerCollectCallBackFunction callback;
  309. void * context;
  310. };
  311. struct WorkerThread
  312. {
  313. // Abstract notion to hold onto threadHandle of worker thread
  314. HANDLE threadHandle;
  315. WorkerThread(HANDLE handle = nullptr) :threadHandle(handle){};
  316. };
  317. void ReleasePreReservedSegment();
  318. void IncrementThreadContextsWithPreReservedSegment();
  319. void SetCurrentThreadId(DWORD threadId) { this->currentThreadId = threadId; }
  320. DWORD GetCurrentThreadId() const { return this->currentThreadId; }
  321. void SetIsThreadBound()
  322. {
  323. if (this->recycler)
  324. {
  325. this->recycler->SetIsThreadBound();
  326. }
  327. this->isThreadBound = true;
  328. }
  329. bool GetIsThreadBound() const { return this->isThreadBound; }
  330. void SetStackProber(StackProber * stackProber);
  331. PBYTE GetScriptStackLimit() const;
  332. static DWORD GetStackLimitForCurrentThreadOffset() { return offsetof(ThreadContext, stackLimitForCurrentThread); }
  333. void * GetAddressOfStackLimitForCurrentThread()
  334. {
  335. FAULTINJECT_SCRIPT_TERMINATION
  336. return &this->stackLimitForCurrentThread;
  337. }
  338. void InitAvailableCommit();
  339. // This is always on for JSRT APIs.
  340. bool IsRentalThreadingEnabledInJSRT() const { return true; }
  341. IActiveScriptProfilerHeapEnum* GetHeapEnum();
  342. void SetHeapEnum(IActiveScriptProfilerHeapEnum* newHeapEnum);
  343. void ClearHeapEnum();
  344. #ifdef ENABLE_BASIC_TELEMETRY
  345. Js::LanguageStats* GetLanguageStats()
  346. {
  347. return langTel.GetLanguageStats();
  348. }
  349. void ResetLangStats()
  350. {
  351. this->langTel.Reset();
  352. }
  353. #endif
  354. bool CanPreReserveSegmentForCustomHeap();
  355. #if ENABLE_NATIVE_CODEGEN
  356. // used by inliner. Maps Simd FuncInfo (library func) to equivalent opcode.
  357. typedef JsUtil::BaseDictionary<Js::FunctionInfo *, Js::OpCode, ArenaAllocator> FuncInfoToOpcodeMap;
  358. FuncInfoToOpcodeMap * simdFuncInfoToOpcodeMap;
  359. struct SimdFuncSignature
  360. {
  361. bool valid;
  362. uint argCount; // actual arguments count (excluding this)
  363. ValueType returnType;
  364. ValueType *args; // argument types
  365. };
  366. SimdFuncSignature *simdOpcodeToSignatureMap;
  367. void AddSimdFuncToMaps(Js::OpCode op, ...);
  368. void AddSimdFuncInfo(Js::OpCode op, Js::FunctionInfo *funcInfo);
  369. Js::OpCode GetSimdOpcodeFromFuncInfo(Js::FunctionInfo * funcInfo);
  370. void GetSimdFuncSignatureFromOpcode(Js::OpCode op, SimdFuncSignature &funcSignature);
  371. #endif
  372. private:
  373. bool noScriptScope;
  374. Js::DebugManager * debugManager;
  375. static uint const MaxTemporaryArenaAllocators = 5;
  376. static CriticalSection s_csThreadContext;
  377. StackProber * GetStackProber() const { return this->stackProber; }
  378. PBYTE GetStackLimitForCurrentThread() const;
  379. void SetStackLimitForCurrentThread(PBYTE limit);
  380. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  381. static uint numOfThreadContextsWithPreReserveSegment;
  382. #endif
  383. // The current heap enumeration object being used during enumeration.
  384. IActiveScriptProfilerHeapEnum* heapEnum;
  385. #ifdef ENABLE_BASIC_TELEMETRY
  386. Js::LanguageTelemetry langTel;
  387. #endif
  388. struct PropertyGuardEntry
  389. {
  390. public:
  391. typedef JsUtil::BaseHashSet<RecyclerWeakReference<Js::PropertyGuard>*, Recycler, PowerOf2SizePolicy> PropertyGuardHashSet;
  392. // we do not have WeaklyReferencedKeyHashSet - hence use BYTE as a dummy value.
  393. typedef JsUtil::WeaklyReferencedKeyDictionary<Js::EntryPointInfo, BYTE> EntryPointDictionary;
  394. // The sharedGuard is strongly referenced and will be kept alive by ThreadContext::propertyGuards until it's invalidated or
  395. // the property record itself is collected. If the code using the guard needs access to it after it's been invalidated, it
  396. // (the code) is responsible for keeping it alive. Each unique guard, is weakly referenced, such that it can be reclaimed
  397. // if not referenced elsewhere even without being invalidated. It's up to the owner of that guard to keep it alive as long
  398. // as necessary.
  399. Js::PropertyGuard* sharedGuard;
  400. PropertyGuardHashSet uniqueGuards;
  401. EntryPointDictionary* entryPoints;
  402. PropertyGuardEntry(Recycler* recycler) : sharedGuard(nullptr), uniqueGuards(recycler), entryPoints(nullptr) {}
  403. };
  404. public:
  405. typedef JsUtil::BaseHashSet<const Js::PropertyRecord *, HeapAllocator, PrimeSizePolicy, const Js::PropertyRecord *,
  406. Js::PropertyRecordStringHashComparer, JsUtil::SimpleHashedEntry, JsUtil::AsymetricResizeLock> PropertyMap;
  407. typedef JsUtil::BaseHashSet<Js::CaseInvariantPropertyListWithHashCode*, Recycler, PowerOf2SizePolicy, Js::CaseInvariantPropertyListWithHashCode*, JsUtil::NoCaseComparer, JsUtil::SimpleDictionaryEntry>
  408. PropertyNoCaseSetType;
  409. typedef JsUtil::WeaklyReferencedKeyDictionary<Js::Type, bool> TypeHashSet;
  410. typedef JsUtil::BaseDictionary<Js::PropertyId, TypeHashSet *, Recycler, PowerOf2SizePolicy> PropertyIdToTypeHashSetDictionary;
  411. typedef JsUtil::WeaklyReferencedKeyDictionary<const Js::PropertyRecord, PropertyGuardEntry*, Js::PropertyRecordPointerComparer> PropertyGuardDictionary;
  412. private:
  413. DWORD m_jitProcessId;
  414. UUID m_jitConnectionId;
  415. intptr_t m_remoteThreadContextInfo;
  416. public:
  417. JITManager m_codeGenManager;
  418. void SetJITConnectionInfo(DWORD processId, UUID connectionId)
  419. {
  420. m_jitProcessId = processId;
  421. m_jitConnectionId = connectionId;
  422. // TODO: OOP JIT, check hresults
  423. m_codeGenManager.ConnectRpcServer(m_jitProcessId, m_jitConnectionId);
  424. // TODO: OOP JIT, do we need to do this initialization in a different place?
  425. ThreadContextData contextData;
  426. HANDLE targetHandle;
  427. HANDLE jitProcHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, m_jitProcessId);
  428. BOOL succeeded = DuplicateHandle(
  429. GetCurrentProcess(), GetCurrentProcess(),
  430. jitProcHandle, &targetHandle,
  431. NULL, FALSE, DUPLICATE_SAME_ACCESS);
  432. if (!succeeded)
  433. {
  434. // TODO: michhol OOP JIT is this correct?
  435. Js::Throw::InternalError();
  436. }
  437. if (!CloseHandle(jitProcHandle))
  438. {
  439. Js::Throw::InternalError();
  440. }
  441. contextData.processHandle = (intptr_t)targetHandle;
  442. // TODO: OOP JIT, use more generic method for getting name, e.g. in case of ChakraTest.dll
  443. contextData.chakraBaseAddress = (intptr_t)GetModuleHandle(L"Chakra.dll");
  444. contextData.crtBaseAddress = (intptr_t)GetModuleHandle(UCrtC99MathApis::LibraryName);
  445. contextData.threadStackLimitAddr = reinterpret_cast<intptr_t>(GetAddressOfStackLimitForCurrentThread());
  446. contextData.scriptStackLimit = reinterpret_cast<size_t>(GetScriptStackLimit());
  447. contextData.isThreadBound = GetIsThreadBound();
  448. m_codeGenManager.InitializeThreadContext(&contextData, &m_remoteThreadContextInfo);
  449. }
  450. intptr_t GetRemoteThreadContextAddr() const
  451. {
  452. return m_remoteThreadContextInfo;
  453. }
  454. private:
  455. typedef JsUtil::BaseDictionary<uint, Js::SourceDynamicProfileManager*, Recycler, PowerOf2SizePolicy> SourceDynamicProfileManagerMap;
  456. typedef JsUtil::BaseDictionary<const wchar_t*, const Js::PropertyRecord*, Recycler, PowerOf2SizePolicy> SymbolRegistrationMap;
  457. class SourceDynamicProfileManagerCache
  458. {
  459. public:
  460. SourceDynamicProfileManagerCache() : refCount(0), sourceProfileManagerMap(nullptr) {}
  461. SourceDynamicProfileManagerMap* sourceProfileManagerMap;
  462. void AddRef() { refCount++; }
  463. uint Release() { Assert(refCount > 0); return --refCount; }
  464. private:
  465. uint refCount; // For every script context using this cache, there is a ref count added.
  466. };
  467. typedef JsUtil::BaseDictionary<const WCHAR*, SourceDynamicProfileManagerCache*, Recycler, PowerOf2SizePolicy> SourceProfileManagersByUrlMap;
  468. struct RecyclableData
  469. {
  470. RecyclableData(Recycler *const recycler);
  471. Js::TempArenaAllocatorObject * temporaryArenaAllocators[MaxTemporaryArenaAllocators];
  472. Js::TempGuestArenaAllocatorObject * temporaryGuestArenaAllocators[MaxTemporaryArenaAllocators];
  473. Js::JavascriptExceptionObject * exceptionObject;
  474. bool propagateException;
  475. // We throw a JS catchable SO exception if we detect we might overflow the stack. Allocating this (JS)
  476. // object though might really overflow the stack. So use this thread global to identify them from the throw point
  477. // to where they are caught; where the stack has been unwound and it is safer to allocate the real exception
  478. // object and throw.
  479. Js::JavascriptExceptionObject soErrorObject;
  480. // We can't allocate an out of memory object... So use this static as a way to identify
  481. // them from the throw point to where they are caught.
  482. Js::JavascriptExceptionObject oomErrorObject;
  483. // This is for JsRT scenario where a runtime is not usable after a suspend request, before a resume runtime call is made
  484. Js::JavascriptExceptionObject terminatedErrorObject;
  485. Js::JavascriptExceptionObject* unhandledExceptionObject;
  486. // Contains types that have property caches that need to be tracked, as the caches may need to be cleared. Types that
  487. // contain a property cache for a property that is on a prototype object will be tracked in this map since those caches
  488. // need to be cleared if for instance, the property is deleted from the prototype object.
  489. //
  490. // It is expected that over time, types that are deleted will eventually be removed by the weak reference hash sets when
  491. // they're searching through a bucket while registering a type or enumerating types to invalidate, or when a property ID
  492. // is reclaimed. If none of those happen, then this collection may contain weak reference handles to deleted objects
  493. // that would not get removed, but it would also not get any bigger.
  494. PropertyIdToTypeHashSetDictionary typesWithProtoPropertyCache;
  495. // The property guard dictionary contains property guards which need to be invalidated in response to properties changing
  496. // from writable to read-only and vice versa, properties being shadowed or unshadowed on prototypes, etc. The dictionary
  497. // holds only weak references to property guards and their lifetimes are controlled by their creators (typically entry points).
  498. // When a guard is no longer needed it is garbage collected, but the weak references and dictionary entries remain, until
  499. // the guards for a given property get invalidated.
  500. // TODO: Create and use a self-cleaning weak reference dictionary, which would periodically remove any unused weak references.
  501. PropertyGuardDictionary propertyGuards;
  502. PropertyNoCaseSetType * caseInvariantPropertySet;
  503. JsUtil::List<Js::PropertyRecord const*>* boundPropertyStrings; // Recycler allocated list of property strings that we need to strongly reference so that they're not reclaimed
  504. SourceProfileManagersByUrlMap* sourceProfileManagersByUrl;
  505. // Used to register recyclable data that needs to be kept alive while jitting
  506. JsUtil::DoublyLinkedList<Js::CodeGenRecyclableData> codeGenRecyclableDatas;
  507. // Used to root old entry points so that they're not prematurely collected
  508. Js::FunctionEntryPointInfo* oldEntryPointInfo;
  509. // Used to store a mapping of string to Symbol for cross-realm Symbol registration
  510. // See ES6 (draft 22) 19.4.2.2
  511. SymbolRegistrationMap* symbolRegistrationMap;
  512. // Just holding the reference to the returnedValueList of the stepController. This way that list will not get recycled prematurely.
  513. Js::ReturnedValueList *returnedValueList;
  514. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  515. // use for autoProxy called from Debug.setAutoProxyName. we need to keep the buffer from GetSz() alive.
  516. LPCWSTR autoProxyName;
  517. #endif
  518. };
  519. static ThreadContext * globalListLast;
  520. ThreadContextFlags threadContextFlags;
  521. DWORD currentThreadId;
  522. mutable PBYTE stackLimitForCurrentThread;
  523. StackProber * stackProber;
  524. bool isThreadBound;
  525. bool hasThrownPendingException;
  526. bool callDispose;
  527. bool isAllJITCodeInPreReservedRegion;
  528. AllocationPolicyManager * allocationPolicyManager;
  529. JsUtil::ThreadService threadService;
  530. PreReservedVirtualAllocWrapper preReservedVirtualAllocator;
  531. uint callRootLevel;
  532. // The thread page allocator is used by the recycler and need the background page queue
  533. PageAllocator::BackgroundPageQueue backgroundPageQueue;
  534. IdleDecommitPageAllocator pageAllocator;
  535. Recycler* recycler;
  536. // Fake RecyclerWeakReference for built-in properties
  537. class StaticPropertyRecordReference : public RecyclerWeakReference<const Js::PropertyRecord>
  538. {
  539. public:
  540. StaticPropertyRecordReference(const Js::PropertyRecord* propertyRecord)
  541. {
  542. strongRef = (char*)propertyRecord;
  543. strongRefHeapBlock = &CollectedRecyclerWeakRefHeapBlock::Instance;
  544. }
  545. };
  546. static const Js::PropertyRecord * const builtInPropertyRecords[];
  547. PropertyMap * propertyMap;
  548. PropertyNoCaseSetType * caseInvariantPropertySet;
  549. Js::ScriptContext * rootPendingClose;
  550. JsUtil::List<IProjectionContext *, ArenaAllocator>* pendingProjectionContextCloseList;
  551. Js::ScriptEntryExitRecord * entryExitRecord;
  552. Js::InterpreterStackFrame* leafInterpreterFrame;
  553. const Js::PropertyRecord * propertyNamesDirect[128];
  554. ArenaAllocator threadAlloc;
  555. ThreadServiceWrapper* threadServiceWrapper;
  556. uint functionCount;
  557. uint sourceInfoCount;
  558. Js::TypeId nextTypeId;
  559. uint32 polymorphicCacheState;
  560. Js::TypeId wellKnownHostTypeHTMLAllCollectionTypeId;
  561. #ifdef ENABLE_PROJECTION
  562. SListBase<ExternalWeakReferenceCache *> externalWeakReferenceCacheList;
  563. #if DBG_DUMP
  564. IProjectionContextMemoryInfo *projectionMemoryInformation;
  565. #endif
  566. #endif
  567. #if ENABLE_NATIVE_CODEGEN
  568. JsUtil::JobProcessor *jobProcessor;
  569. Js::Var * bailOutRegisterSaveSpace;
  570. CodeGenNumberThreadAllocator * codeGenNumberThreadAllocator;
  571. #endif
  572. RecyclerRootPtr<RecyclableData> recyclableData;
  573. uint temporaryArenaAllocatorCount;
  574. uint temporaryGuestArenaAllocatorCount;
  575. #if DBG_DUMP || defined(PROFILE_EXEC)
  576. ScriptSite* topLevelScriptSite;
  577. #endif
  578. Js::ScriptContext *scriptContextList;
  579. bool scriptContextEverRegistered;
  580. static size_t processNativeCodeSize;
  581. size_t nativeCodeSize;
  582. size_t sourceCodeSize;
  583. Js::HiResTimer hTimer;
  584. int stackProbeCount;
  585. // Count stack probes and poll for continuation every n probes
  586. static const int StackProbePollThreshold = 1000;
  587. ArenaAllocator inlineCacheThreadInfoAllocator;
  588. ArenaAllocator isInstInlineCacheThreadInfoAllocator;
  589. ArenaAllocator equivalentTypeCacheInfoAllocator;
  590. DListBase<Js::ScriptContext *> inlineCacheScriptContexts;
  591. DListBase<Js::ScriptContext *> isInstInlineCacheScriptContexts;
  592. DListBase<Js::EntryPointInfo *> equivalentTypeCacheEntryPoints;
  593. typedef SList<Js::InlineCache*> InlineCacheList;
  594. typedef JsUtil::BaseDictionary<Js::PropertyId, InlineCacheList*, ArenaAllocator> InlineCacheListMapByPropertyId;
  595. InlineCacheListMapByPropertyId protoInlineCacheByPropId;
  596. InlineCacheListMapByPropertyId storeFieldInlineCacheByPropId;
  597. uint registeredInlineCacheCount;
  598. uint unregisteredInlineCacheCount;
  599. typedef JsUtil::BaseDictionary<Js::Var, Js::IsInstInlineCache*, ArenaAllocator> IsInstInlineCacheListMapByFunction;
  600. IsInstInlineCacheListMapByFunction isInstInlineCacheByFunction;
  601. ArenaAllocator prototypeChainEnsuredToHaveOnlyWritableDataPropertiesAllocator;
  602. DListBase<Js::ScriptContext *> prototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext;
  603. DListBase<CollectCallBack> collectCallBackList;
  604. CriticalSection csCollectionCallBack;
  605. bool hasCollectionCallBack;
  606. bool isOptimizedForManyInstances;
  607. bool bgJit;
  608. // We report library code to profiler only if called directly by user code. Not if called by library implementation.
  609. bool isProfilingUserCode;
  610. void* jsrtRuntime;
  611. bool hasUnhandledException;
  612. bool hasCatchHandler;
  613. DisableImplicitFlags disableImplicitFlags;
  614. // Used for identifying that any particular time, the caller chain has try/catch blocks belong to the user code.
  615. // If all try/catch blocks in the current stack marked as non-user code then this member will remain false.
  616. bool hasCatchHandlerToUserCode;
  617. Js::DelayLoadWinRtString delayLoadWinRtString;
  618. #ifdef ENABLE_PROJECTION
  619. Js::DelayLoadWinRtError delayLoadWinRtError;
  620. Js::DelayLoadWinRtTypeResolution delayLoadWinRtTypeResolution;
  621. Js::DelayLoadWinRtRoParameterizedIID delayLoadWinRtRoParameterizedIID;
  622. #endif
  623. #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_ES6_CHAR_CLASSIFIER)
  624. Js::DelayLoadWindowsGlobalization delayLoadWindowsGlobalizationLibrary;
  625. Js::WindowsGlobalizationAdapter windowsGlobalizationAdapter;
  626. #endif
  627. #ifdef ENABLE_FOUNDATION_OBJECT
  628. Js::DelayLoadWinRtFoundation delayLoadWinRtFoundationLibrary;
  629. Js::WindowsFoundationAdapter windowsFoundationAdapter;
  630. #endif
  631. #ifdef _CONTROL_FLOW_GUARD
  632. Js::DelayLoadWinCoreMemory delayLoadWinCoreMemoryLibrary;
  633. #endif
  634. Js::DelayLoadWinCoreProcessThreads delayLoadWinCoreProcessThreads;
  635. // Number of script context attached with probe manager.
  636. // This counter will be used as addref when the script context is created, this way we maintain the life of diagnostic object.
  637. // Once no script context available , diagnostic will go away.
  638. long crefSContextForDiag;
  639. Entropy entropy;
  640. JsUtil::Stack<HostScriptContext*>* hostScriptContextStack;
  641. //
  642. // Regex globals
  643. //
  644. UnifiedRegex::StandardChars<uint8>* standardUTF8Chars;
  645. UnifiedRegex::StandardChars<wchar_t>* standardUnicodeChars;
  646. Js::ImplicitCallFlags implicitCallFlags;
  647. __declspec(thread) static uint activeScriptSiteCount;
  648. bool isScriptActive;
  649. // To synchronize with ETW rundown, which needs to walk scriptContext/functionBody/entryPoint lists.
  650. CriticalSection csEtwRundown;
  651. #ifdef _M_X64
  652. friend class Js::Amd64StackFrame;
  653. Js::Amd64ContextsManager amd64ContextsManager;
  654. Js::Amd64ContextsManager* GetAmd64ContextsManager() { return &amd64ContextsManager; }
  655. #endif
  656. typedef JsUtil::BaseDictionary<Js::DynamicType const *, void *, HeapAllocator, PowerOf2SizePolicy> DynamicObjectEnumeratorCacheMap;
  657. DynamicObjectEnumeratorCacheMap dynamicObjectEnumeratorCacheMap;
  658. ThreadContextWatsonTelemetryBlock localTelemetryBlock;
  659. ThreadContextWatsonTelemetryBlock * telemetryBlock;
  660. NativeLibraryEntryRecord nativeLibraryEntry;
  661. UCrtC99MathApis ucrtC99MathApis;
  662. // Indicates the current loop depth as observed by the interpreter. The interpreter causes this value to be updated upon
  663. // entering and leaving a loop.
  664. uint8 loopDepth;
  665. const ThreadConfiguration configuration;
  666. public:
  667. static ThreadContext * globalListFirst;
  668. static uint GetScriptSiteHolderCount() { return activeScriptSiteCount; }
  669. static uint IncrementActiveScriptSiteCount() { return ++activeScriptSiteCount; }
  670. static uint DecrementActiveScriptSiteCount() { return --activeScriptSiteCount; }
  671. static ThreadContext * GetThreadContextList() { return globalListFirst; }
  672. void ValidateThreadContext();
  673. bool IsInScript() const { return callRootLevel != 0; }
  674. uint GetCallRootLevel() const { return callRootLevel; }
  675. PageAllocator * GetPageAllocator() { return &pageAllocator; }
  676. AllocationPolicyManager * GetAllocationPolicyManager() { return allocationPolicyManager; }
  677. PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() { return &preReservedVirtualAllocator; }
  678. void ResetIsAllJITCodeInPreReservedRegion() { isAllJITCodeInPreReservedRegion = false; }
  679. bool IsAllJITCodeInPreReservedRegion() { return isAllJITCodeInPreReservedRegion; }
  680. CriticalSection* GetEtwRundownCriticalSection() { return &csEtwRundown; }
  681. UCrtC99MathApis* GetUCrtC99MathApis() { return &ucrtC99MathApis; }
  682. Js::DelayLoadWinRtString *GetWinRTStringLibrary();
  683. #ifdef ENABLE_PROJECTION
  684. Js::DelayLoadWinRtError *GetWinRTErrorLibrary();
  685. Js::DelayLoadWinRtTypeResolution* GetWinRTTypeResolutionLibrary();
  686. Js::DelayLoadWinRtRoParameterizedIID* GetWinRTRoParameterizedIIDLibrary();
  687. #endif
  688. #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_ES6_CHAR_CLASSIFIER)
  689. Js::DelayLoadWindowsGlobalization *GetWindowsGlobalizationLibrary();
  690. Js::WindowsGlobalizationAdapter *GetWindowsGlobalizationAdapter();
  691. #endif
  692. #ifdef ENABLE_FOUNDATION_OBJECT
  693. Js::DelayLoadWinRtFoundation *GetWinRtFoundationLibrary();
  694. Js::WindowsFoundationAdapter *GetWindowsFoundationAdapter();
  695. #endif
  696. #ifdef _CONTROL_FLOW_GUARD
  697. Js::DelayLoadWinCoreMemory * GetWinCoreMemoryLibrary();
  698. #endif
  699. Js::DelayLoadWinCoreProcessThreads * GetWinCoreProcessThreads();
  700. JITTimer JITTelemetry;
  701. ParserTimer ParserTelemetry;
  702. GUID activityId;
  703. void *tridentLoadAddress;
  704. void* GetTridentLoadAddress() const { return tridentLoadAddress; }
  705. void SetTridentLoadAddress(void *loadAddress) { tridentLoadAddress = loadAddress; }
  706. #ifdef ENABLE_DIRECTCALL_TELEMETRY
  707. DirectCallTelemetry directCallTelemetry;
  708. #endif
  709. JITStats GetJITStats()
  710. {
  711. return JITTelemetry.GetStats();
  712. }
  713. void ResetJITStats()
  714. {
  715. JITTelemetry.Reset();
  716. }
  717. ParserStats GetParserStats()
  718. {
  719. return ParserTelemetry.GetStats();
  720. }
  721. void ResetParserStats()
  722. {
  723. ParserTelemetry.Reset();
  724. }
  725. double maxGlobalFunctionExecTime;
  726. double GetAndResetMaxGlobalFunctionExecTime()
  727. {
  728. double res = maxGlobalFunctionExecTime;
  729. this->maxGlobalFunctionExecTime = 0.0;
  730. return res;
  731. }
  732. bool IsCFGEnabled();
  733. void SetValidCallTargetForCFG(PVOID callTargetAddress, bool isSetValid = true);
  734. BOOL HasPreviousHostScriptContext();
  735. HostScriptContext* GetPreviousHostScriptContext() ;
  736. void PushHostScriptContext(HostScriptContext* topProvider);
  737. HostScriptContext* PopHostScriptContext();
  738. void SetInterruptPoller(InterruptPoller *poller) { interruptPoller = poller; }
  739. InterruptPoller *GetInterruptPoller() const { return interruptPoller; }
  740. BOOL HasInterruptPoller() const { return interruptPoller != nullptr; }
  741. void CheckScriptInterrupt();
  742. void CheckInterruptPoll();
  743. bool DoInterruptProbe(Js::FunctionBody *const func) const
  744. {
  745. return
  746. (this->TestThreadContextFlag(ThreadContextFlagCanDisableExecution) &&
  747. !PHASE_OFF(Js::InterruptProbePhase, func)) ||
  748. PHASE_ON(Js::InterruptProbePhase, func);
  749. }
  750. bool DoInterruptProbe() const
  751. {
  752. return
  753. (this->TestThreadContextFlag(ThreadContextFlagCanDisableExecution) &&
  754. !PHASE_OFF1(Js::InterruptProbePhase)) ||
  755. PHASE_ON1(Js::InterruptProbePhase);
  756. }
  757. bool EvalDisabled() const
  758. {
  759. return this->TestThreadContextFlag(ThreadContextFlagEvalDisabled);
  760. }
  761. bool NoJIT() const
  762. {
  763. return this->TestThreadContextFlag(ThreadContextFlagNoJIT);
  764. }
  765. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  766. Js::Var GetMemoryStat(Js::ScriptContext* scriptContext);
  767. void SetAutoProxyName(LPCWSTR objectName);
  768. LPCWSTR GetAutoProxyName() const { return recyclableData->autoProxyName; }
  769. Js::PropertyId handlerPropertyId = Js::Constants::NoProperty;
  770. #endif
  771. void SetReturnedValueList(Js::ReturnedValueList *returnedValueList)
  772. {
  773. Assert(this->recyclableData != nullptr);
  774. this->recyclableData->returnedValueList = returnedValueList;
  775. }
  776. #if DBG
  777. void EnsureNoReturnedValueList()
  778. {
  779. Assert(this->recyclableData == nullptr || this->recyclableData->returnedValueList == nullptr);
  780. }
  781. uint GetScriptContextCount() const { return this->scriptContextCount; }
  782. #endif
  783. Js::ScriptContext* GetScriptContextList() const { return this->scriptContextList; }
  784. bool WasAnyScriptContextEverRegistered() const { return this->scriptContextEverRegistered; }
  785. #if DBG_DUMP || defined(PROFILE_EXEC)
  786. void SetTopLevelScriptSite(ScriptSite* topScriptSite) { this->topLevelScriptSite = topScriptSite; }
  787. ScriptSite* GetTopLevelScriptSite () { return this->topLevelScriptSite; }
  788. #endif
  789. #if DBG || defined(PROFILE_EXEC)
  790. virtual bool AsyncHostOperationStart(void *) override;
  791. virtual void AsyncHostOperationEnd(bool wasInAsync, void *) override;
  792. #endif
  793. #if DBG
  794. bool IsInAsyncHostOperation() const;
  795. #endif
  796. BOOL ReserveStaticTypeIds(__in int first, __in int last);
  797. Js::TypeId ReserveTypeIds(int count);
  798. Js::TypeId CreateTypeId();
  799. Js::TypeId GetNextTypeId() { return nextTypeId; }
  800. // Lookup the well known type registered with a Js::TypeId.
  801. // typeId: The type id to match
  802. // returns: The well known type which was previously registered via a call to SetWellKnownHostTypeId
  803. WellKnownHostType GetWellKnownHostType(Js::TypeId typeId);
  804. // Register a well known type to a Js::TypeId.
  805. // wellKnownType: The well known type which we should register
  806. // typeId: The type id which matches to the well known type
  807. void SetWellKnownHostTypeId(WellKnownHostType wellKnownType, Js::TypeId typeId);
  808. uint32 GetNextPolymorphicCacheState()
  809. {
  810. return ++polymorphicCacheState;
  811. };
  812. ~ThreadContext();
  813. void CloseForJSRT();
  814. //Call back is called for one or more handles
  815. //It does multiple callbacks (For example: separate call back for GC thread handle & JIT thread handles)
  816. // template<class Fn>
  817. //void ShutdownThreads(Fn callback);
  818. void ShutdownThreads()
  819. {
  820. m_codeGenManager.CleanupThreadContext(m_remoteThreadContextInfo);
  821. m_codeGenManager.DisconnectRpcServer();
  822. #if ENABLE_NATIVE_CODEGEN
  823. if (jobProcessor)
  824. {
  825. jobProcessor->Close();
  826. }
  827. #endif
  828. #if ENABLE_CONCURRENT_GC
  829. if (this->recycler != nullptr)
  830. {
  831. this->recycler->ShutdownThread();
  832. }
  833. #endif
  834. }
  835. Js::HiResTimer * GetHiResTimer() { return &hTimer; }
  836. ArenaAllocator* GetThreadAlloc() { return &threadAlloc; }
  837. static CriticalSection * GetCriticalSection() { return &s_csThreadContext; }
  838. ThreadContext(AllocationPolicyManager * allocationPolicyManager = nullptr, JsUtil::ThreadService::ThreadServiceCallback threadServiceCallback = nullptr, bool enableExperimentalFeatures = false);
  839. static void Add(ThreadContext *threadContext);
  840. ThreadConfiguration const * GetConfig() const { return &configuration; }
  841. public:
  842. void SetTelemetryBlock(ThreadContextWatsonTelemetryBlock * telemetryBlock) { this->telemetryBlock = telemetryBlock; }
  843. static ThreadContext* GetContextForCurrentThread();
  844. Recycler* GetRecycler() { return recycler; }
  845. Recycler* EnsureRecycler();
  846. ThreadContext::CollectCallBack * AddRecyclerCollectCallBack(RecyclerCollectCallBackFunction callback, void * context);
  847. void RemoveRecyclerCollectCallBack(ThreadContext::CollectCallBack * collectCallBack);
  848. void AddToPendingProjectionContextCloseList(IProjectionContext *projectionContext);
  849. void RemoveFromPendingClose(IProjectionContext *projectionContext);
  850. void ClosePendingProjectionContexts();
  851. void AddToPendingScriptContextCloseList(Js::ScriptContext * scriptContext);
  852. void RemoveFromPendingClose(Js::ScriptContext * scriptContext);
  853. void ClosePendingScriptContexts();
  854. Js::PropertyRecord const * GetPropertyName(Js::PropertyId propertyId);
  855. Js::PropertyRecord const * GetPropertyNameLocked(Js::PropertyId propertyId);
  856. private:
  857. template <bool locked> Js::PropertyRecord const * GetPropertyNameImpl(Js::PropertyId propertyId);
  858. public:
  859. void FindPropertyRecord(Js::JavascriptString *pstName, Js::PropertyRecord const ** propertyRecord);
  860. void FindPropertyRecord(__in LPCWSTR propertyName, __in int propertyNameLength, Js::PropertyRecord const ** propertyRecord);
  861. const Js::PropertyRecord * FindPropertyRecord(const wchar_t * propertyName, int propertyNameLength);
  862. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>* FindPropertyIdNoCase(Js::ScriptContext * scriptContext, LPCWSTR propertyName, int propertyNameLength);
  863. JsUtil::List<const RecyclerWeakReference<Js::PropertyRecord const>*>* FindPropertyIdNoCase(Js::ScriptContext * scriptContext, JsUtil::CharacterBuffer<WCHAR> const& propertyName);
  864. bool FindExistingPropertyRecord(_In_ JsUtil::CharacterBuffer<WCHAR> const& propertyName, Js::CaseInvariantPropertyListWithHashCode** propertyRecord);
  865. void CleanNoCasePropertyMap();
  866. void ForceCleanPropertyMap();
  867. const Js::PropertyRecord * GetOrAddPropertyRecord(JsUtil::CharacterBuffer<wchar_t> propertyName)
  868. {
  869. return GetOrAddPropertyRecordImpl(propertyName, false);
  870. }
  871. const Js::PropertyRecord * GetOrAddPropertyRecordBind(JsUtil::CharacterBuffer<wchar_t> propertyName)
  872. {
  873. return GetOrAddPropertyRecordImpl(propertyName, true);
  874. }
  875. void AddBuiltInPropertyRecord(const Js::PropertyRecord *propertyRecord);
  876. void GetOrAddPropertyId(__in LPCWSTR propertyName, __in int propertyNameLength, Js::PropertyRecord const** propertyRecord);
  877. void GetOrAddPropertyId(JsUtil::CharacterBuffer<WCHAR> const& propertyName, Js::PropertyRecord const** propertyRecord);
  878. Js::PropertyRecord const * UncheckedAddPropertyId(JsUtil::CharacterBuffer<WCHAR> const& propertyName, bool bind, bool isSymbol = false);
  879. Js::PropertyRecord const * UncheckedAddPropertyId(__in LPCWSTR propertyName, __in int propertyNameLength, bool bind = false, bool isSymbol = false);
  880. #ifdef ENABLE_JS_ETW
  881. void EtwLogPropertyIdList();
  882. #endif
  883. private:
  884. const Js::PropertyRecord * GetOrAddPropertyRecordImpl(JsUtil::CharacterBuffer<wchar_t> propertyName, bool bind);
  885. void AddPropertyRecordInternal(const Js::PropertyRecord * propertyRecord);
  886. void BindPropertyRecord(const Js::PropertyRecord * propertyRecord);
  887. bool IsDirectPropertyName(const wchar_t * propertyName, int propertyNameLength);
  888. RecyclerWeakReference<const Js::PropertyRecord> * CreatePropertyRecordWeakRef(const Js::PropertyRecord * propertyRecord);
  889. void AddCaseInvariantPropertyRecord(const Js::PropertyRecord * propertyRecord);
  890. uint scriptContextCount;
  891. public:
  892. void UncheckedAddBuiltInPropertyId();
  893. BOOL IsNumericPropertyId(Js::PropertyId propertyId, uint32* value);
  894. bool IsActivePropertyId(Js::PropertyId pid);
  895. void InvalidatePropertyRecord(const Js::PropertyRecord * propertyRecord);
  896. Js::PropertyId GetNextPropertyId();
  897. Js::PropertyId GetMaxPropertyId();
  898. uint GetHighestPropertyNameIndex() const;
  899. void SetThreadServiceWrapper(ThreadServiceWrapper*);
  900. ThreadServiceWrapper* GetThreadServiceWrapper();
  901. uint GetUnreleasedScriptContextCount(){return scriptContextCount;}
  902. #ifdef ENABLE_PROJECTION
  903. void AddExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache);
  904. void RemoveExternalWeakReferenceCache(ExternalWeakReferenceCache *externalWeakReferenceCache);
  905. virtual void MarkExternalWeakReferencedObjects(bool inPartialCollect) override;
  906. virtual void ResolveExternalWeakReferencedObjects() override;
  907. #if DBG_DUMP
  908. void RegisterProjectionMemoryInformation(IProjectionContextMemoryInfo* projectionContextMemoryInfo);
  909. void DumpProjectionContextMemoryStats(LPCWSTR headerMsg, bool forceDetailed = false);
  910. IProjectionContextMemoryInfo* GetProjectionContextMemoryInformation();
  911. #endif
  912. #endif
  913. uint NewFunctionNumber() { return ++functionCount; }
  914. uint PeekNewFunctionNumber() { return functionCount + 1; }
  915. uint NewSourceInfoNumber() { return ++sourceInfoCount; }
  916. void AddCodeSize(size_t newCode)
  917. {
  918. ::InterlockedExchangeAdd(&nativeCodeSize, newCode);
  919. ::InterlockedExchangeAdd(&processNativeCodeSize, newCode);
  920. }
  921. void AddSourceSize(size_t newCode) { sourceCodeSize += newCode; }
  922. void SubCodeSize(size_t deadCode)
  923. {
  924. Assert(nativeCodeSize >= deadCode);
  925. Assert(processNativeCodeSize >= deadCode);
  926. ::InterlockedExchangeSubtract(&nativeCodeSize, deadCode);
  927. ::InterlockedExchangeSubtract(&processNativeCodeSize, deadCode);
  928. }
  929. void SubSourceSize(size_t deadCode) { Assert(sourceCodeSize >= deadCode); sourceCodeSize -= deadCode; }
  930. size_t GetCodeSize() { return nativeCodeSize; }
  931. static size_t GetProcessCodeSize() { return processNativeCodeSize; }
  932. size_t GetSourceSize() { return sourceCodeSize; }
  933. Js::ScriptEntryExitRecord * GetScriptEntryExit() const { return entryExitRecord; }
  934. void RegisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData);
  935. void UnregisterCodeGenRecyclableData(Js::CodeGenRecyclableData *const codeGenRecyclableData);
  936. #if ENABLE_NATIVE_CODEGEN
  937. BOOL IsNativeAddress(void *pCodeAddr);
  938. JsUtil::JobProcessor *GetJobProcessor();
  939. static void CloseSharedJobProcessor(const bool waitForThread);
  940. Js::Var * GetBailOutRegisterSaveSpace() const { return bailOutRegisterSaveSpace; }
  941. CodeGenNumberThreadAllocator * GetCodeGenNumberThreadAllocator() const
  942. {
  943. return codeGenNumberThreadAllocator;
  944. }
  945. #endif
  946. void ResetFunctionCount() { Assert(this->GetScriptSiteHolderCount() == 0); this->functionCount = 0; }
  947. void PushEntryExitRecord(Js::ScriptEntryExitRecord *);
  948. void PopEntryExitRecord(Js::ScriptEntryExitRecord *);
  949. uint EnterScriptStart(Js::ScriptEntryExitRecord *, bool doCleanup);
  950. void EnterScriptEnd(Js::ScriptEntryExitRecord *, bool doCleanup);
  951. template <bool leaveForHost>
  952. void LeaveScriptStart(void *);
  953. template <bool leaveForHost>
  954. void LeaveScriptEnd(void *);
  955. void DisposeOnLeaveScript();
  956. void PushInterpreterFrame(Js::InterpreterStackFrame *interpreterFrame);
  957. Js::InterpreterStackFrame *PopInterpreterFrame();
  958. Js::InterpreterStackFrame *GetLeafInterpreterFrame() const { return leafInterpreterFrame; }
  959. Js::TempArenaAllocatorObject * GetTemporaryAllocator(LPCWSTR name);
  960. void ReleaseTemporaryAllocator(Js::TempArenaAllocatorObject * tempAllocator);
  961. Js::TempGuestArenaAllocatorObject * GetTemporaryGuestAllocator(LPCWSTR name);
  962. void ReleaseTemporaryGuestAllocator(Js::TempGuestArenaAllocatorObject * tempAllocator);
  963. // Should be called from script context, at the time when construction for scriptcontext is just done.
  964. void EnsureDebugManager();
  965. // Should be called from script context 's destructor,
  966. void ReleaseDebugManager();
  967. void RegisterScriptContext(Js::ScriptContext *scriptContext);
  968. void UnregisterScriptContext(Js::ScriptContext *scriptContext);
  969. // NoScriptScope
  970. void SetNoScriptScope(bool noScriptScope) { this->noScriptScope = noScriptScope; }
  971. bool IsNoScriptScope() { return this->noScriptScope; }
  972. Js::ScriptContext ** RegisterInlineCacheScriptContext(Js::ScriptContext * scriptContext);
  973. Js::ScriptContext ** RegisterIsInstInlineCacheScriptContext(Js::ScriptContext * scriptContext);
  974. Js::EntryPointInfo ** RegisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo * entryPoint);
  975. void UnregisterInlineCacheScriptContext(Js::ScriptContext ** scriptContext);
  976. void UnregisterIsInstInlineCacheScriptContext(Js::ScriptContext ** scriptContext);
  977. void UnregisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo ** entryPoint);
  978. void RegisterProtoInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  979. void RegisterStoreFieldInlineCache(Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  980. void NotifyInlineCacheBatchUnregistered(uint count);
  981. #if DBG
  982. bool IsProtoInlineCacheRegistered(const Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  983. bool IsStoreFieldInlineCacheRegistered(const Js::InlineCache * inlineCache, Js::PropertyId propertyId);
  984. #endif
  985. #if ENABLE_NATIVE_CODEGEN
  986. Js::PropertyGuard* RegisterSharedPropertyGuard(Js::PropertyId propertyId);
  987. void RegisterLazyBailout(Js::PropertyId propertyId, Js::EntryPointInfo* entryPoint);
  988. void RegisterUniquePropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard* guard);
  989. void RegisterUniquePropertyGuard(Js::PropertyId propertyId, RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef);
  990. void RegisterConstructorCache(Js::PropertyId propertyId, Js::ConstructorCache* cache);
  991. #endif
  992. private:
  993. void RegisterInlineCache(InlineCacheListMapByPropertyId& inlineCacheMap, Js::InlineCache* inlineCache, Js::PropertyId propertyId);
  994. static bool IsInlineCacheRegistered(InlineCacheListMapByPropertyId& inlineCacheMap, const Js::InlineCache* inlineCache, Js::PropertyId propertyId);
  995. void InvalidateInlineCacheList(InlineCacheList *inlineCacheList);
  996. void CompactInlineCacheList(InlineCacheList *inlineCacheList);
  997. void CompactInlineCacheInvalidationLists();
  998. void CompactProtoInlineCaches();
  999. void CompactStoreFieldInlineCaches();
  1000. #if DBG
  1001. static bool IsInlineCacheInList(const Js::InlineCache* inlineCache, const InlineCacheList* inlineCacheChain);
  1002. #endif
  1003. #if ENABLE_NATIVE_CODEGEN
  1004. void InvalidateFixedFieldGuard(Js::PropertyGuard* guard);
  1005. PropertyGuardEntry* EnsurePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, bool& foundExistingEntry);
  1006. void InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry);
  1007. #endif
  1008. public:
  1009. class AutoDisableExpiration
  1010. {
  1011. public:
  1012. AutoDisableExpiration(ThreadContext* threadContext):
  1013. _threadContext(threadContext),
  1014. _oldExpirationDisabled(threadContext->disableExpiration)
  1015. {
  1016. _threadContext->disableExpiration = true;
  1017. }
  1018. ~AutoDisableExpiration()
  1019. {
  1020. _threadContext->disableExpiration = _oldExpirationDisabled;
  1021. }
  1022. private:
  1023. ThreadContext* _threadContext;
  1024. bool _oldExpirationDisabled;
  1025. };
  1026. void InvalidateProtoInlineCaches(Js::PropertyId propertyId);
  1027. void InvalidateStoreFieldInlineCaches(Js::PropertyId propertyId);
  1028. void InvalidateAllProtoInlineCaches();
  1029. bool AreAllProtoInlineCachesInvalidated();
  1030. void InvalidateAllStoreFieldInlineCaches();
  1031. bool AreAllStoreFieldInlineCachesInvalidated();
  1032. void InvalidatePropertyGuards(Js::PropertyId propertyId);
  1033. void InvalidateAllPropertyGuards();
  1034. void RegisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1035. void UnregisterIsInstInlineCache(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1036. #if DBG
  1037. bool IsIsInstInlineCacheRegistered(Js::IsInstInlineCache * inlineCache, Js::Var function);
  1038. #endif
  1039. private:
  1040. void InvalidateIsInstInlineCacheList(Js::IsInstInlineCache* inlineCacheList);
  1041. #if DBG
  1042. bool IsIsInstInlineCacheInList(const Js::IsInstInlineCache* inlineCache, const Js::IsInstInlineCache* inlineCacheList);
  1043. #endif
  1044. public:
  1045. void InvalidateIsInstInlineCachesForFunction(Js::Var function);
  1046. void InvalidateAllIsInstInlineCaches();
  1047. bool AreAllIsInstInlineCachesInvalidated() const;
  1048. #ifdef PERSISTENT_INLINE_CACHES
  1049. void ClearInlineCachesWithDeadWeakRefs();
  1050. #endif
  1051. void ClearInlineCaches();
  1052. void ClearIsInstInlineCaches();
  1053. void ClearEquivalentTypeCaches();
  1054. void ClearScriptContextCaches();
  1055. void RegisterTypeWithProtoPropertyCache(const Js::PropertyId propertyId, Js::Type *const type);
  1056. void InvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId);
  1057. void InternalInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId);
  1058. void InvalidateAllProtoTypePropertyCaches();
  1059. Js::ScriptContext ** RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext(Js::ScriptContext * scriptContext);
  1060. void UnregisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesScriptContext(Js::ScriptContext ** scriptContext);
  1061. void ClearPrototypeChainEnsuredToHaveOnlyWritableDataPropertiesCaches();
  1062. BOOL HasUnhandledException() const { return hasUnhandledException; }
  1063. void SetHasUnhandledException() {hasUnhandledException = TRUE; }
  1064. void ResetHasUnhandledException() {hasUnhandledException = FALSE; }
  1065. void SetUnhandledExceptionObject(Js::JavascriptExceptionObject* exceptionObject) {recyclableData->unhandledExceptionObject = exceptionObject; }
  1066. Js::JavascriptExceptionObject* GetUnhandledExceptionObject() const { return recyclableData->unhandledExceptionObject; };
  1067. bool HasCatchHandler() const { return hasCatchHandler; }
  1068. void SetHasCatchHandler(bool hasCatchHandler) { this->hasCatchHandler = hasCatchHandler; }
  1069. bool IsUserCode() const { return this->hasCatchHandlerToUserCode; }
  1070. void SetIsUserCode(bool set) { this->hasCatchHandlerToUserCode = set; }
  1071. void QueueFreeOldEntryPointInfoIfInScript(Js::FunctionEntryPointInfo* oldEntryPointInfo)
  1072. {
  1073. if (this->IsInScript())
  1074. {
  1075. // Add it to the list only if it's not already in it
  1076. if (oldEntryPointInfo->nextEntryPoint == nullptr && !oldEntryPointInfo->IsCleanedUp())
  1077. {
  1078. oldEntryPointInfo->nextEntryPoint = recyclableData->oldEntryPointInfo;
  1079. recyclableData->oldEntryPointInfo = oldEntryPointInfo;
  1080. }
  1081. }
  1082. }
  1083. static BOOLEAN IsOnStack(void const *ptr);
  1084. __declspec(noinline) bool IsStackAvailable(size_t size);
  1085. __declspec(noinline) bool IsStackAvailableNoThrow(size_t size = Js::Constants::MinStackDefault);
  1086. static bool IsCurrentStackAvailable(size_t size);
  1087. void ProbeStackNoDispose(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress = nullptr);
  1088. void ProbeStack(size_t size, Js::ScriptContext *scriptContext, PVOID returnAddress = nullptr);
  1089. void ProbeStack(size_t size, Js::RecyclableObject * obj, Js::ScriptContext *scriptContext);
  1090. void ProbeStack(size_t size);
  1091. static void __stdcall ProbeCurrentStackNoDispose(size_t size, Js::ScriptContext *scriptContext);
  1092. static void __stdcall ProbeCurrentStack(size_t size, Js::ScriptContext *scriptContext);
  1093. static void __stdcall ProbeCurrentStack2(size_t size, Js::ScriptContext *scriptContext, uint32 u1, uint32 u2)
  1094. {
  1095. ProbeCurrentStack(size, scriptContext);
  1096. }
  1097. #if ENABLE_PROFILE_INFO
  1098. void ThreadContext::EnsureSourceProfileManagersByUrlMap();
  1099. Js::SourceDynamicProfileManager* GetSourceDynamicProfileManager(_In_z_ const WCHAR* url, _In_ uint hash, _Inout_ bool* addref);
  1100. uint ReleaseSourceDynamicProfileManagers(const WCHAR* url);
  1101. #endif
  1102. void EnsureSymbolRegistrationMap();
  1103. const Js::PropertyRecord* GetSymbolFromRegistrationMap(const wchar_t* stringKey);
  1104. const Js::PropertyRecord* AddSymbolToRegistrationMap(const wchar_t* stringKey, charcount_t stringLength);
  1105. inline void ClearPendingSOError()
  1106. {
  1107. this->GetPendingSOErrorObject()->ClearError();
  1108. }
  1109. inline void ClearPendingOOMError()
  1110. {
  1111. this->GetPendingOOMErrorObject()->ClearError();
  1112. }
  1113. Js::JavascriptExceptionObject *GetPendingSOErrorObject()
  1114. {
  1115. Assert(recyclableData->soErrorObject.IsPendingExceptionObject());
  1116. return &recyclableData->soErrorObject;
  1117. }
  1118. Js::JavascriptExceptionObject *GetPendingOOMErrorObject()
  1119. {
  1120. Assert(recyclableData->oomErrorObject.IsPendingExceptionObject());
  1121. return &recyclableData->oomErrorObject;
  1122. }
  1123. Js::JavascriptExceptionObject *GetPendingTerminatedErrorObject()
  1124. {
  1125. return &recyclableData->terminatedErrorObject;
  1126. }
  1127. Js::JavascriptExceptionObject* GetRecordedException()
  1128. {
  1129. return recyclableData->exceptionObject;
  1130. }
  1131. bool GetPropagateException()
  1132. {
  1133. return recyclableData->propagateException;
  1134. }
  1135. void SetHasThrownPendingException()
  1136. {
  1137. Assert(this->IsInScript());
  1138. this->hasThrownPendingException = true;
  1139. }
  1140. void SetRecordedException(Js::JavascriptExceptionObject* exceptionObject, bool propagateToDebugger = false)
  1141. {
  1142. this->recyclableData->exceptionObject = exceptionObject;
  1143. this->recyclableData->propagateException = propagateToDebugger;
  1144. }
  1145. Entropy& GetEntropy()
  1146. {
  1147. return entropy;
  1148. }
  1149. Js::ImplicitCallFlags * GetAddressOfImplicitCallFlags()
  1150. {
  1151. return &implicitCallFlags;
  1152. }
  1153. DisableImplicitFlags * GetAddressOfDisableImplicitFlags()
  1154. {
  1155. return &disableImplicitFlags;
  1156. }
  1157. Js::ImplicitCallFlags GetImplicitCallFlags()
  1158. {
  1159. return implicitCallFlags;
  1160. }
  1161. void SetImplicitCallFlags(Js::ImplicitCallFlags flags)
  1162. {
  1163. //Note: this action is inlined into JITed code in Lowerer::GenerateCallProfiling.
  1164. // if you change this, you might want to add it there too.
  1165. implicitCallFlags = flags;
  1166. }
  1167. void ClearImplicitCallFlags();
  1168. void ClearImplicitCallFlags(Js::ImplicitCallFlags flags);
  1169. void AddImplicitCallFlags(Js::ImplicitCallFlags flags)
  1170. {
  1171. SetImplicitCallFlags((Js::ImplicitCallFlags)(implicitCallFlags | flags));
  1172. }
  1173. void CheckAndResetImplicitCallAccessorFlag();
  1174. template <class Fn>
  1175. __inline Js::Var ExecuteImplicitCall(Js::RecyclableObject * function, Js::ImplicitCallFlags flags, Fn implicitCall)
  1176. {
  1177. // For now, we will not allow Function that is marked as HasNoSideEffect to be called, and we will just bailout.
  1178. // These function may still throw exceptions, so we will need to add checks with RecordImplicitException
  1179. // so that we don't throw exception when disableImplicitCall is set before we allow these function to be called
  1180. // as an optimization. (These functions are valueOf and toString calls for built-in non primitive types)
  1181. Js::FunctionInfo::Attributes attributes = Js::FunctionInfo::GetAttributes(function);
  1182. // we can hoist out const method if we know the function doesn't have side effect,
  1183. // and the value can be hoisted.
  1184. if (this->HasNoSideEffect(function, attributes))
  1185. {
  1186. // Has no side effect means the function does not change global value or
  1187. // will check for implicit call flags
  1188. return implicitCall();
  1189. }
  1190. // Don't call the implicit call if disable implicit call
  1191. if (IsDisableImplicitCall())
  1192. {
  1193. AddImplicitCallFlags(flags);
  1194. // Return "undefined" just so we have a valid var, in case subsequent instructions are executed
  1195. // before we bail out.
  1196. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1197. }
  1198. if ((attributes & Js::FunctionInfo::HasNoSideEffect) != 0)
  1199. {
  1200. // Has no side effect means the function does not change global value or
  1201. // will check for implicit call flags
  1202. return implicitCall();
  1203. }
  1204. // Save and restore implicit flags around the implicit call
  1205. Js::ImplicitCallFlags saveImplicitCallFlags = this->GetImplicitCallFlags();
  1206. Js::Var result = implicitCall();
  1207. this->SetImplicitCallFlags((Js::ImplicitCallFlags)(saveImplicitCallFlags | flags));
  1208. return result;
  1209. }
  1210. bool HasNoSideEffect(Js::RecyclableObject * function) const;
  1211. bool HasNoSideEffect(Js::RecyclableObject * function, Js::FunctionInfo::Attributes attr) const;
  1212. bool RecordImplicitException();
  1213. DisableImplicitFlags GetDisableImplicitFlags() const { return disableImplicitFlags; }
  1214. void SetDisableImplicitFlags(DisableImplicitFlags flags) { disableImplicitFlags = flags; }
  1215. bool IsDisableImplicitCall() const { return (disableImplicitFlags & DisableImplicitCallFlag) != 0; }
  1216. bool IsDisableImplicitException() const { return (disableImplicitFlags & DisableImplicitExceptionFlag) != 0; }
  1217. void DisableImplicitCall() { disableImplicitFlags = (DisableImplicitFlags)(disableImplicitFlags | DisableImplicitCallFlag); }
  1218. void ClearDisableImplicitFlags() { disableImplicitFlags = DisableImplicitNoFlag; }
  1219. virtual uint GetRandomNumber() override;
  1220. // DefaultCollectWrapper
  1221. virtual void PreCollectionCallBack(CollectionFlags flags) override;
  1222. virtual void PreSweepCallback() override;
  1223. virtual void WaitCollectionCallBack() override;
  1224. virtual void PostCollectionCallBack() override;
  1225. virtual BOOL ExecuteRecyclerCollectionFunction(Recycler * recycler, CollectionFunction function, CollectionFlags flags) override;
  1226. #ifdef FAULT_INJECTION
  1227. virtual void DisposeScriptContextByFaultInjectionCallBack() override;
  1228. #endif
  1229. virtual void DisposeObjects(Recycler * recycler) override;
  1230. typedef DList<ExpirableObject*, ArenaAllocator> ExpirableObjectList;
  1231. ExpirableObjectList* expirableObjectList;
  1232. ExpirableObjectList* expirableObjectDisposeList;
  1233. int numExpirableObjects;
  1234. int expirableCollectModeGcCount;
  1235. bool disableExpiration;
  1236. bool InExpirableCollectMode();
  1237. void TryEnterExpirableCollectMode();
  1238. void TryExitExpirableCollectMode();
  1239. void RegisterExpirableObject(ExpirableObject* object);
  1240. void UnregisterExpirableObject(ExpirableObject* object);
  1241. void DisposeExpirableObject(ExpirableObject* object);
  1242. void * GetDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType);
  1243. void AddDynamicObjectEnumeratorCache(Js::DynamicType const * dynamicType, void * cache);
  1244. public:
  1245. bool IsScriptActive() const { return isScriptActive; }
  1246. void SetIsScriptActive(bool isActive) { isScriptActive = isActive; }
  1247. bool IsExecutionDisabled() const
  1248. {
  1249. return this->GetStackLimitForCurrentThread() == Js::Constants::StackLimitForScriptInterrupt;
  1250. }
  1251. void DisableExecution();
  1252. void EnableExecution();
  1253. bool TestThreadContextFlag(ThreadContextFlags threadContextFlag) const;
  1254. void SetThreadContextFlag(ThreadContextFlags threadContextFlag);
  1255. void ClearThreadContextFlag(ThreadContextFlags threadContextFlag);
  1256. void SetForceOneIdleCollection();
  1257. bool IsInThreadServiceCallback() const { return threadService.IsInCallback(); }
  1258. Js::DebugManager * GetDebugManager() const { return this->debugManager; }
  1259. const NativeLibraryEntryRecord::Entry* PeekNativeLibraryEntry() const { return this->nativeLibraryEntry.Peek(); }
  1260. void PushNativeLibraryEntry(_In_ NativeLibraryEntryRecord::Entry* entry) { this->nativeLibraryEntry.Push(entry); }
  1261. void PopNativeLibraryEntry() { this->nativeLibraryEntry.Pop(); }
  1262. bool IsProfilingUserCode() const { return isProfilingUserCode; }
  1263. void SetIsProfilingUserCode(bool value) { isProfilingUserCode = value; }
  1264. #if DBG_DUMP
  1265. uint scriptSiteCount;
  1266. #endif
  1267. #ifdef BAILOUT_INJECTION
  1268. uint bailOutByteCodeLocationCount;
  1269. #endif
  1270. #ifdef DYNAMIC_PROFILE_MUTATOR
  1271. DynamicProfileMutator * dynamicProfileMutator;
  1272. #endif
  1273. //
  1274. // Regex helpers
  1275. //
  1276. UnifiedRegex::StandardChars<uint8>* GetStandardChars(__inout_opt uint8* dummy);
  1277. UnifiedRegex::StandardChars<wchar_t>* GetStandardChars(__inout_opt wchar_t* dummy);
  1278. bool IsOptimizedForManyInstances() const { return isOptimizedForManyInstances; }
  1279. void OptimizeForManyInstances(const bool optimizeForManyInstances)
  1280. {
  1281. Assert(!recycler || optimizeForManyInstances == isOptimizedForManyInstances); // mode cannot be changed after recycler is created
  1282. isOptimizedForManyInstances = optimizeForManyInstances;
  1283. }
  1284. #if ENABLE_NATIVE_CODEGEN
  1285. bool IsBgJitEnabled() const { return bgJit; }
  1286. void EnableBgJit(const bool enableBgJit)
  1287. {
  1288. Assert(!jobProcessor || enableBgJit == bgJit);
  1289. bgJit = enableBgJit;
  1290. }
  1291. #endif
  1292. void* GetJSRTRuntime() const { return jsrtRuntime; }
  1293. void SetJSRTRuntime(void* runtime);
  1294. bool CanBeFalsy(Js::TypeId typeId);
  1295. private:
  1296. BOOL ExecuteRecyclerCollectionFunctionCommon(Recycler * recycler, CollectionFunction function, CollectionFlags flags);
  1297. void DoInvalidateProtoTypePropertyCaches(const Js::PropertyId propertyId, TypeHashSet *const typeHashSet);
  1298. void InitializePropertyMaps();
  1299. void CreateNoCasePropertyMap();
  1300. InterruptPoller *interruptPoller;
  1301. void CollectionCallBack(RecyclerCollectCallBackFlags flags);
  1302. // Cache used by HostDispatch::GetBuiltInOperationFromEntryPoint
  1303. private:
  1304. JsUtil::BaseDictionary<Js::JavascriptMethod, uint, ArenaAllocator, PowerOf2SizePolicy> entryPointToBuiltInOperationIdCache;
  1305. public:
  1306. bool IsEntryPointToBuiltInOperationIdCacheInitialized()
  1307. {
  1308. return entryPointToBuiltInOperationIdCache.Count() != 0;
  1309. }
  1310. bool GetBuiltInOperationIdFromEntryPoint(Js::JavascriptMethod entryPoint, uint * id)
  1311. {
  1312. return entryPointToBuiltInOperationIdCache.TryGetValue(entryPoint, id);
  1313. }
  1314. void SetBuiltInOperationIdForEntryPoint(Js::JavascriptMethod entryPoint, uint id)
  1315. {
  1316. entryPointToBuiltInOperationIdCache.Add(entryPoint, id);
  1317. }
  1318. void ResetEntryPointToBuiltInOperationIdCache()
  1319. {
  1320. entryPointToBuiltInOperationIdCache.ResetNoDelete();
  1321. }
  1322. uint8 LoopDepth() const
  1323. {
  1324. return loopDepth;
  1325. }
  1326. void SetLoopDepth(const uint8 loopDepth)
  1327. {
  1328. this->loopDepth = loopDepth;
  1329. }
  1330. void IncrementLoopDepth()
  1331. {
  1332. if(loopDepth != UCHAR_MAX)
  1333. {
  1334. ++loopDepth;
  1335. }
  1336. }
  1337. void DecrementLoopDepth()
  1338. {
  1339. if(loopDepth != 0)
  1340. {
  1341. --loopDepth;
  1342. }
  1343. }
  1344. #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
  1345. static void ReportAndCheckLeaksOnProcessDetach();
  1346. #endif
  1347. #ifdef LEAK_REPORT
  1348. void SetRootTrackerScriptContext(Js::ScriptContext * scriptContext);
  1349. void ClearRootTrackerScriptContext(Js::ScriptContext * scriptContext);
  1350. private:
  1351. Js::ScriptContext * rootTrackerScriptContext;
  1352. DWORD threadId;
  1353. #endif
  1354. };
  1355. extern void(*InitializeAdditionalProperties)(ThreadContext *threadContext);
  1356. // Temporarily set script profiler isProfilingUserCode state, restore at destructor
  1357. class AutoProfilingUserCode
  1358. {
  1359. private:
  1360. ThreadContext* threadContext;
  1361. const bool oldIsProfilingUserCode;
  1362. public:
  1363. AutoProfilingUserCode(ThreadContext* threadContext, bool isProfilingUserCode) :
  1364. threadContext(threadContext),
  1365. oldIsProfilingUserCode(threadContext->IsProfilingUserCode())
  1366. {
  1367. threadContext->SetIsProfilingUserCode(isProfilingUserCode);
  1368. }
  1369. ~AutoProfilingUserCode()
  1370. {
  1371. threadContext->SetIsProfilingUserCode(oldIsProfilingUserCode);
  1372. }
  1373. };