EmitBuffer.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. //---------------------------------------------------------------------------------
  7. // One allocation chunk from CustomHeap + PData if needed, tracked as a linked list
  8. //---------------------------------------------------------------------------------
  9. struct EmitBufferAllocation
  10. {
  11. CustomHeap::Allocation* allocation;
  12. size_t bytesUsed;
  13. size_t bytesCommitted;
  14. bool recorded;
  15. EmitBufferAllocation * nextAllocation;
  16. BYTE * GetUnused() const { return (BYTE*) allocation->address + bytesUsed; }
  17. BYTE * GetUncommitted() const { return (BYTE*) allocation->address + bytesCommitted; }
  18. // Truncation to DWORD okay here
  19. DWORD BytesFree() const { return static_cast<DWORD>(this->bytesCommitted - this->bytesUsed); }
  20. };
  21. typedef void* NativeMethod;
  22. //----------------------------------------------------------------------------
  23. // Emit buffer manager - manages allocation chunks from VirtualAlloc
  24. //----------------------------------------------------------------------------
  25. template <class SyncObject = FakeCriticalSection>
  26. class EmitBufferManager
  27. {
  28. public:
  29. EmitBufferManager(AllocationPolicyManager * policyManager, ArenaAllocator * allocator, Js::ScriptContext * scriptContext, LPCWSTR name, bool allocXdata);
  30. ~EmitBufferManager();
  31. // All the following methods are guarded with the SyncObject
  32. void Decommit();
  33. void Clear();
  34. EmitBufferAllocation* AllocateBuffer(__in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer, ushort pdataCount = 0, ushort xdataSize = 0, bool canAllocInPreReservedHeapPageSegment = false, bool isAnyJittedCode = false);
  35. bool CommitBuffer(EmitBufferAllocation* allocation, __out_bcount(bytes) BYTE* destBuffer, __in size_t bytes, __in_bcount(bytes) const BYTE* sourceBuffer, __in DWORD alignPad = 0);
  36. bool ProtectBufferWithExecuteReadWriteForInterpreter(EmitBufferAllocation* allocation);
  37. bool CommitReadWriteBufferForInterpreter(EmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize);
  38. void CompletePreviousAllocation(EmitBufferAllocation* allocation);
  39. bool FreeAllocation(void* address);
  40. //Ends here
  41. bool IsInRange(void* address)
  42. {
  43. return this->allocationHeap.IsInRange(address);
  44. }
  45. HeapPageAllocator<VirtualAllocWrapper>* GetHeapPageAllocator()
  46. {
  47. return this->allocationHeap.GetHeapPageAllocator();
  48. }
  49. HeapPageAllocator<PreReservedVirtualAllocWrapper>* GetPreReservedHeapPageAllocator()
  50. {
  51. return this->allocationHeap.GetPreReservedHeapPageAllocator();
  52. }
  53. char * EnsurePreReservedPageAllocation(PreReservedVirtualAllocWrapper * preReservedVirtualAllocator)
  54. {
  55. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  56. bool canPreReserveSegmentForCustomHeap = scriptContext && scriptContext->GetThreadContext()->CanPreReserveSegmentForCustomHeap();
  57. #endif
  58. AssertMsg(preReservedVirtualAllocator, "Virtual Allocator for pre reserved Segment should not be null when EnsurePreReservedPageAllocation is called");
  59. if (this->GetPreReservedHeapPageAllocator()->GetVirtualAllocator() == nullptr)
  60. {
  61. this->GetPreReservedHeapPageAllocator()->SetVirtualAllocator(preReservedVirtualAllocator);
  62. }
  63. if (preReservedVirtualAllocator->IsPreReservedRegionPresent())
  64. {
  65. return (char*) preReservedVirtualAllocator->GetPreReservedStartAddress();
  66. }
  67. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  68. if (!canPreReserveSegmentForCustomHeap)
  69. {
  70. VerboseHeapTrace(L"PRE-RESERVE: Upper Cap for PreReservedSegment reached.\n");
  71. return nullptr;
  72. }
  73. #endif
  74. char * startAddressOfPreReservedRegion = this->allocationHeap.EnsurePreReservedPageAllocation(preReservedVirtualAllocator);
  75. //We have newly reserved a segment at this point
  76. if (startAddressOfPreReservedRegion != nullptr)
  77. {
  78. #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
  79. Assert(canPreReserveSegmentForCustomHeap);
  80. this->scriptContext->GetThreadContext()->IncrementThreadContextsWithPreReservedSegment();
  81. #endif
  82. }
  83. return startAddressOfPreReservedRegion;
  84. }
  85. #if DBG_DUMP
  86. void DumpAndResetStats(wchar_t const * source);
  87. #endif
  88. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  89. void CheckBufferPermissions(EmitBufferAllocation *allocation);
  90. #endif
  91. EmitBufferAllocation * allocations;
  92. private:
  93. void FreeAllocations(bool release);
  94. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  95. bool CheckCommitFaultInjection();
  96. int commitCount;
  97. #endif
  98. ArenaAllocator * allocator;
  99. Js::ScriptContext * scriptContext;
  100. EmitBufferAllocation * NewAllocation(size_t bytes, ushort pdataCount, ushort xdataSize, bool canAllocInPreReservedHeapPageSegment, bool isAnyJittedCode);
  101. EmitBufferAllocation* GetBuffer(EmitBufferAllocation *allocation, __in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer);
  102. bool FinalizeAllocation(EmitBufferAllocation *allocation);
  103. CustomHeap::Heap allocationHeap;
  104. SyncObject criticalSection;
  105. #if DBG_DUMP
  106. public:
  107. LPCWSTR name;
  108. size_t totalBytesCode;
  109. size_t totalBytesLoopBody;
  110. size_t totalBytesAlignment;
  111. size_t totalBytesCommitted;
  112. size_t totalBytesReserved;
  113. #endif
  114. };