EmitBuffer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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, typename 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. Assert(resultBytes == 0 || memBasicInfo.Protect == PAGE_EXECUTE);
  258. #endif
  259. return allocation;
  260. }
  261. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  262. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  263. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckCommitFaultInjection()
  264. {
  265. if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == 0)
  266. {
  267. return false;
  268. }
  269. commitCount++;
  270. if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == -1)
  271. {
  272. Output::Print(_u("Commit count: %d\n"), commitCount);
  273. }
  274. else if (commitCount == Js::Configuration::Global.flags.ForceOOMOnEBCommit)
  275. {
  276. return true;
  277. }
  278. return false;
  279. }
  280. #endif
  281. #if DBG
  282. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  283. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::IsBufferExecuteReadOnly(TEmitBufferAllocation * allocation)
  284. {
  285. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  286. MEMORY_BASIC_INFORMATION memBasicInfo;
  287. size_t resultBytes = VirtualQuery(allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
  288. return resultBytes != 0 && memBasicInfo.Protect == PAGE_EXECUTE;
  289. }
  290. #endif
  291. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  292. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::ProtectBufferWithExecuteReadWriteForInterpreter(TEmitBufferAllocation* allocation)
  293. {
  294. Assert(this->criticalSection.IsLocked());
  295. Assert(allocation != nullptr);
  296. return (this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation) == TRUE);
  297. }
  298. // Returns true if we successfully commit the buffer
  299. // Returns false if we OOM
  300. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  301. bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBufferForInterpreter(TEmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize)
  302. {
  303. Assert(this->criticalSection.IsLocked());
  304. Assert(allocation != nullptr);
  305. allocation->bytesUsed += bufferSize;
  306. #ifdef DEBUG
  307. this->totalBytesCode += bufferSize;
  308. #endif
  309. VerboseHeapTrace(_u("Setting execute permissions on 0x%p, allocation: 0x%p\n"), pBuffer, allocation->allocation->address);
  310. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  311. if (CheckCommitFaultInjection())
  312. {
  313. return false;
  314. }
  315. #endif
  316. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation))
  317. {
  318. return false;
  319. }
  320. FlushInstructionCache(this->processHandle, pBuffer, bufferSize);
  321. return true;
  322. }
  323. //----------------------------------------------------------------------------
  324. // EmitBufferManager::CommitBuffer
  325. // Aligns the buffer with DEBUG instructions.
  326. // Copies contents of source buffer to the destination buffer - at max of one page at a time.
  327. // This ensures that only 1 page is writable at any point of time.
  328. // Commit a buffer from the last AllocateBuffer call that is filled.
  329. //----------------------------------------------------------------------------
  330. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  331. bool
  332. 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)
  333. {
  334. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  335. Assert(destBuffer != nullptr);
  336. Assert(allocation != nullptr);
  337. BYTE *currentDestBuffer = destBuffer + allocation->GetBytesUsed();
  338. char *bufferToFlush = allocation->allocation->address + allocation->GetBytesUsed();
  339. Assert(allocation->BytesFree() >= bytes + alignPad);
  340. size_t bytesLeft = bytes + alignPad;
  341. size_t sizeToFlush = bytesLeft;
  342. // Copy the contents and set the alignment pad
  343. while(bytesLeft != 0)
  344. {
  345. DWORD spaceInCurrentPage = AutoSystemInfo::PageSize - ((size_t)currentDestBuffer & (AutoSystemInfo::PageSize - 1));
  346. size_t bytesToChange = bytesLeft > spaceInCurrentPage ? spaceInCurrentPage : bytesLeft;
  347. // Buffer and the bytes that are marked RWX - these will eventually be marked as 'EXCEUTE' only.
  348. BYTE* readWriteBuffer = currentDestBuffer;
  349. size_t readWriteBytes = bytesToChange;
  350. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  351. if (CheckCommitFaultInjection())
  352. {
  353. return false;
  354. }
  355. #endif
  356. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation, (char*)readWriteBuffer))
  357. {
  358. return false;
  359. }
  360. if (alignPad != 0)
  361. {
  362. DWORD alignBytes = alignPad < spaceInCurrentPage ? alignPad : spaceInCurrentPage;
  363. CustomHeap::FillDebugBreak(currentDestBuffer, alignBytes);
  364. alignPad -= alignBytes;
  365. currentDestBuffer += alignBytes;
  366. allocation->bytesUsed += alignBytes;
  367. bytesLeft -= alignBytes;
  368. bytesToChange -= alignBytes;
  369. #if DBG_DUMP
  370. this->totalBytesAlignment += alignBytes;
  371. #endif
  372. }
  373. // If there are bytes still left to be copied then we should do the copy.
  374. if(bytesToChange > 0)
  375. {
  376. AssertMsg(alignPad == 0, "If we are copying right now - we should be done with setting alignment.");
  377. memcpy_s(currentDestBuffer, allocation->BytesFree(), sourceBuffer, bytesToChange);
  378. currentDestBuffer += bytesToChange;
  379. sourceBuffer += bytesToChange;
  380. allocation->bytesUsed += bytesToChange;
  381. bytesLeft -= bytesToChange;
  382. }
  383. Assert(readWriteBuffer + readWriteBytes == currentDestBuffer);
  384. if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation, (char*)readWriteBuffer))
  385. {
  386. return false;
  387. }
  388. }
  389. FlushInstructionCache(this->processHandle, bufferToFlush, sizeToFlush);
  390. #if DBG_DUMP
  391. this->totalBytesCode += bytes;
  392. #endif
  393. //Finish the current EmitBufferAllocation
  394. return FinalizeAllocation(allocation, destBuffer);
  395. }
  396. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  397. void
  398. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CompletePreviousAllocation(TEmitBufferAllocation* allocation)
  399. {
  400. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  401. if (allocation != nullptr)
  402. {
  403. allocation->bytesUsed = allocation->bytesCommitted;
  404. }
  405. }
  406. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  407. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  408. void
  409. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckBufferPermissions(TEmitBufferAllocation *allocation)
  410. {
  411. AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
  412. if(allocation->bytesCommitted == 0)
  413. return;
  414. MEMORY_BASIC_INFORMATION memInfo;
  415. BYTE *buffer = (BYTE*) allocation->allocation->address;
  416. SIZE_T size = allocation->bytesCommitted;
  417. while(1)
  418. {
  419. SIZE_T result = VirtualQuery(buffer, &memInfo, sizeof(memInfo));
  420. if(result == 0)
  421. {
  422. // VirtualQuery failed. This is not an expected condition, but it would be benign for the purposes of this check. Seems
  423. // to occur occasionally on process shutdown.
  424. break;
  425. }
  426. else if(memInfo.Protect == PAGE_EXECUTE_READWRITE)
  427. {
  428. Output::Print(_u("ERROR: Found PAGE_EXECUTE_READWRITE page!\n"));
  429. #ifdef DEBUG
  430. AssertMsg(FALSE, "Page was marked PAGE_EXECUTE_READWRITE");
  431. #else
  432. Fatal();
  433. #endif
  434. }
  435. // Figure out if we need to continue the query. The returned size might be larger than the size we requested,
  436. // for instance if more pages were allocated directly afterward, with the same permissions.
  437. if(memInfo.RegionSize >= size)
  438. {
  439. break;
  440. }
  441. // recalculate size for next iteration
  442. buffer += memInfo.RegionSize;
  443. size -= memInfo.RegionSize;
  444. if(size <= 0)
  445. {
  446. AssertMsg(FALSE, "Last VirtualQuery left us with unmatched regions");
  447. break;
  448. }
  449. }
  450. }
  451. #endif
  452. #if DBG_DUMP
  453. template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
  454. void
  455. EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::DumpAndResetStats(char16 const * filename)
  456. {
  457. if (this->totalBytesCommitted != 0)
  458. {
  459. size_t wasted = this->totalBytesCommitted - this->totalBytesCode - this->totalBytesAlignment;
  460. Output::Print(_u("Stats for %s: %s \n"), name, filename);
  461. Output::Print(_u(" Total code size : %10d (%6.2f%% of committed)\n"), this->totalBytesCode,
  462. (float)this->totalBytesCode * 100 / this->totalBytesCommitted);
  463. Output::Print(_u(" Total LoopBody code : %10d\n"), this->totalBytesLoopBody);
  464. Output::Print(_u(" Total alignment size : %10d (%6.2f%% of committed)\n"), this->totalBytesAlignment,
  465. (float)this->totalBytesAlignment * 100 / this->totalBytesCommitted);
  466. Output::Print(_u(" Total wasted size : %10d (%6.2f%% of committed)\n"), wasted,
  467. (float)wasted * 100 / this->totalBytesCommitted);
  468. Output::Print(_u(" Total committed size : %10d (%6.2f%% of reserved)\n"), this->totalBytesCommitted,
  469. (float)this->totalBytesCommitted * 100 / this->totalBytesReserved);
  470. Output::Print(_u(" Total reserved size : %10d\n"), this->totalBytesReserved);
  471. }
  472. this->totalBytesCode = 0;
  473. this->totalBytesLoopBody = 0;
  474. this->totalBytesAlignment = 0;
  475. this->totalBytesCommitted = 0;
  476. this->totalBytesReserved = 0;
  477. }
  478. #endif
  479. template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, FakeCriticalSection>;
  480. template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, CriticalSection>;
  481. #if ENABLE_OOP_NATIVE_CODEGEN
  482. template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, FakeCriticalSection>;
  483. template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, CriticalSection>;
  484. #endif