blob: 045c388a8fc85ec0d1ba3c72feaa470c549c08d3 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
// TODO, this should be elsewhere
#define RecyclerNewImplicitRoot(recycler,T,...) AllocatorNewBase(Recycler, recycler, NoThrowAllocImplicitRoot, T, __VA_ARGS__)
// Forward reference
class RecyclerTestObject;
// A "Location" represents a location in memory where object references (ReccylerTestObject *s) are stored.
// It includes a "type" that defines how the reference should be read or written.
// This allows us to specify special handling for certain location types,
// such as pinned roots, software write barrier locations, tagged locations for tracked objects, etc.
class Location
{
private:
enum class Type
{
Scanned, // For regular locations in scanned objects (or stack locations)
Rooted, // This is a non-heap location that's explicitly rooted.
Barrier, // Write barrier location
Tagged, // Tagged location (used in tracked objects)
ImplicitRoot, // Uses ImplicitRootBit to hold reference
};
class ImplicitRootHolder
{
private:
Field(RecyclerTestObject *) reference;
public:
ImplicitRootHolder(RecyclerTestObject * reference)
: reference(reference)
{
VerifyCondition(reference != nullptr);
}
RecyclerTestObject * GetReference() const
{
VerifyCondition(this->reference != nullptr);
return this->reference;
}
};
Location(RecyclerTestObject ** location, Type type) :
location(location), type(type)
{
VerifyCondition(location != nullptr);
}
public:
static Location Scanned(RecyclerTestObject ** location)
{
return Location(location, Type::Scanned);
}
static Location Rooted(RecyclerTestObject ** location)
{
return Location(location, Type::Rooted);
}
static Location Barrier(RecyclerTestObject ** location)
{
return Location(location, Type::Barrier);
}
static Location Tagged(RecyclerTestObject ** location)
{
return Location(location, Type::Tagged);
}
static Location ImplicitRoot(RecyclerTestObject ** location)
{
return Location(location, Type::ImplicitRoot);
}
RecyclerTestObject * Get()
{
switch (type)
{
case Type::Scanned:
return *location;
case Type::Rooted:
return *location;
case Type::Barrier:
return *location;
case Type::Tagged:
return Untag(*location);
case Type::ImplicitRoot:
// The stored location actually contains a pointer to the ImplicitRootHolder
ImplicitRootHolder * holder = (ImplicitRootHolder *)(*location);
if (holder == nullptr)
{
return nullptr;
}
return holder->GetReference();
}
// Shouldn't get here
VerifyCondition(false);
return nullptr;
}
void Set(RecyclerTestObject * value)
{
switch (type)
{
case Type::Scanned:
*location = value;
return;
case Type::Rooted:
Unroot();
*location = value;
Root();
return;
case Type::Barrier:
*location = value;
if (value != nullptr)
{
RecyclerWriteBarrierManager::WriteBarrier(location);
}
return;
case Type::Tagged:
*location = Tag(value);
return;
case Type::ImplicitRoot:
// The stored location actually contains a pointer to the ImplicitRootHolder
ImplicitRootHolder * holder = (ImplicitRootHolder *)(*location);
if (holder != nullptr)
{
// Free the implicit root
// TODO: This should be better encapsulated
RecyclerHeapObjectInfo heapObject;
bool found = recyclerInstance->FindHeapObject(holder, FindHeapObjectFlags_VerifyFreeBitForAttribute, heapObject);
VerifyCondition(found);
// Zero pointers in order to eliminate false-positives
memset(holder, 0, heapObject.GetSize());
bool success = heapObject.ClearImplicitRootBit();
VerifyCondition(success);
*location = nullptr;
}
if (value != nullptr)
{
// Create new holder object
holder = RecyclerNewImplicitRoot(recyclerInstance, ImplicitRootHolder, value);
VerifyCondition(holder != nullptr);
// Store holder back to the location
*location = (RecyclerTestObject *)holder;
}
return;
}
// Shouldn't get here
VerifyCondition(false);
}
static RecyclerTestObject * Tag(RecyclerTestObject * untagged)
{
if (untagged == nullptr)
{
return nullptr;
}
else
{
size_t value = (size_t)untagged;
VerifyCondition((value & 0x1) == 0);
value |= 0x1;
return (RecyclerTestObject *)value;
}
}
static RecyclerTestObject * Untag(RecyclerTestObject * tagged)
{
if (tagged == nullptr)
{
return nullptr;
}
else
{
size_t value = (size_t)tagged;
VerifyCondition((value & 0x1) == 0x1);
value &= ~(0x1);
return (RecyclerTestObject *)value;
}
}
private:
void Unroot()
{
if (*location != nullptr)
{
recyclerInstance->RootRelease(*location);
}
}
void Root()
{
if (*location != nullptr)
{
recyclerInstance->RootAddRef(*location);
}
}
private:
RecyclerTestObject ** location;
Type type;
};