CodeGenWorkItem.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. class Func;
  7. struct CodeGenWorkItem : public JsUtil::Job
  8. {
  9. protected:
  10. CodeGenWorkItem(
  11. JsUtil::JobManager *const manager,
  12. Js::FunctionBody *const functionBody,
  13. Js::EntryPointInfo* entryPointInfo,
  14. bool isJitInDebugMode,
  15. CodeGenWorkItemType type);
  16. ~CodeGenWorkItem();
  17. CodeGenWorkItemIDL jitData;
  18. Js::FunctionBody *const functionBody;
  19. ptrdiff_t codeSize;
  20. public:
  21. virtual uint GetByteCodeCount() const = 0;
  22. virtual size_t GetDisplayName(_Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars) = 0;
  23. virtual void GetEntryPointAddress(void** entrypoint, ptrdiff_t *size) = 0;
  24. virtual uint GetInterpretedCount() const = 0;
  25. virtual void Delete() = 0;
  26. #if DBG_DUMP | defined(VTUNE_PROFILING)
  27. virtual void RecordNativeMap(uint32 nativeOffset, uint32 statementIndex) = 0;
  28. #endif
  29. #if DBG_DUMP
  30. virtual void DumpNativeOffsetMaps() = 0;
  31. virtual void DumpNativeThrowSpanSequence() = 0;
  32. #endif
  33. uint GetFunctionNumber() const
  34. {
  35. return this->functionBody->GetFunctionNumber();
  36. }
  37. ExecutionMode GetJitMode() const
  38. {
  39. return static_cast<ExecutionMode>(this->jitData.jitMode);
  40. }
  41. CodeGenWorkItemIDL * GetJITData()
  42. {
  43. return &this->jitData;
  44. }
  45. CodeGenWorkItemType Type() const { return static_cast<CodeGenWorkItemType>(this->jitData.type); }
  46. Js::ScriptContext* GetScriptContext()
  47. {
  48. return functionBody->GetScriptContext();
  49. }
  50. uint GetByteCodeLength() const
  51. {
  52. return this->functionBody->IsInDebugMode()
  53. ? this->functionBody->GetOriginalByteCode()->GetLength()
  54. : this->functionBody->GetByteCode()->GetLength();
  55. }
  56. Js::FunctionBody* GetFunctionBody() const
  57. {
  58. return functionBody;
  59. }
  60. void SetCodeSize(ptrdiff_t codeSize) { this->codeSize = codeSize; }
  61. ptrdiff_t GetCodeSize() { return codeSize; }
  62. protected:
  63. virtual uint GetLoopNumber() const
  64. {
  65. return Js::LoopHeader::NoLoop;
  66. }
  67. protected:
  68. // This reference does not keep the entry point alive, and it's not expected to
  69. // The entry point is kept alive only if it's in the JIT queue, in which case recyclableData will be allocated and will keep the entry point alive
  70. // If the entry point is getting collected, it'll actually remove itself from the work item list so this work item will get deleted when the EntryPointInfo goes away
  71. Js::EntryPointInfo* entryPointInfo;
  72. Js::CodeGenRecyclableData *recyclableData;
  73. private:
  74. bool isInJitQueue; // indicates if the work item has been added to the global jit queue
  75. bool isAllocationCommitted; // Whether the EmitBuffer allocation has been committed
  76. QueuedFullJitWorkItem *queuedFullJitWorkItem;
  77. EmitBufferAllocation<VirtualAllocWrapper, PreReservedVirtualAllocWrapper> *allocation;
  78. #ifdef IR_VIEWER
  79. public:
  80. bool isRejitIRViewerFunction; // re-JIT function for IRViewer object generation
  81. Js::DynamicObject *irViewerOutput; // hold results of IRViewer APIs
  82. Js::ScriptContext *irViewerRequestContext; // keep track of the request context
  83. Js::DynamicObject * GetIRViewerOutput(Js::ScriptContext *scriptContext)
  84. {
  85. if (!irViewerOutput)
  86. {
  87. irViewerOutput = scriptContext->GetLibrary()->CreateObject();
  88. }
  89. return irViewerOutput;
  90. }
  91. void SetIRViewerOutput(Js::DynamicObject *output)
  92. {
  93. irViewerOutput = output;
  94. }
  95. #endif
  96. private:
  97. // REVIEW: can we delete this?
  98. EmitBufferAllocation<VirtualAllocWrapper, PreReservedVirtualAllocWrapper> *GetAllocation() { return allocation; }
  99. public:
  100. Js::EntryPointInfo* GetEntryPoint() const
  101. {
  102. return this->entryPointInfo;
  103. }
  104. Js::CodeGenRecyclableData *RecyclableData() const
  105. {
  106. return recyclableData;
  107. }
  108. void SetRecyclableData(Js::CodeGenRecyclableData *const recyclableData)
  109. {
  110. Assert(recyclableData);
  111. Assert(!this->recyclableData);
  112. this->recyclableData = recyclableData;
  113. }
  114. void SetEntryPointInfo(Js::EntryPointInfo* entryPointInfo)
  115. {
  116. this->entryPointInfo = entryPointInfo;
  117. }
  118. public:
  119. void ResetJitMode()
  120. {
  121. this->jitData.jitMode = static_cast<uint8>(ExecutionMode::Interpreter);
  122. }
  123. void SetJitMode(const ExecutionMode jitMode)
  124. {
  125. this->jitData.jitMode = static_cast<uint8>(jitMode);
  126. VerifyJitMode();
  127. }
  128. void VerifyJitMode() const
  129. {
  130. Assert(GetJitMode() == ExecutionMode::SimpleJit || GetJitMode() == ExecutionMode::FullJit);
  131. Assert(GetJitMode() != ExecutionMode::SimpleJit || GetFunctionBody()->DoSimpleJit());
  132. Assert(GetJitMode() != ExecutionMode::FullJit || !PHASE_OFF(Js::FullJitPhase, GetFunctionBody()));
  133. }
  134. void OnAddToJitQueue();
  135. void OnRemoveFromJitQueue(NativeCodeGenerator* generator);
  136. public:
  137. bool ShouldSpeculativelyJit(uint byteCodeSizeGenerated) const;
  138. private:
  139. bool ShouldSpeculativelyJitBasedOnProfile() const;
  140. public:
  141. bool IsInJitQueue() const
  142. {
  143. return isInJitQueue;
  144. }
  145. bool IsJitInDebugMode() const
  146. {
  147. return jitData.isJitInDebugMode != 0;
  148. }
  149. void OnWorkItemProcessFail(NativeCodeGenerator *codeGen);
  150. void RecordNativeThrowMap(Js::SmallSpanSequenceIter& iter, uint32 nativeOffset, uint32 statementIndex)
  151. {
  152. this->functionBody->RecordNativeThrowMap(iter, nativeOffset, statementIndex, this->GetEntryPoint(), GetLoopNumber());
  153. }
  154. QueuedFullJitWorkItem *GetQueuedFullJitWorkItem() const;
  155. QueuedFullJitWorkItem *EnsureQueuedFullJitWorkItem();
  156. };
  157. struct JsFunctionCodeGen sealed : public CodeGenWorkItem
  158. {
  159. JsFunctionCodeGen(
  160. JsUtil::JobManager *const manager,
  161. Js::FunctionBody *const functionBody,
  162. Js::EntryPointInfo* entryPointInfo,
  163. bool isJitInDebugMode)
  164. : CodeGenWorkItem(manager, functionBody, entryPointInfo, isJitInDebugMode, JsFunctionType)
  165. {
  166. this->jitData.loopNumber = GetLoopNumber();
  167. }
  168. public:
  169. uint GetByteCodeCount() const override
  170. {
  171. return functionBody->GetByteCodeCount() + functionBody->GetConstantCount();
  172. }
  173. size_t GetDisplayName(_Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars) override
  174. {
  175. const WCHAR* name = functionBody->GetExternalDisplayName();
  176. size_t nameSizeInChars = wcslen(name) + 1;
  177. if (displayName == NULL || sizeInChars < nameSizeInChars)
  178. {
  179. return nameSizeInChars;
  180. }
  181. js_wmemcpy_s(displayName, nameSizeInChars, name, nameSizeInChars);
  182. return nameSizeInChars;
  183. }
  184. void GetEntryPointAddress(void** entrypoint, ptrdiff_t *size) override
  185. {
  186. Assert(entrypoint);
  187. *entrypoint = (void*)this->GetEntryPoint()->jsMethod;
  188. *size = this->GetEntryPoint()->GetCodeSize();
  189. }
  190. uint GetInterpretedCount() const override
  191. {
  192. return this->functionBody->GetInterpretedCount();
  193. }
  194. void Delete() override
  195. {
  196. HeapDelete(this);
  197. }
  198. #if DBG_DUMP | defined(VTUNE_PROFILING)
  199. void RecordNativeMap(uint32 nativeOffset, uint32 statementIndex) override
  200. {
  201. Js::FunctionEntryPointInfo* info = (Js::FunctionEntryPointInfo*) this->GetEntryPoint();
  202. info->RecordNativeMap(nativeOffset, statementIndex);
  203. }
  204. #endif
  205. #if DBG_DUMP
  206. virtual void DumpNativeOffsetMaps() override
  207. {
  208. this->GetEntryPoint()->DumpNativeOffsetMaps();
  209. }
  210. virtual void DumpNativeThrowSpanSequence() override
  211. {
  212. this->GetEntryPoint()->DumpNativeThrowSpanSequence();
  213. }
  214. #endif
  215. };
  216. struct JsLoopBodyCodeGen sealed : public CodeGenWorkItem
  217. {
  218. JsLoopBodyCodeGen(
  219. JsUtil::JobManager *const manager, Js::FunctionBody *const functionBody,
  220. Js::EntryPointInfo* entryPointInfo, bool isJitInDebugMode, Js::LoopHeader * loopHeader) :
  221. CodeGenWorkItem(manager, functionBody, entryPointInfo, isJitInDebugMode, JsLoopBodyWorkItemType),
  222. codeAddress(NULL),
  223. loopHeader(loopHeader)
  224. {
  225. this->jitData.loopNumber = GetLoopNumber();
  226. }
  227. uintptr_t codeAddress;
  228. Js::LoopHeader * loopHeader;
  229. uint GetLoopNumber() const override
  230. {
  231. return functionBody->GetLoopNumberWithLock(loopHeader);
  232. }
  233. void SetCodeAddress(uintptr_t codeAddress) { this->codeAddress = codeAddress; }
  234. uintptr_t GetCodeAddress() const { return codeAddress; }
  235. uint GetByteCodeCount() const override
  236. {
  237. return (loopHeader->endOffset - loopHeader->startOffset) + functionBody->GetConstantCount();
  238. }
  239. size_t GetDisplayName(_Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars) override
  240. {
  241. return this->functionBody->GetLoopBodyName(this->GetLoopNumber(), displayName, sizeInChars);
  242. }
  243. void GetEntryPointAddress(void** entrypoint, ptrdiff_t *size) override
  244. {
  245. Assert(entrypoint);
  246. Js::EntryPointInfo * entryPoint = this->GetEntryPoint();
  247. *entrypoint = reinterpret_cast<void*>(entryPoint->jsMethod);
  248. *size = entryPoint->GetCodeSize();
  249. }
  250. uint GetInterpretedCount() const override
  251. {
  252. return loopHeader->interpretCount;
  253. }
  254. #if DBG_DUMP | defined(VTUNE_PROFILING)
  255. void RecordNativeMap(uint32 nativeOffset, uint32 statementIndex) override
  256. {
  257. this->GetEntryPoint()->RecordNativeMap(nativeOffset, statementIndex);
  258. }
  259. #endif
  260. #if DBG_DUMP
  261. virtual void DumpNativeOffsetMaps() override
  262. {
  263. this->GetEntryPoint()->DumpNativeOffsetMaps();
  264. }
  265. virtual void DumpNativeThrowSpanSequence() override
  266. {
  267. this->GetEntryPoint()->DumpNativeThrowSpanSequence();
  268. }
  269. #endif
  270. void Delete() override
  271. {
  272. HeapDelete(this);
  273. }
  274. ~JsLoopBodyCodeGen()
  275. {
  276. if (this->jitData.symIdToValueTypeMap != nullptr)
  277. {
  278. HeapDeleteArray(this->jitData.symIdToValueTypeMapCount, this->jitData.symIdToValueTypeMap);
  279. this->jitData.symIdToValueTypeMap = nullptr;
  280. }
  281. }
  282. };