CodeGenWorkItem.h 10 KB

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