CodeGenWorkItem.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. size_t sizeInBytes = nameSizeInChars * sizeof(WCHAR);
  178. if(displayName == NULL || sizeInChars < nameSizeInChars)
  179. {
  180. return nameSizeInChars;
  181. }
  182. js_memcpy_s(displayName, sizeInChars * sizeof(WCHAR), name, sizeInBytes);
  183. return nameSizeInChars;
  184. }
  185. void GetEntryPointAddress(void** entrypoint, ptrdiff_t *size) override
  186. {
  187. Assert(entrypoint);
  188. *entrypoint = (void*)this->GetEntryPoint()->jsMethod;
  189. *size = this->GetEntryPoint()->GetCodeSize();
  190. }
  191. uint GetInterpretedCount() const override
  192. {
  193. return this->functionBody->GetInterpretedCount();
  194. }
  195. void Delete() override
  196. {
  197. HeapDelete(this);
  198. }
  199. #if DBG_DUMP | defined(VTUNE_PROFILING)
  200. void RecordNativeMap(uint32 nativeOffset, uint32 statementIndex) override
  201. {
  202. Js::FunctionEntryPointInfo* info = (Js::FunctionEntryPointInfo*) this->GetEntryPoint();
  203. info->RecordNativeMap(nativeOffset, statementIndex);
  204. }
  205. #endif
  206. #if DBG_DUMP
  207. virtual void DumpNativeOffsetMaps() override
  208. {
  209. this->GetEntryPoint()->DumpNativeOffsetMaps();
  210. }
  211. virtual void DumpNativeThrowSpanSequence() override
  212. {
  213. this->GetEntryPoint()->DumpNativeThrowSpanSequence();
  214. }
  215. #endif
  216. };
  217. struct JsLoopBodyCodeGen sealed : public CodeGenWorkItem
  218. {
  219. JsLoopBodyCodeGen(
  220. JsUtil::JobManager *const manager, Js::FunctionBody *const functionBody,
  221. Js::EntryPointInfo* entryPointInfo, bool isJitInDebugMode, Js::LoopHeader * loopHeader) :
  222. CodeGenWorkItem(manager, functionBody, entryPointInfo, isJitInDebugMode, JsLoopBodyWorkItemType),
  223. codeAddress(NULL),
  224. loopHeader(loopHeader)
  225. {
  226. this->jitData.loopNumber = GetLoopNumber();
  227. }
  228. uintptr_t codeAddress;
  229. Js::LoopHeader * loopHeader;
  230. uint GetLoopNumber() const override
  231. {
  232. return functionBody->GetLoopNumberWithLock(loopHeader);
  233. }
  234. void SetCodeAddress(uintptr_t codeAddress) { this->codeAddress = codeAddress; }
  235. uintptr_t GetCodeAddress() const { return codeAddress; }
  236. uint GetByteCodeCount() const override
  237. {
  238. return (loopHeader->endOffset - loopHeader->startOffset) + functionBody->GetConstantCount();
  239. }
  240. size_t GetDisplayName(_Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars) override
  241. {
  242. return this->functionBody->GetLoopBodyName(this->GetLoopNumber(), displayName, sizeInChars);
  243. }
  244. void GetEntryPointAddress(void** entrypoint, ptrdiff_t *size) override
  245. {
  246. Assert(entrypoint);
  247. Js::EntryPointInfo * entryPoint = this->GetEntryPoint();
  248. *entrypoint = reinterpret_cast<void*>(entryPoint->jsMethod);
  249. *size = entryPoint->GetCodeSize();
  250. }
  251. uint GetInterpretedCount() const override
  252. {
  253. return loopHeader->interpretCount;
  254. }
  255. #if DBG_DUMP | defined(VTUNE_PROFILING)
  256. void RecordNativeMap(uint32 nativeOffset, uint32 statementIndex) override
  257. {
  258. this->GetEntryPoint()->RecordNativeMap(nativeOffset, statementIndex);
  259. }
  260. #endif
  261. #if DBG_DUMP
  262. virtual void DumpNativeOffsetMaps() override
  263. {
  264. this->GetEntryPoint()->DumpNativeOffsetMaps();
  265. }
  266. virtual void DumpNativeThrowSpanSequence() override
  267. {
  268. this->GetEntryPoint()->DumpNativeThrowSpanSequence();
  269. }
  270. #endif
  271. void Delete() override
  272. {
  273. HeapDelete(this);
  274. }
  275. ~JsLoopBodyCodeGen()
  276. {
  277. if (this->jitData.symIdToValueTypeMap != nullptr)
  278. {
  279. HeapDeleteArray(this->jitData.symIdToValueTypeMapCount, this->jitData.symIdToValueTypeMap);
  280. this->jitData.symIdToValueTypeMap = nullptr;
  281. }
  282. }
  283. };