EmitBuffer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. #include "Backend.h"
  6. //----------------------------------------------------------------------------
  7. // EmitBufferManager::EmitBufferManager
  8. // Constructor
  9. //----------------------------------------------------------------------------
  10. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  11. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::EmitBufferManager(ArenaAllocator * allocator, CustomHeap::CodePageAllocators<TAlloc, TPreReservedAlloc> * codePageAllocators,
  12. Js::ScriptContext * scriptContext, LPCWSTR name, HANDLE processHandle) :
  13. allocationHeap(allocator, codePageAllocators, processHandle),
  14. allocator(allocator),
  15. allocations(nullptr),
  16. scriptContext(scriptContext),
  17. processHandle(processHandle)
  18. {
  19. #if DBG_DUMP
  20. this->totalBytesCode = 0;
  21. this->totalBytesLoopBody = 0;
  22. this->totalBytesAlignment = 0;
  23. this->totalBytesCommitted = 0;
  24. this->totalBytesReserved = 0;
  25. this->name = name;
  26. #endif
  27. }
  28. //----------------------------------------------------------------------------
  29. // EmitBufferManager::~EmitBufferManager()
  30. // Free up all the VirtualAlloced memory
  31. //----------------------------------------------------------------------------
  32. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  33. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::~EmitBufferManager()
  34. {
  35. Clear();
  36. }
  37. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  38. void
  39. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::Decommit()
  40. {
  41. FreeAllocations(false);
  42. }
  43. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  44. void
  45. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::Clear()
  46. {
  47. FreeAllocations(true);
  48. }
  49. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  50. void
  51. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocations(bool release)
  52. {
  53. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  54. #if DBG_DUMP
  55. if (!release && PHASE_STATS1(Js::EmitterPhase))
  56. {
  57. this->DumpAndResetStats(Js::Configuration::Global.flags.Filename);
  58. }
  59. #endif
  60. TEmitBufferAllocation * allocation = this->allocations;
  61. while (allocation != nullptr)
  62. {
  63. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  64. if(CONFIG_FLAG(CheckEmitBufferPermissions))
  65. {
  66. CheckBufferPermissions(allocation);
  67. }
  68. #endif
  69. if (release)
  70. {
  71. this->allocationHeap.Free(allocation->allocation);
  72. }
  73. else if ((scriptContext != nullptr) && allocation->recorded)
  74. {
  75. // In case of ThunkEmitter the script context would be null and we don't want to track that as code size.
  76. this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
  77. allocation->recorded = false;
  78. }
  79. allocation = allocation->nextAllocation;
  80. }
  81. if (release)
  82. {
  83. this->allocations = nullptr;
  84. }
  85. else
  86. {
  87. this->allocationHeap.DecommitAll();
  88. }
  89. }
  90. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  91. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::IsInHeap(__in void* address)
  92. {
  93. AutoRealOrFakeCriticalSection<SyncObject> autocs(&this->criticalSection);
  94. return this->allocationHeap.IsInHeap(address);
  95. }
  96. template <typename TAlloc, typename TPreReservedAlloc>
  97. class AutoCustomHeapPointer
  98. {
  99. public:
  100. AutoCustomHeapPointer(CustomHeap::Heap<TAlloc, TPreReservedAlloc> * allocationHeap, CustomHeap::Allocation* heapAllocation) :
  101. _allocationHeap(allocationHeap),
  102. _heapAllocation(heapAllocation)
  103. {
  104. }
  105. ~AutoCustomHeapPointer()
  106. {
  107. if (_heapAllocation)
  108. {
  109. _allocationHeap->Free(_heapAllocation);
  110. }
  111. }
  112. CustomHeap::Allocation* Detach()
  113. {
  114. CustomHeap::Allocation* allocation = _heapAllocation;
  115. Assert(allocation != nullptr);
  116. _heapAllocation = nullptr;
  117. return allocation;
  118. }
  119. private:
  120. CustomHeap::Allocation* _heapAllocation;
  121. CustomHeap::Heap<TAlloc, TPreReservedAlloc>* _allocationHeap;
  122. };
  123. //----------------------------------------------------------------------------
  124. // EmitBufferManager::NewAllocation
  125. // Create a new allocation
  126. //----------------------------------------------------------------------------
  127. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  128. EmitBufferAllocation<TAlloc, TPreReservedAlloc> *
  129. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::NewAllocation(size_t bytes, ushort pdataCount, ushort xdataSize, bool canAllocInPreReservedHeapPageSegment, bool isAnyJittedCode)
  130. {
  131. FAULTINJECT_MEMORY_THROW(_u("JIT"), bytes);
  132. Assert(this->criticalSection.IsLocked());
  133. bool isAllJITCodeInPreReservedRegion = true;
  134. CustomHeap::Allocation* heapAllocation = this->allocationHeap.Alloc(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, &isAllJITCodeInPreReservedRegion);
  135. if (heapAllocation == nullptr)
  136. {
  137. if (!JITManager::GetJITManager()->IsJITServer())
  138. {
  139. // This is used in interpreter scenario, thus we need to try to recover memory, if possible.
  140. // Can't simply throw as in JIT scenario, for which throw is what we want in order to give more mem to interpreter.
  141. JsUtil::ExternalApi::RecoverUnusedMemory();
  142. heapAllocation = this->allocationHeap.Alloc(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, &isAllJITCodeInPreReservedRegion);
  143. }
  144. }
  145. if (heapAllocation == nullptr)
  146. {
  147. Js::Throw::OutOfMemory();
  148. }
  149. #if DBG
  150. heapAllocation->isAllocationUsed = true;
  151. #endif
  152. AutoCustomHeapPointer<TAlloc, TPreReservedAlloc> allocatedMemory(&this->allocationHeap, heapAllocation);
  153. VerboseHeapTrace(_u("New allocation: 0x%p, size: %p\n"), heapAllocation->address, heapAllocation->size);
  154. TEmitBufferAllocation * allocation = AnewStruct(this->allocator, TEmitBufferAllocation);
  155. allocation->bytesCommitted = heapAllocation->size;
  156. allocation->allocation = allocatedMemory.Detach();
  157. allocation->bytesUsed = 0;
  158. allocation->nextAllocation = this->allocations;
  159. allocation->recorded = false;
  160. allocation->inPrereservedRegion = isAllJITCodeInPreReservedRegion;
  161. this->allocations = allocation;
  162. #if DBG_DUMP
  163. this->totalBytesCommitted += heapAllocation->size;
  164. #endif
  165. return allocation;
  166. }
  167. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  168. bool
  169. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocation(void* address)
  170. {
  171. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  172. TEmitBufferAllocation* previous = nullptr;
  173. TEmitBufferAllocation* allocation = allocations;
  174. while(allocation != nullptr)
  175. {
  176. if (address >= allocation->allocation->address && address < (allocation->allocation->address + allocation->bytesUsed))
  177. {
  178. if (previous == nullptr)
  179. {
  180. this->allocations = allocation->nextAllocation;
  181. }
  182. else
  183. {
  184. previous->nextAllocation = allocation->nextAllocation;
  185. }
  186. if ((scriptContext != nullptr) && allocation->recorded)
  187. {
  188. this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
  189. }
  190. VerboseHeapTrace(_u("Freeing 0x%p, allocation: 0x%p\n"), address, allocation->allocation->address);
  191. this->allocationHeap.Free(allocation->allocation);
  192. this->allocator->Free(allocation, sizeof(TEmitBufferAllocation));
  193. return true;
  194. }
  195. previous = allocation;
  196. allocation = allocation->nextAllocation;
  197. }
  198. return false;
  199. }
  200. //----------------------------------------------------------------------------
  201. // EmitBufferManager::FinalizeAllocation
  202. // Fill the rest of the page with debugger breakpoint.
  203. //----------------------------------------------------------------------------
  204. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  205. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FinalizeAllocation(TEmitBufferAllocation *allocation, BYTE * dstBuffer)
  206. {
  207. Assert(this->criticalSection.IsLocked());
  208. DWORD bytes = allocation->BytesFree();
  209. if(bytes > 0)
  210. {
  211. BYTE* buffer = nullptr;
  212. this->GetBuffer(allocation, bytes, &buffer);
  213. if (!this->CommitBuffer(allocation, dstBuffer, 0, /*sourceBuffer=*/ nullptr, /*alignPad=*/ bytes))
  214. {
  215. return false;
  216. }
  217. #if DBG_DUMP
  218. this->totalBytesCode -= bytes;
  219. #endif
  220. }
  221. return true;
  222. }
  223. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  224. EmitBufferAllocation<TAlloc, TPreReservedAlloc>*
  225. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::GetBuffer(TEmitBufferAllocation *allocation, __in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer)
  226. {
  227. Assert(this->criticalSection.IsLocked());
  228. Assert(allocation->BytesFree() >= bytes);
  229. // In case of ThunkEmitter the script context would be null and we don't want to track that as code size.
  230. if (scriptContext && !allocation->recorded)
  231. {
  232. this->scriptContext->GetThreadContext()->AddCodeSize(allocation->bytesCommitted);
  233. allocation->recorded = true;
  234. }
  235. // The codegen buffer is beyond the alignment section - hence, we pass this pointer.
  236. *ppBuffer = allocation->GetUnused();
  237. return allocation;
  238. }
  239. //----------------------------------------------------------------------------
  240. // EmitBufferManager::Allocate
  241. // Allocates an executable buffer with a certain alignment
  242. // NOTE: This buffer is not readable or writable. Use CommitBuffer
  243. // to modify this buffer one page at a time.
  244. //----------------------------------------------------------------------------
  245. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  246. EmitBufferAllocation<TAlloc, TPreReservedAlloc>*
  247. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::AllocateBuffer(__in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer, ushort pdataCount /*=0*/, ushort xdataSize /*=0*/, bool canAllocInPreReservedHeapPageSegment /*=false*/,
  248. bool isAnyJittedCode /* = false*/)
  249. {
  250. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  251. Assert(ppBuffer != nullptr);
  252. TEmitBufferAllocation * allocation = this->NewAllocation(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode);
  253. GetBuffer(allocation, bytes, ppBuffer);
  254. #if DBG
  255. MEMORY_BASIC_INFORMATION memBasicInfo;
  256. size_t resultBytes = VirtualQueryEx(this->processHandle, allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
  257. if (resultBytes == 0)
  258. {
  259. MemoryOperationLastError::RecordLastError();
  260. if (this->processHandle != GetCurrentProcess())
  261. {
  262. return nullptr;
  263. }
  264. }
  265. Assert(resultBytes != 0 && memBasicInfo.Protect == PAGE_EXECUTE);
  266. #endif
  267. return allocation;
  268. }
  269. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  270. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  271. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckCommitFaultInjection()
  272. {
  273. if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == 0)
  274. {
  275. return false;
  276. }
  277. commitCount++;
  278. if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == -1)
  279. {
  280. Output::Print(_u("Commit count: %d\n"), commitCount);
  281. }
  282. else if (commitCount == Js::Configuration::Global.flags.ForceOOMOnEBCommit)
  283. {
  284. return true;
  285. }
  286. return false;
  287. }
  288. #endif
  289. #if DBG
  290. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  291. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::IsBufferExecuteReadOnly(TEmitBufferAllocation * allocation)
  292. {
  293. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  294. MEMORY_BASIC_INFORMATION memBasicInfo;
  295. size_t resultBytes = VirtualQuery(allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
  296. return resultBytes != 0 && memBasicInfo.Protect == PAGE_EXECUTE;
  297. }
  298. #endif
  299. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  300. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::ProtectBufferWithExecuteReadWriteForInterpreter(TEmitBufferAllocation* allocation)
  301. {
  302. Assert(this->criticalSection.IsLocked());
  303. Assert(allocation != nullptr);
  304. return (this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation) == TRUE);
  305. }
  306. // Returns true if we successfully commit the buffer
  307. // Returns false if we OOM
  308. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  309. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBufferForInterpreter(TEmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize)
  310. {
  311. Assert(this->criticalSection.IsLocked());
  312. Assert(allocation != nullptr);
  313. allocation->bytesUsed += bufferSize;
  314. #ifdef DEBUG
  315. this->totalBytesCode += bufferSize;
  316. #endif
  317. VerboseHeapTrace(_u("Setting execute permissions on 0x%p, allocation: 0x%p\n"), pBuffer, allocation->allocation->address);
  318. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  319. if (CheckCommitFaultInjection())
  320. {
  321. return false;
  322. }
  323. #endif
  324. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation))
  325. {
  326. return false;
  327. }
  328. FlushInstructionCache(this->processHandle, pBuffer, bufferSize);
  329. return true;
  330. }
  331. //----------------------------------------------------------------------------
  332. // EmitBufferManager::CommitBuffer
  333. // Aligns the buffer with DEBUG instructions.
  334. // Copies contents of source buffer to the destination buffer - at max of one page at a time.
  335. // This ensures that only 1 page is writable at any point of time.
  336. // Commit a buffer from the last AllocateBuffer call that is filled.
  337. //----------------------------------------------------------------------------
  338. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  339. bool
  340. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBuffer(TEmitBufferAllocation* allocation, __out_bcount(bytes) BYTE* destBuffer, __in size_t bytes, __in_bcount(bytes) const BYTE* sourceBuffer, __in DWORD alignPad)
  341. {
  342. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  343. Assert(destBuffer != nullptr);
  344. Assert(allocation != nullptr);
  345. BYTE *currentDestBuffer = destBuffer + allocation->GetBytesUsed();
  346. char *bufferToFlush = allocation->allocation->address + allocation->GetBytesUsed();
  347. Assert(allocation->BytesFree() >= bytes + alignPad);
  348. size_t bytesLeft = bytes + alignPad;
  349. size_t sizeToFlush = bytesLeft;
  350. // Copy the contents and set the alignment pad
  351. while(bytesLeft != 0)
  352. {
  353. DWORD spaceInCurrentPage = AutoSystemInfo::PageSize - ((size_t)currentDestBuffer & (AutoSystemInfo::PageSize - 1));
  354. size_t bytesToChange = bytesLeft > spaceInCurrentPage ? spaceInCurrentPage : bytesLeft;
  355. // Buffer and the bytes that are marked RWX - these will eventually be marked as 'EXCEUTE' only.
  356. BYTE* readWriteBuffer = currentDestBuffer;
  357. size_t readWriteBytes = bytesToChange;
  358. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  359. if (CheckCommitFaultInjection())
  360. {
  361. return false;
  362. }
  363. #endif
  364. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation, (char*)readWriteBuffer))
  365. {
  366. return false;
  367. }
  368. if (alignPad != 0)
  369. {
  370. DWORD alignBytes = alignPad < spaceInCurrentPage ? alignPad : spaceInCurrentPage;
  371. CustomHeap::FillDebugBreak(currentDestBuffer, alignBytes);
  372. alignPad -= alignBytes;
  373. currentDestBuffer += alignBytes;
  374. allocation->bytesUsed += alignBytes;
  375. bytesLeft -= alignBytes;
  376. bytesToChange -= alignBytes;
  377. #if DBG_DUMP
  378. this->totalBytesAlignment += alignBytes;
  379. #endif
  380. }
  381. // If there are bytes still left to be copied then we should do the copy.
  382. if(bytesToChange > 0)
  383. {
  384. AssertMsg(alignPad == 0, "If we are copying right now - we should be done with setting alignment.");
  385. memcpy_s(currentDestBuffer, allocation->BytesFree(), sourceBuffer, bytesToChange);
  386. currentDestBuffer += bytesToChange;
  387. sourceBuffer += bytesToChange;
  388. allocation->bytesUsed += bytesToChange;
  389. bytesLeft -= bytesToChange;
  390. }
  391. Assert(readWriteBuffer + readWriteBytes == currentDestBuffer);
  392. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation, (char*)readWriteBuffer))
  393. {
  394. return false;
  395. }
  396. }
  397. FlushInstructionCache(this->processHandle, bufferToFlush, sizeToFlush);
  398. #if DBG_DUMP
  399. this->totalBytesCode += bytes;
  400. #endif
  401. //Finish the current EmitBufferAllocation
  402. return FinalizeAllocation(allocation, destBuffer);
  403. }
  404. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  405. void
  406. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CompletePreviousAllocation(TEmitBufferAllocation* allocation)
  407. {
  408. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  409. if (allocation != nullptr)
  410. {
  411. allocation->bytesUsed = allocation->bytesCommitted;
  412. }
  413. }
  414. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  415. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  416. void
  417. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckBufferPermissions(TEmitBufferAllocation *allocation)
  418. {
  419. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  420. if(allocation->bytesCommitted == 0)
  421. return;
  422. MEMORY_BASIC_INFORMATION memInfo;
  423. BYTE *buffer = (BYTE*) allocation->allocation->address;
  424. SIZE_T size = allocation->bytesCommitted;
  425. while(1)
  426. {
  427. SIZE_T result = VirtualQuery(buffer, &memInfo, sizeof(memInfo));
  428. if(result == 0)
  429. {
  430. // VirtualQuery failed. This is not an expected condition, but it would be benign for the purposes of this check. Seems
  431. // to occur occasionally on process shutdown.
  432. break;
  433. }
  434. else if(memInfo.Protect == PAGE_EXECUTE_READWRITE)
  435. {
  436. Output::Print(_u("ERROR: Found PAGE_EXECUTE_READWRITE page!\n"));
  437. #ifdef DEBUG
  438. AssertMsg(FALSE, "Page was marked PAGE_EXECUTE_READWRITE");
  439. #else
  440. Fatal();
  441. #endif
  442. }
  443. // Figure out if we need to continue the query. The returned size might be larger than the size we requested,
  444. // for instance if more pages were allocated directly afterward, with the same permissions.
  445. if(memInfo.RegionSize >= size)
  446. {
  447. break;
  448. }
  449. // recalculate size for next iteration
  450. buffer += memInfo.RegionSize;
  451. size -= memInfo.RegionSize;
  452. if(size <= 0)
  453. {
  454. AssertMsg(FALSE, "Last VirtualQuery left us with unmatched regions");
  455. break;
  456. }
  457. }
  458. }
  459. #endif
  460. #if DBG_DUMP
  461. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  462. void
  463. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::DumpAndResetStats(char16 const * filename)
  464. {
  465. if (this->totalBytesCommitted != 0)
  466. {
  467. size_t wasted = this->totalBytesCommitted - this->totalBytesCode - this->totalBytesAlignment;
  468. Output::Print(_u("Stats for %s: %s \n"), name, filename);
  469. Output::Print(_u(" Total code size : %10d (%6.2f%% of committed)\n"), this->totalBytesCode,
  470. (float)this->totalBytesCode * 100 / this->totalBytesCommitted);
  471. Output::Print(_u(" Total LoopBody code : %10d\n"), this->totalBytesLoopBody);
  472. Output::Print(_u(" Total alignment size : %10d (%6.2f%% of committed)\n"), this->totalBytesAlignment,
  473. (float)this->totalBytesAlignment * 100 / this->totalBytesCommitted);
  474. Output::Print(_u(" Total wasted size : %10d (%6.2f%% of committed)\n"), wasted,
  475. (float)wasted * 100 / this->totalBytesCommitted);
  476. Output::Print(_u(" Total committed size : %10d (%6.2f%% of reserved)\n"), this->totalBytesCommitted,
  477. (float)this->totalBytesCommitted * 100 / this->totalBytesReserved);
  478. Output::Print(_u(" Total reserved size : %10d\n"), this->totalBytesReserved);
  479. }
  480. this->totalBytesCode = 0;
  481. this->totalBytesLoopBody = 0;
  482. this->totalBytesAlignment = 0;
  483. this->totalBytesCommitted = 0;
  484. this->totalBytesReserved = 0;
  485. }
  486. #endif
  487. template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, FakeCriticalSection>;
  488. template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, CriticalSection>;
  489. #if ENABLE_OOP_NATIVE_CODEGEN
  490. template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, FakeCriticalSection>;
  491. template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, CriticalSection>;
  492. #endif