NativeCodeGenerator.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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. struct CodeGenWorkItem;
  7. struct JsFunctionCodeGen;
  8. struct JsLoopBodyCodeGen;
  9. class InliningDecider;
  10. namespace Js
  11. {
  12. class ObjTypeSpecFldInfo;
  13. class FunctionCodeGenJitTimeData;
  14. };
  15. class NativeCodeGenerator sealed : public JsUtil::WaitableJobManager
  16. {
  17. #if ENABLE_DEBUG_CONFIG_OPTIONS
  18. static volatile UINT_PTR CodegenFailureSeed;
  19. #endif
  20. friend JsUtil::ForegroundJobProcessor;
  21. friend JsUtil::BackgroundJobProcessor;
  22. friend Js::RemoteScriptContext;
  23. public:
  24. NativeCodeGenerator(Js::ScriptContext * scriptContext);
  25. ~NativeCodeGenerator();
  26. void Close();
  27. JsFunctionCodeGen * NewFunctionCodeGen(Js::FunctionBody *functionBody, Js::EntryPointInfo* info);
  28. JsLoopBodyCodeGen * NewLoopBodyCodeGen(Js::FunctionBody *functionBody, Js::EntryPointInfo* info);
  29. bool GenerateFunction(Js::FunctionBody * fn, Js::ScriptFunction * function = nullptr);
  30. void GenerateLoopBody(Js::FunctionBody * functionBody, Js::LoopHeader * loopHeader, Js::EntryPointInfo* info = nullptr, uint localCount = 0, Js::Var localSlots[] = nullptr);
  31. static bool IsValidVar(const Js::Var var, Recycler *const recycler);
  32. #ifdef ENABLE_PREJIT
  33. void GenerateAllFunctions(Js::FunctionBody * fn);
  34. bool DoBackEnd(Js::FunctionBody * fn);
  35. #endif
  36. #ifdef IR_VIEWER
  37. Js::Var RejitIRViewerFunction(Js::FunctionBody *fn, Js::ScriptContext *scriptContext);
  38. #endif
  39. void SetProfileMode(BOOL fSet);
  40. public:
  41. static Js::Var CheckCodeGenThunk(Js::RecyclableObject* function, Js::CallInfo callInfo, ...);
  42. #ifdef ASMJS_PLAT
  43. static Js::Var CheckAsmJsCodeGenThunk(Js::RecyclableObject* function, Js::CallInfo callInfo, ...);
  44. #endif
  45. static bool IsThunk(Js::JavascriptMethod codeAddress);
  46. static bool IsAsmJsCodeGenThunk(Js::JavascriptMethod codeAddress);
  47. static CheckCodeGenFunction GetCheckCodeGenFunction(Js::JavascriptMethod codeAddress);
  48. static Js::JavascriptMethod CheckCodeGen(Js::ScriptFunction * function);
  49. static Js::Var CheckAsmJsCodeGen(Js::ScriptFunction * function);
  50. public:
  51. static void Jit_TransitionFromSimpleJit(void *const framePointer);
  52. private:
  53. static void TransitionFromSimpleJit(Js::ScriptFunction *const function);
  54. private:
  55. static Js::JavascriptMethod CheckCodeGenDone(Js::FunctionBody *const functionBody, Js::FunctionEntryPointInfo *const entryPointInfo, Js::ScriptFunction * function);
  56. CodeGenWorkItem *GetJob(Js::EntryPointInfo *const entryPoint) const;
  57. bool WasAddedToJobProcessor(JsUtil::Job *const job) const;
  58. bool ShouldProcessInForeground(const bool willWaitForJob, const unsigned int numJobsInQueue) const;
  59. void Prioritize(JsUtil::Job *const job, const bool forceAddJobToProcessor = false, void* function = nullptr);
  60. void PrioritizedButNotYetProcessed(JsUtil::Job *const job);
  61. void BeforeWaitForJob(Js::EntryPointInfo *const entryPoint) const;
  62. void AfterWaitForJob(Js::EntryPointInfo *const entryPoint) const;
  63. static bool WorkItemExceedsJITLimits(CodeGenWorkItem *const codeGenWork);
  64. virtual bool Process(JsUtil::Job *const job, JsUtil::ParallelThreadData *threadData) override;
  65. virtual void JobProcessed(JsUtil::Job *const job, const bool succeeded) override;
  66. JsUtil::Job *GetJobToProcessProactively();
  67. void AddToJitQueue(CodeGenWorkItem *const codeGenWorkItem, bool prioritize, bool lock, void* function = nullptr);
  68. void RemoveProactiveJobs();
  69. typedef SListCounted<Js::ObjTypeSpecFldInfo*, ArenaAllocator> ObjTypeSpecFldInfoList;
  70. template<bool IsInlinee> void GatherCodeGenData(
  71. Recycler *const recycler,
  72. Js::FunctionBody *const topFunctionBody,
  73. Js::FunctionBody *const functionBody,
  74. Js::EntryPointInfo *const entryPoint,
  75. InliningDecider &inliningDecider,
  76. ObjTypeSpecFldInfoList *objTypeSpecFldInfoList,
  77. Js::FunctionCodeGenJitTimeData *const jitTimeData,
  78. Js::FunctionCodeGenRuntimeData *const runtimeData,
  79. Js::JavascriptFunction* function = nullptr,
  80. bool isJitTimeDataComputed = false,
  81. uint32 recursiveInlineDepth = 0);
  82. Js::CodeGenRecyclableData *GatherCodeGenData(Js::FunctionBody *const topFunctionBody, Js::FunctionBody *const functionBody, Js::EntryPointInfo *const entryPoint, CodeGenWorkItem* workItem, void* function = nullptr);
  83. public:
  84. void UpdateQueueForDebugMode();
  85. bool IsBackgroundJIT() const;
  86. void EnterScriptStart();
  87. bool IsNativeFunctionAddr(void * address);
  88. void FreeNativeCodeGenAllocation(void* address);
  89. bool TryReleaseNonHiPriWorkItem(CodeGenWorkItem* workItem);
  90. void QueueFreeNativeCodeGenAllocation(void* address);
  91. bool IsClosed() { return isClosed; }
  92. void AddWorkItem(CodeGenWorkItem* workItem);
  93. CodeGenAllocators* GetCodeGenAllocator(PageAllocator* pageallocator){ return EnsureForegroundAllocators(pageallocator); }
  94. #if DBG_DUMP
  95. FILE * asmFile;
  96. #endif
  97. #ifdef PROFILE_EXEC
  98. void CreateProfiler(Js::ScriptContextProfiler * profiler);
  99. void SetProfilerFromNativeCodeGen(NativeCodeGenerator * nativeCodeGen);
  100. Js::ScriptContextProfiler *EnsureForegroundCodeGenProfiler();
  101. static void ProfileBegin(Js::ScriptContextProfiler *const profiler, Js::Phase);
  102. static void ProfileEnd(Js::ScriptContextProfiler *const profiler, Js::Phase);
  103. void ProfilePrint();
  104. #endif
  105. private:
  106. void CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* workItem, const bool foreground);
  107. CodeGenAllocators *CreateAllocators(PageAllocator *const pageAllocator)
  108. {
  109. return HeapNew(CodeGenAllocators, pageAllocator->GetAllocationPolicyManager(), scriptContext);
  110. }
  111. CodeGenAllocators *EnsureForegroundAllocators(PageAllocator * pageAllocator)
  112. {
  113. if (this->foregroundAllocators == nullptr)
  114. {
  115. this->foregroundAllocators = CreateAllocators(pageAllocator);
  116. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  117. if (this->scriptContext->webWorkerId != Js::Constants::NonWebWorkerContextId)
  118. {
  119. this->foregroundAllocators->canCreatePreReservedSegment = true;
  120. }
  121. #endif
  122. }
  123. return this->foregroundAllocators;
  124. }
  125. CodeGenAllocators * GetBackgroundAllocator(PageAllocator *pageAllocator)
  126. {
  127. return this->backgroundAllocators;
  128. }
  129. Js::ScriptContextProfiler * GetBackgroundCodeGenProfiler(PageAllocator *allocator);
  130. void AllocateBackgroundCodeGenProfiler(PageAllocator * pageAllocator);
  131. void AllocateBackgroundAllocators(PageAllocator * pageAllocator)
  132. {
  133. if (!this->backgroundAllocators)
  134. {
  135. this->backgroundAllocators = CreateAllocators(pageAllocator);
  136. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  137. this->backgroundAllocators->canCreatePreReservedSegment = true;
  138. #endif
  139. }
  140. AllocateBackgroundCodeGenProfiler(pageAllocator);
  141. }
  142. virtual void ProcessorThreadSpecificCallBack(PageAllocator * pageAllocator) override
  143. {
  144. AllocateBackgroundAllocators(pageAllocator);
  145. }
  146. bool IsInDebugMode() const;
  147. static ExecutionMode PrejitJitMode(Js::FunctionBody *const functionBody);
  148. bool TryAggressiveInlining(Js::FunctionBody *const topFunctionBody, Js::FunctionBody *const functionBody, InliningDecider &inliningDecider, uint32& inlineeCount, uint recursiveInlineDepth);
  149. private:
  150. Js::ScriptContext * scriptContext;
  151. Js::FunctionBody::SetNativeEntryPointFuncType SetNativeEntryPoint;
  152. uint pendingCodeGenWorkItems;
  153. JsUtil::DoublyLinkedList<CodeGenWorkItem> workItems;
  154. JsUtil::DoublyLinkedList<QueuedFullJitWorkItem> queuedFullJitWorkItems;
  155. uint queuedFullJitWorkItemCount;
  156. uint byteCodeSizeGenerated;
  157. bool isOptimizedForManyInstances;
  158. bool isClosed;
  159. bool hasUpdatedQForDebugMode;
  160. class FreeLoopBodyJob: public JsUtil::Job
  161. {
  162. public:
  163. FreeLoopBodyJob(JsUtil::JobManager *const manager, void* address, bool isHeapAllocated = true):
  164. JsUtil::Job(manager),
  165. codeAddress(address),
  166. heapAllocated(isHeapAllocated)
  167. {
  168. }
  169. bool heapAllocated;
  170. void* codeAddress;
  171. };
  172. class FreeLoopBodyJobManager sealed: public WaitableJobManager
  173. {
  174. public:
  175. FreeLoopBodyJobManager(JsUtil::JobProcessor* processor)
  176. : JsUtil::WaitableJobManager(processor)
  177. , autoClose(true)
  178. , isClosed(false)
  179. {
  180. Processor()->AddManager(this);
  181. }
  182. virtual ~FreeLoopBodyJobManager()
  183. {
  184. if (autoClose && !isClosed)
  185. {
  186. Close();
  187. }
  188. Assert(this->isClosed);
  189. }
  190. void Close()
  191. {
  192. Assert(!this->isClosed);
  193. Processor()->RemoveManager(this);
  194. this->isClosed = true;
  195. }
  196. void SetAutoClose(bool autoClose)
  197. {
  198. this->autoClose = autoClose;
  199. }
  200. FreeLoopBodyJob* GetJob(FreeLoopBodyJob* job)
  201. {
  202. return job;
  203. }
  204. bool WasAddedToJobProcessor(JsUtil::Job *const job) const
  205. {
  206. return true;
  207. }
  208. void SetNativeCodeGen(NativeCodeGenerator* nativeCodeGen)
  209. {
  210. this->nativeCodeGen = nativeCodeGen;
  211. }
  212. void BeforeWaitForJob(FreeLoopBodyJob*) const {}
  213. void AfterWaitForJob(FreeLoopBodyJob*) const {}
  214. virtual bool Process(JsUtil::Job *const job, JsUtil::ParallelThreadData *threadData) override
  215. {
  216. FreeLoopBodyJob* freeLoopBodyJob = static_cast<FreeLoopBodyJob*>(job);
  217. // Free Loop Body
  218. nativeCodeGen->FreeNativeCodeGenAllocation(freeLoopBodyJob->codeAddress);
  219. return true;
  220. }
  221. virtual void JobProcessed(JsUtil::Job *const job, const bool succeeded) override
  222. {
  223. FreeLoopBodyJob* freeLoopBodyJob = static_cast<FreeLoopBodyJob*>(job);
  224. if (freeLoopBodyJob->heapAllocated)
  225. {
  226. HeapDelete(freeLoopBodyJob);
  227. }
  228. }
  229. void QueueFreeLoopBodyJob(void* codeAddress);
  230. private:
  231. NativeCodeGenerator* nativeCodeGen;
  232. bool autoClose;
  233. bool isClosed;
  234. };
  235. FreeLoopBodyJobManager freeLoopBodyManager;
  236. CodeGenAllocators * foregroundAllocators;
  237. CodeGenAllocators * backgroundAllocators;
  238. #ifdef PROFILE_EXEC
  239. Js::ScriptContextProfiler * foregroundCodeGenProfiler;
  240. Js::ScriptContextProfiler * backgroundCodeGenProfiler;
  241. #endif
  242. #if DBG
  243. ThreadContextId mainThreadId;
  244. friend void CheckIsExecutable(Js::RecyclableObject * function, Js::JavascriptMethod entrypoint);
  245. #endif
  246. };