blob: bf126d8474a96295dd45b93f05760be27fe39b5a [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
namespace Js
{
bool DelayedFreeArrayBuffer::HasAnyItem()
{
return !this->listOfBuffers.Empty();
}
void DelayedFreeArrayBuffer::Push(ArrayBufferContentForDelayedFreeBase* item)
{
AssertOrFailFast(item);
this->listOfBuffers.Push(item);
}
void Js::DelayedFreeArrayBuffer::ResetToNoMarkObject()
{
this->listOfBuffers.Map([](Js::ArrayBufferContentForDelayedFreeBase* item) {
Assert(item != nullptr);
item->SetMarkBit(false);
});
}
void DelayedFreeArrayBuffer::ReleaseOnlyNonMarkedObject()
{
FOREACH_SLIST_ENTRY_EDITING(ArrayBufferContentForDelayedFreeBase*, item, &this->listOfBuffers, iter)
{
if (!item->IsMarked())
{
item->Release();
item->ClearSelfOnly();
iter.RemoveCurrent();
}
else
{
// Reset the mark bit
item->SetMarkBit(false);
}
} NEXT_SLIST_ENTRY_EDITING
}
void DelayedFreeArrayBuffer::CheckAndMarkObject(void * candidate)
{
this->listOfBuffers.Map([&](Js::ArrayBufferContentForDelayedFreeBase* item) {
if (!item->IsMarked() && item->IsAddressPartOfBuffer(candidate))
{
item->SetMarkBit(true);
}
});
}
void DelayedFreeArrayBuffer::ClearAll()
{
if (HasAnyItem())
{
this->listOfBuffers.Map([](Js::ArrayBufferContentForDelayedFreeBase* item) {
item->Release();
item->ClearSelfOnly();
});
this->listOfBuffers.Clear();
}
}
void DelayedFreeArrayBuffer::ScanStack(void ** stackTop, size_t byteCount, void ** registers, size_t registersByteCount)
{
AssertOrFailFast(HasAnyItem());
ResetToNoMarkObject();
auto BufferFreeFunction = [&](void ** obj, size_t byteCount)
{
Assert(byteCount != 0);
Assert(byteCount % sizeof(void *) == 0);
void ** objEnd = obj + (byteCount / sizeof(void *));
do
{
// We need to ensure that the compiler does not reintroduce reads to the object after inlining.
// This could cause the value to change after the marking checks (e.g., the null/low address check).
// Intrinsics avoid the expensive memory barrier on ARM (due to /volatile:ms).
#if defined(_M_ARM64)
void * candidate = reinterpret_cast<void *>(__iso_volatile_load64(reinterpret_cast<volatile __int64 *>(obj)));
#elif defined(_M_ARM)
void * candidate = reinterpret_cast<void *>(__iso_volatile_load32(reinterpret_cast<volatile __int32 *>(obj)));
#else
void * candidate = *(static_cast<void * volatile *>(obj));
#endif
CheckAndMarkObject(candidate);
obj++;
} while (obj != objEnd);
};
BufferFreeFunction(registers, registersByteCount);
BufferFreeFunction(stackTop, byteCount);
ReleaseOnlyNonMarkedObject();
}
void ArrayBufferContentForDelayedFreeBase::Release()
{
// this function will be called when we are releasing instance from the listOfBuffer which we have delayed.
RefCountedBuffer *content = this->buffer;
this->buffer = nullptr;
long refCount = content->Release();
if (refCount == 0)
{
FreeTheBuffer(content->GetBuffer());
HeapDelete(content);
}
}
bool ArrayBufferContentForDelayedFreeBase::IsAddressPartOfBuffer(void *obj)
{
void *start = this->buffer->GetBuffer();
void *end = this->buffer->GetBuffer() + this->bufferLength;
return start <= obj && obj < end;
}
}