DelayFreeArrayBufferHelper.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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 "RuntimeLibraryPch.h"
  6. namespace Js
  7. {
  8. bool DelayedFreeArrayBuffer::HasAnyItem()
  9. {
  10. return !this->listOfBuffers.Empty();
  11. }
  12. void DelayedFreeArrayBuffer::Push(ArrayBufferContentForDelayedFreeBase* item)
  13. {
  14. AssertOrFailFast(item);
  15. this->listOfBuffers.Push(item);
  16. }
  17. void Js::DelayedFreeArrayBuffer::ResetToNoMarkObject()
  18. {
  19. this->listOfBuffers.Map([](Js::ArrayBufferContentForDelayedFreeBase* item) {
  20. Assert(item != nullptr);
  21. item->SetMarkBit(false);
  22. });
  23. }
  24. void DelayedFreeArrayBuffer::ReleaseOnlyNonMarkedObject()
  25. {
  26. FOREACH_SLIST_ENTRY_EDITING(ArrayBufferContentForDelayedFreeBase*, item, &this->listOfBuffers, iter)
  27. {
  28. if (!item->IsMarked())
  29. {
  30. item->Release();
  31. item->ClearSelfOnly();
  32. iter.RemoveCurrent();
  33. }
  34. else
  35. {
  36. // Reset the mark bit
  37. item->SetMarkBit(false);
  38. }
  39. } NEXT_SLIST_ENTRY_EDITING
  40. }
  41. void DelayedFreeArrayBuffer::CheckAndMarkObject(void * candidate)
  42. {
  43. this->listOfBuffers.Map([&](Js::ArrayBufferContentForDelayedFreeBase* item) {
  44. if (!item->IsMarked() && item->IsAddressPartOfBuffer(candidate))
  45. {
  46. item->SetMarkBit(true);
  47. }
  48. });
  49. }
  50. void DelayedFreeArrayBuffer::ClearAll()
  51. {
  52. if (HasAnyItem())
  53. {
  54. this->listOfBuffers.Map([](Js::ArrayBufferContentForDelayedFreeBase* item) {
  55. item->Release();
  56. item->ClearSelfOnly();
  57. });
  58. this->listOfBuffers.Clear();
  59. }
  60. }
  61. void DelayedFreeArrayBuffer::ScanStack(void ** stackTop, size_t byteCount, void ** registers, size_t registersByteCount)
  62. {
  63. AssertOrFailFast(HasAnyItem());
  64. ResetToNoMarkObject();
  65. auto BufferFreeFunction = [&](void ** obj, size_t byteCount)
  66. {
  67. Assert(byteCount != 0);
  68. Assert(byteCount % sizeof(void *) == 0);
  69. void ** objEnd = obj + (byteCount / sizeof(void *));
  70. do
  71. {
  72. // We need to ensure that the compiler does not reintroduce reads to the object after inlining.
  73. // This could cause the value to change after the marking checks (e.g., the null/low address check).
  74. // Intrinsics avoid the expensive memory barrier on ARM (due to /volatile:ms).
  75. #if defined(_M_ARM64)
  76. void * candidate = reinterpret_cast<void *>(__iso_volatile_load64(reinterpret_cast<volatile __int64 *>(obj)));
  77. #elif defined(_M_ARM)
  78. void * candidate = reinterpret_cast<void *>(__iso_volatile_load32(reinterpret_cast<volatile __int32 *>(obj)));
  79. #else
  80. void * candidate = *(static_cast<void * volatile *>(obj));
  81. #endif
  82. CheckAndMarkObject(candidate);
  83. obj++;
  84. } while (obj != objEnd);
  85. };
  86. BufferFreeFunction(registers, registersByteCount);
  87. BufferFreeFunction(stackTop, byteCount);
  88. ReleaseOnlyNonMarkedObject();
  89. }
  90. void ArrayBufferContentForDelayedFreeBase::Release()
  91. {
  92. // this function will be called when we are releasing instance from the listOfBuffer which we have delayed.
  93. RefCountedBuffer *content = this->buffer;
  94. this->buffer = nullptr;
  95. long refCount = content->Release();
  96. if (refCount == 0)
  97. {
  98. FreeTheBuffer(content->GetBuffer());
  99. HeapDelete(content);
  100. }
  101. }
  102. bool ArrayBufferContentForDelayedFreeBase::IsAddressPartOfBuffer(void *obj)
  103. {
  104. void *start = this->buffer->GetBuffer();
  105. void *end = this->buffer->GetBuffer() + this->bufferLength;
  106. return start <= obj && obj < end;
  107. }
  108. }