AllocationPolicyManager.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. //
  6. // AllocationPolicyManager allows a caller/host to disallow new page allocations
  7. // and to track current page usage.
  8. //
  9. // NOTE: For now, we are only tracking reserved page count.
  10. // Consider whether we should also (or maybe only) track committed page count.
  11. class AllocationPolicyManager
  12. {
  13. public:
  14. enum MemoryAllocateEvent
  15. {
  16. MemoryAllocate = 0,
  17. MemoryFree = 1,
  18. MemoryFailure = 2,
  19. MemoryMax = 2,
  20. };
  21. typedef bool (__stdcall * PageAllocatorMemoryAllocationCallback)(__in LPVOID context,
  22. __in AllocationPolicyManager::MemoryAllocateEvent allocationEvent,
  23. __in size_t allocationSize);
  24. private:
  25. size_t memoryLimit;
  26. size_t currentMemory;
  27. bool supportConcurrency;
  28. CriticalSection cs;
  29. void * context;
  30. PageAllocatorMemoryAllocationCallback memoryAllocationCallback;
  31. public:
  32. AllocationPolicyManager(bool needConcurrencySupport) :
  33. memoryLimit((size_t)-1),
  34. currentMemory(0),
  35. supportConcurrency(needConcurrencySupport),
  36. context(NULL),
  37. memoryAllocationCallback(NULL)
  38. {
  39. Js::Number limitMB = Js::Configuration::Global.flags.AllocPolicyLimit;
  40. if (limitMB > 0)
  41. {
  42. memoryLimit = (size_t)limitMB * 1024 * 1024;
  43. }
  44. }
  45. ~AllocationPolicyManager()
  46. {
  47. Assert(currentMemory == 0);
  48. }
  49. size_t GetUsage()
  50. {
  51. return currentMemory;
  52. }
  53. size_t GetLimit()
  54. {
  55. return memoryLimit;
  56. }
  57. void SetLimit(size_t newLimit)
  58. {
  59. memoryLimit = newLimit;
  60. }
  61. bool RequestAlloc(DECLSPEC_GUARD_OVERFLOW size_t byteCount, bool externalAlloc = false)
  62. {
  63. if (supportConcurrency)
  64. {
  65. AutoCriticalSection auto_cs(&cs);
  66. return RequestAllocImpl(byteCount, externalAlloc);
  67. }
  68. else
  69. {
  70. return RequestAllocImpl(byteCount, externalAlloc);
  71. }
  72. }
  73. void ReportFailure(size_t byteCount)
  74. {
  75. if (supportConcurrency)
  76. {
  77. AutoCriticalSection auto_cs(&cs);
  78. ReportFreeImpl(MemoryAllocateEvent::MemoryFailure, byteCount);
  79. }
  80. else
  81. {
  82. ReportFreeImpl(MemoryAllocateEvent::MemoryFailure, byteCount);
  83. }
  84. }
  85. void ReportFree(size_t byteCount)
  86. {
  87. if (supportConcurrency)
  88. {
  89. AutoCriticalSection auto_cs(&cs);
  90. ReportFreeImpl(MemoryAllocateEvent::MemoryFree, byteCount);
  91. }
  92. else
  93. {
  94. ReportFreeImpl(MemoryAllocateEvent::MemoryFree, byteCount);
  95. }
  96. }
  97. void SetMemoryAllocationCallback(LPVOID newContext, PageAllocatorMemoryAllocationCallback callback)
  98. {
  99. this->memoryAllocationCallback = callback;
  100. if (callback == NULL)
  101. {
  102. // doesn't make sense to have non-null context when the callback is NULL.
  103. this->context = NULL;
  104. }
  105. else
  106. {
  107. this->context = newContext;
  108. }
  109. }
  110. private:
  111. inline bool RequestAllocImpl(size_t byteCount, bool externalAlloc = false)
  112. {
  113. size_t newCurrentMemory = currentMemory + byteCount;
  114. if (newCurrentMemory < currentMemory ||
  115. newCurrentMemory > memoryLimit ||
  116. (memoryAllocationCallback != NULL && !memoryAllocationCallback(context, MemoryAllocateEvent::MemoryAllocate, byteCount)))
  117. {
  118. // oopjit number allocator allocated pages, we can't stop it from allocating so just increase the usage number
  119. if (externalAlloc)
  120. {
  121. currentMemory = newCurrentMemory;
  122. return true;
  123. }
  124. if (memoryAllocationCallback != NULL)
  125. {
  126. memoryAllocationCallback(context, MemoryAllocateEvent::MemoryFailure, byteCount);
  127. }
  128. return false;
  129. }
  130. else
  131. {
  132. currentMemory = newCurrentMemory;
  133. return true;
  134. }
  135. }
  136. inline void ReportFreeImpl(MemoryAllocateEvent allocationEvent, size_t byteCount)
  137. {
  138. Assert(currentMemory >= byteCount);
  139. byteCount = min(byteCount, currentMemory);
  140. currentMemory = currentMemory - byteCount;
  141. if (memoryAllocationCallback != NULL)
  142. {
  143. // The callback should be minimal, with no possibility of calling back to us.
  144. // Note that this can be called both in script or out of script.
  145. memoryAllocationCallback(context, allocationEvent, byteCount);
  146. }
  147. }
  148. };