| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "stdafx.h"
- #include "Core/RecyclerHeapMarkingContext.h"
- class RecyclerTestObject : public IRecyclerVisitedObject
- {
- protected:
- RecyclerTestObject()
- {
- generation = currentGeneration;
- }
- public:
- // IRecyclerVisitedObject implementation. We don't use FinalizableObject here as
- // RecyclerVisitedObjects need to have Trace called on them, which is not allowed for
- // FinalizableObject.
- virtual void Finalize(bool isShutdown) override { VerifyCondition(false); };
- virtual void Dispose(bool isShutdown) override { VerifyCondition(false); };
- virtual void OnMark() override {}
- virtual void Mark(RecyclerHeapHandle recycler) override { Mark(static_cast<Recycler*>(recycler)); };
- virtual void Trace(IRecyclerHeapMarkingContext* markContext) override { VerifyCondition(false); };
- virtual void Mark(Recycler * recycler) { VerifyCondition(false); };
- public:
- static void BeginWalk()
- {
- currentGeneration++;
- walkObjectCount = 0;
- walkScannedByteCount = 0;
- walkBarrierByteCount = 0;
- walkTrackedByteCount = 0;
- walkFinalizedByteCount = 0;
- walkRecyclerVisitedByteCount = 0;
- walkLeafByteCount = 0;
- maxWalkDepth = 0;
- currentWalkDepth = 0;
- wprintf(_u("-------------------------------------------\n"));
- wprintf(_u("Full heap walk starting. Current generation: %12llu\n"), (unsigned long long) currentGeneration);
- }
- static void WalkReference(RecyclerTestObject * object)
- {
- if (object != nullptr)
- {
- // See if we've already seen the location in this traversal.
- if (object->generation != currentGeneration)
- {
- // Haven't see it yet. Must be from the previous generation; increment generation and validate that.
- // Update to current generation to indicate we've seen it
- object->generation++;
- VerifyCondition(object->generation == currentGeneration);
- walkObjectCount++;
- currentWalkDepth++;
- maxWalkDepth = max(currentWalkDepth, maxWalkDepth);
- // Call virtual for object-specific behavior
- object->DoWalkObject();
- currentWalkDepth--;
- }
- }
- }
- static void EndWalk()
- {
- VerifyCondition(currentWalkDepth == 0);
- wprintf(_u("Full heap walk finished\n"));
- wprintf(_u("Object Count: %12llu\n"), (unsigned long long) walkObjectCount);
- wprintf(_u("Scanned Bytes: %12llu\n"), (unsigned long long) walkScannedByteCount);
- wprintf(_u("Barrier Bytes: %12llu\n"), (unsigned long long) walkBarrierByteCount);
- wprintf(_u("Tracked Bytes: %12llu\n"), (unsigned long long) walkTrackedByteCount);
- wprintf(_u("Finalized Bytes: %12llu\n"), (unsigned long long) walkFinalizedByteCount);
- wprintf(_u("RecyclerVisited Bytes: %12llu\n"), (unsigned long long) walkRecyclerVisitedByteCount);
- wprintf(_u("Leaf Bytes: %12llu\n"), (unsigned long long) walkLeafByteCount);
- wprintf(_u("Total Bytes: %12llu\n"), (unsigned long long) (walkScannedByteCount + walkBarrierByteCount + walkTrackedByteCount + walkFinalizedByteCount + walkLeafByteCount + walkRecyclerVisitedByteCount));
- wprintf(_u("Max Depth: %12llu\n"), (unsigned long long) maxWalkDepth);
- }
- // Virtual methods
- virtual bool TryGetRandomLocation(Location * location)
- {
- // Return false to indicate no internal locations
- // Subclasses can override this to handle their internal locations as appropriate
- return false;
- }
- virtual void DoWalkObject() = 0;
- protected:
- // Global variables
- // This global variable contains the "generation" of GC objects
- // It is used to validate the correctness of GC objects
- // It is assigned initially during object creation, and
- // updated when we walk the entire object graph in TraverseAllObjects
- static size_t currentGeneration;
- // These globals contain statistical data generated by WalkAllReferences
- static size_t walkObjectCount;
- static size_t walkScannedByteCount;
- static size_t walkLeafByteCount;
- static size_t walkBarrierByteCount;
- static size_t walkTrackedByteCount;
- static size_t walkFinalizedByteCount;
- static size_t walkRecyclerVisitedByteCount;
- static size_t currentWalkDepth;
- static size_t maxWalkDepth;
- private:
- // Instance variables
- // See comments above re currentGeneration
- Field(size_t) generation;
- };
- template <unsigned int minCount, unsigned int maxCount>
- class LeafObject : public RecyclerTestObject
- {
- private:
- LeafObject(unsigned int count) :
- count(count)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- data[i] = i;
- }
- }
- public:
- static RecyclerTestObject * New()
- {
- unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- return RecyclerNewPlusLeaf(recyclerInstance, sizeof(size_t) * count, LeafObject, count);
- }
- protected:
- virtual void DoWalkObject() override
- {
- walkLeafByteCount += sizeof(LeafObject) + count * sizeof(size_t);
- }
- private:
- Field(unsigned int) count;
- Field(size_t ) data[0];
- };
- template <unsigned int minCount, unsigned int maxCount>
- class ScannedObject : public RecyclerTestObject
- {
- private:
- ScannedObject(unsigned int count) :
- count(count)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- references[i] = nullptr;
- }
- }
- public:
- static RecyclerTestObject * New()
- {
- unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- return RecyclerNewPlus(recyclerInstance, sizeof(RecyclerTestObject *) * count, ScannedObject, count);
- }
- virtual bool TryGetRandomLocation(Location * location) override
- {
- // Get a random slot and construct a Location for it
- *location = Location::Scanned(&references[GetRandomInteger(count)]);
- return true;
- }
- protected:
- virtual void DoWalkObject() override
- {
- walkScannedByteCount += sizeof(ScannedObject) + count * sizeof(RecyclerTestObject *);
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject::WalkReference(references[i]);
- }
- }
- private:
- Field(unsigned int) count;
- FieldNoBarrier(RecyclerTestObject *) references[0]; // SWB-TODO: is this correct?
- };
- template <unsigned int minCount, unsigned int maxCount>
- class BarrierObject : public RecyclerTestObject
- {
- private:
- BarrierObject(unsigned int count) :
- count(count)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- references[i] = nullptr;
- }
- }
- public:
- static RecyclerTestObject * New()
- {
- unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- return RecyclerNewWithBarrierPlus(recyclerInstance, sizeof(RecyclerTestObject *) * count, BarrierObject, count);
- }
- virtual bool TryGetRandomLocation(Location * location) override
- {
- // Get a random slot and construct a Location for it
- *location = Location::Barrier(&references[GetRandomInteger(count)]);
- return true;
- }
- protected:
- virtual void DoWalkObject() override
- {
- walkBarrierByteCount += sizeof(BarrierObject) + count * sizeof(RecyclerTestObject *);
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject::WalkReference(references[i]);
- }
- }
- private:
- Field(unsigned int) count;
- FieldNoBarrier(RecyclerTestObject *) references[0]; // SWB-TODO: is this correct?
- };
- // TrackedObject must be a FinalizableObject (in order to be 'new'ed with RecyclerNewTrackedLeafPlusZ)
- // but it also must be a RecyclerTestObject to participate in GCStress. It must inherit from RecyclerTestObject
- // first so that the algined pointer is returned from New.
- // Fortunately, the v-tables for RecyclerTestObject and FinalizableObject line up, so the
- // IRecyclerVisitedObject/FinalizableObject calls end up in the right place.
- template <unsigned int minCount, unsigned int maxCount>
- class TrackedObject : public RecyclerTestObject, public FinalizableObject
- {
- private:
- TrackedObject(unsigned int count) :
- count(count)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- references[i] = nullptr;
- }
- }
- public:
- static RecyclerTestObject * New()
- {
- unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- return RecyclerNewTrackedLeafPlusZ(recyclerInstance, sizeof(RecyclerTestObject *) * count, TrackedObject, count);
- }
- virtual bool TryGetRandomLocation(Location * location) override
- {
- // Get a random slot and construct a Location for it
- *location = Location::Tagged(&references[GetRandomInteger(count)]);
- return true;
- }
- // Tracked object implementation
- virtual void Mark(Recycler * recycler) override
- {
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject * object = Location::Untag(references[i]);
- if (object != nullptr)
- {
- recycler->TryMarkNonInterior(object);
- }
- }
- };
- // Tracked objects are always finalize as well. Just do nothing.
- virtual void Finalize(bool isShutdown) override { }
- virtual void Dispose(bool isShutdown) override { };
- protected:
- virtual void DoWalkObject() override
- {
- walkTrackedByteCount += sizeof(TrackedObject) + count * sizeof(RecyclerTestObject *);
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject::WalkReference(Location::Untag(references[i]));
- }
- }
- private:
- Field(unsigned int) count;
- FieldNoBarrier(RecyclerTestObject *) references[0]; // SWB-TODO: is this correct?
- };
- // A type of object that is finalizable, but not traced/tracked so that it can be used to test finalization
- // for LargeHeapBlock (which currently supports the FinalizeBit, but not TrackBit)
- template <unsigned int minCount, unsigned int maxCount>
- class FinalizedObject : public RecyclerTestObject, public FinalizableObject
- {
- private:
- FinalizedObject(unsigned int count) :
- count(count)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- references[i] = nullptr;
- }
- }
- public:
- static RecyclerTestObject * New()
- {
- unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- return RecyclerNewFinalizedPlus(recyclerInstance, sizeof(RecyclerTestObject *) * count, FinalizedObject, count);
- }
- virtual bool TryGetRandomLocation(Location * location) override
- {
- // Get a random slot and construct a Location for it
- *location = Location::Scanned(&references[GetRandomInteger(count)]);
- return true;
- }
- virtual void Mark(Recycler * recycler) override { VerifyCondition(false); };
- // Finalize implementation.
- virtual void Finalize(bool isShutdown) override { }
- virtual void Dispose(bool isShutdown) override { }
- protected:
- virtual void DoWalkObject() override
- {
- walkFinalizedByteCount += sizeof(FinalizedObject) + count * sizeof(RecyclerTestObject *);
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject::WalkReference(references[i]);
- }
- }
- private:
- Field(unsigned int) count;
- FieldNoBarrier(RecyclerTestObject *) references[0]; // SWB-TODO: is this correct?
- };
- #ifdef RECYCLER_VISITED_HOST
- template <unsigned int minCount, unsigned int maxCount>
- class RecyclerVisitedObject : public RecyclerTestObject
- {
- public:
- static RecyclerTestObject * New()
- {
- // Determine a random amount of RecyclerTestObject* references to influence the size of this object.
- const unsigned int count = minCount + GetRandomInteger(maxCount - minCount + 1);
- void* mem = nullptr;
- const size_t size = sizeof(RecyclerVisitedObject) + (sizeof(RecyclerTestObject*) * count);
- // Randomly select the type of object to create
- AllocationType allocType = static_cast<AllocationType>(GetRandomInteger(static_cast<unsigned int>(AllocationType::Count)));
- switch (allocType)
- {
- case AllocationType::TraceAndFinalized:
- mem = RecyclerAllocVisitedHostTracedAndFinalized(recyclerInstance, size);
- break;
- case AllocationType::TraceOnly:
- mem = RecyclerAllocVisitedHostTraced(recyclerInstance, size);
- break;
- case AllocationType::FinalizeLeaf:
- mem = RecyclerAllocVisitedHostFinalized(recyclerInstance, size);
- break;
- default:
- Assert(allocType == AllocationType::Leaf);
- mem = RecyclerAllocLeaf(recyclerInstance, size);
- }
- // Construct the v-table, allocType, and count information for the new object.
- RecyclerVisitedObject* obj = new (mem) RecyclerVisitedObject(allocType, count);
- return obj;
- }
- virtual bool TryGetRandomLocation(Location * location) override
- {
- // Leaf types should not return a location
- if (type == AllocationType::Leaf || type == AllocationType::FinalizeLeaf)
- {
- return false;
- }
- // Get a random slot and construct a Location for it
- // Make this a Tagged location so that we won't inadvertently keep objects alive
- // in the case where this object gets put on the wrong mark stack.
- *location = Location::Tagged(&references[GetRandomInteger(count)]);
- return true;
- }
- virtual void Trace(IRecyclerHeapMarkingContext* markContext) override
- {
- VerifyCondition(type == AllocationType::TraceAndFinalized || type == AllocationType::TraceOnly);
- // Note that the pointers in the references arrary are technically tagged. However, this is ok
- // as the Mark that we're performing is an interior mark, which gets us to the right object(s).
- markContext->MarkObjects(reinterpret_cast<void**>(&references[0]), count, this);
- }
- virtual void Finalize(bool isShutdown) override
- {
- // Only types that request finalization should have Finalize called
- VerifyCondition(IsFinalizable());
- }
- virtual void Dispose(bool isShutdown) override
- {
- // Only types that request finalization should have Finalize called
- VerifyCondition(IsFinalizable());
- VerifyCondition(unmanagedResource != nullptr);
- BOOL success = ::HeapFree(GetProcessHeap(), 0, unmanagedResource);
- VerifyCondition(success != FALSE);
- unmanagedResource = nullptr;
- }
- protected:
- virtual void DoWalkObject() override
- {
- walkRecyclerVisitedByteCount += sizeof(RecyclerVisitedObject) + count * sizeof(RecyclerTestObject *);
- for (unsigned int i = 0; i < count; i++)
- {
- RecyclerTestObject::WalkReference(Location::Untag(references[i]));
- }
- }
- private:
- enum class AllocationType : unsigned int
- {
- TraceAndFinalized = 0,
- TraceOnly,
- FinalizeLeaf,
- Leaf,
- Count,
- };
- bool IsFinalizable() const { return type == AllocationType::TraceAndFinalized || type == AllocationType::FinalizeLeaf; }
- RecyclerVisitedObject(AllocationType allocType, unsigned int count) :
- count(count),
- type(allocType)
- {
- for (unsigned int i = 0; i < count; i++)
- {
- references[i] = nullptr;
- }
- if (IsFinalizable())
- {
- unmanagedResource = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, GetRandomInteger(1024));
- VerifyCondition(unmanagedResource != nullptr);
- }
- }
- Field(AllocationType) type;
- Field(void*) unmanagedResource;
- Field(unsigned int) count;
- FieldNoBarrier(RecyclerTestObject *) references[0]; // SWB-TODO: is this correct? (copied from TrackedObject)
- };
- #endif
|