Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/gc/env/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <assert.h>
Expand Down
5 changes: 5 additions & 0 deletions src/gc/env/gcenv.base.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ inline void* ALIGN_DOWN(void* ptr, size_t alignment)
return reinterpret_cast<void*>(ALIGN_DOWN(as_size_t, alignment));
}

inline int GetRandomInt(int max)
{
return rand() % max;
}

typedef struct _PROCESSOR_NUMBER {
uint16_t Group;
uint8_t Number;
Expand Down
2 changes: 2 additions & 0 deletions src/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class GCToEEInterface
static bool IsGCThread();
static bool WasCurrentThreadCreatedByGC();
static bool CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name);
static void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback);
static void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*));
};

#endif // __GCENV_EE_H__
11 changes: 11 additions & 0 deletions src/gc/gcenv.ee.standalone.inl
Original file line number Diff line number Diff line change
Expand Up @@ -258,5 +258,16 @@ inline bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg,
return g_theGCToCLR->CreateThread(threadStart, arg, is_suspendable, name);
}

inline void GCToEEInterface::WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->WalkAsyncPinnedForPromotion(object, sc, callback);
}

inline void GCToEEInterface::WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*))
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->WalkAsyncPinned(object, context, callback);
}

#endif // __GCTOENV_EE_STANDALONE_INL__
4 changes: 2 additions & 2 deletions src/gc/gchandletable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secon
return handle;
}

void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget)
void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE))
{
// assumption - the IGCHandleStore is an instance of GCHandleStore
GCHandleStore* other = static_cast<GCHandleStore*>(pTarget);
::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket);
::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket, clearIfComplete, setHandle);
}

bool GCHandleStore::EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context)
Expand Down
2 changes: 1 addition & 1 deletion src/gc/gchandletableimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GCHandleStore : public IGCHandleStore

virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary);

virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget);
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfCompleteCallback)(Object* object), void (*setHandle)(Object* object, OBJECTHANDLE handle));

virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context);

Expand Down
32 changes: 32 additions & 0 deletions src/gc/gcinterface.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,38 @@ class IGCToCLR {
// or a server GC thread.
virtual
bool WasCurrentThreadCreatedByGC() = 0;

// Given an object, if this object is an instance of `System.Threading.OverlappedData`,
// and the runtime treats instances of this class specially, traverses the objects that
// are directly or (once) indirectly pinned by this object and reports them to the GC for
// the purposes of relocation and promotion.
//
// Overlapped objects are very special and as such the objects they wrap can't be promoted in
// the same manner as normal objects. This callback gives the EE the opportunity to hide these
// details, if they are implemented at all.
//
// This function is a no-op if "object" is not an OverlappedData object.
virtual
void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) = 0;

// Given an object, if this object is an instance of `System.Threading.OverlappedData` and the
// runtime treats instances of this class specially, traverses the objects that are directly
// or once indirectly pinned by this object and invokes the given callback on them. The callback
// is passed the following arguments:
// Object* "from" - The object that "caused" the "to" object to be pinned. If a single object
// is pinned directly by this OverlappedData, this object will be the
// OverlappedData object itself. If an array is pinned by this OverlappedData,
// this object will be the pinned array.
// Object* "to" - The object that is pinned by the "from" object. If a single object is pinned
// by an OverlappedData, "to" will be that single object. If an array is pinned
// by an OverlappedData, the callback will be invoked on all elements of that
// array and each element will be a "to" object.
// void* "context" - Passed verbatim from "WalkOverlappedObject" to the callback function.
// The "context" argument will be passed directly to the callback without modification or inspection.
//
// This function is a no-op if "object" is not an OverlappedData object.
virtual
void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)) = 0;
};

#endif // _GCINTERFACE_EE_H_
31 changes: 20 additions & 11 deletions src/gc/gcinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ struct WriteBarrierParameters
uint8_t* write_watch_table;
};

// Opaque type for tracking object pointers
#ifndef DACCESS_COMPILE
struct OBJECTHANDLE__
{
void* unused;
};
typedef struct OBJECTHANDLE__* OBJECTHANDLE;
#else
typedef uintptr_t OBJECTHANDLE;
#endif

/*
* Scanning callback.
*/
Expand Down Expand Up @@ -393,16 +404,7 @@ typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlag
typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent);
typedef bool (* async_pin_enum_fn)(Object* object, void* context);

// Opaque type for tracking object pointers
#ifndef DACCESS_COMPILE
struct OBJECTHANDLE__
{
void* unused;
};
typedef struct OBJECTHANDLE__* OBJECTHANDLE;
#else
typedef uintptr_t OBJECTHANDLE;
#endif


class IGCHandleStore {
public:
Expand All @@ -419,7 +421,14 @@ class IGCHandleStore {

virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0;

virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget) = 0;
// Relocates async pinned handles from a condemned handle store to the default domain's handle store.
//
// The two callbacks are called when:
// 1. clearIfComplete is called whenever the handle table observes an async pin that is still live.
// The callback gives a chance for the EE to unpin the referents if the overlapped operation is complete.
// 2. setHandle is called whenever the GC has relocated the async pin to a new handle table. The passed-in
// handle is the newly-allocated handle in the default domain that should be assigned to the overlapped object.
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)) = 0;

virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) = 0;

Expand Down
64 changes: 26 additions & 38 deletions src/gc/handletable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
#include "objecthandle.h"
#include "handletablepriv.h"

#ifndef FEATURE_REDHAWK
#include "nativeoverlapped.h"
#endif

/****************************************************************************
*
* FORWARD DECLARATIONS
Expand Down Expand Up @@ -626,34 +622,31 @@ void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value)
FireEtwSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId());
FireEtwPrvSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId());

#ifndef FEATURE_REDHAWK
// Also fire the things pinned by Async pinned handles
if (hndType == HNDTYPE_ASYNCPINNED)
{
if (value->GetMethodTable() == g_pOverlappedDataClass)
// the closure passed to "WalkOverlappedObject" is not permitted to implicitly
// capture any variables in this scope, since WalkForOverlappedObject takes a bare
// function pointer and context pointer as arguments. We can still /explicitly/
// close over values in this scope by doing what the compiler would do and introduce
// a structure that contains all of the things we closed over, while passing a pointer
// to this structure as our closure's context pointer.
struct ClosureCapture
{
OverlappedDataObject* overlapped = (OverlappedDataObject*) value;
if (overlapped->m_isArray)
{
ArrayBase* pUserObject = (ArrayBase*)OBJECTREFToObject(overlapped->m_userObject);
Object **ppObj = (Object**)pUserObject->GetDataPtr(TRUE);
size_t num = pUserObject->GetNumComponents();
for (size_t i = 0; i < num; i ++)
{
value = ppObj[i];
uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0;
FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId());
}
}
else
{
value = OBJECTREF_TO_UNCHECKED_OBJECTREF(overlapped->m_userObject);
uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0;
FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId());
}
}
AppDomain* pAppDomain;
Object* overlapped;
};

ClosureCapture captured;
captured.pAppDomain = pAppDomain;
captured.overlapped = value;
GCToEEInterface::WalkAsyncPinned(value, &captured, [](Object*, Object* to, void* ctx)
{
ClosureCapture* captured = reinterpret_cast<ClosureCapture*>(ctx);
uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0;
FireEtwSetGCHandle(captured->overlapped, to, HNDTYPE_PINNED, generation, (int64_t) captured->pAppDomain, GetClrInstanceId());
});
}
#endif // FEATURE_REDHAWK
}
#else
UNREFERENCED_PARAMETER(handle);
Expand Down Expand Up @@ -709,14 +702,12 @@ void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref)
int generation = g_theGCHeap->WhichGeneration(value);
uint32_t uType = HandleFetchType(handle);

#ifndef FEATURE_REDHAWK
//OverlappedData need special treatment: because all user data pointed by it needs to be reported by this handle,
//its age is consider to be min age of the user data, to be simple, we just make it 0
if (uType == HNDTYPE_ASYNCPINNED && objref->GetGCSafeMethodTable () == g_pOverlappedDataClass)
if (uType == HNDTYPE_ASYNCPINNED)
{
generation = 0;
}
#endif // !FEATURE_REDHAWK

if (uType == HNDTYPE_DEPENDENT)
{
Expand Down Expand Up @@ -1165,7 +1156,6 @@ uint32_t HndCountAllHandles(BOOL fUseLocks)

BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context)
{
#ifndef FEATURE_REDHAWK
CONTRACTL
{
NOTHROW;
Expand All @@ -1186,14 +1176,13 @@ BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* contex
}

return result;
#else
return true;
#endif // !FEATURE_REDHAWK
}

void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget)
void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource,
HandleTableBucket *pTarget,
void (*clearIfComplete)(Object* object),
void (*setHandle)(Object* object, OBJECTHANDLE handle))
{
#ifndef FEATURE_REDHAWK
CONTRACTL
{
NOTHROW;
Expand All @@ -1204,9 +1193,8 @@ void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket
int limit = getNumberOfSlots();
for (int n = 0; n < limit; n ++ )
{
TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]));
TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]), clearIfComplete, setHandle);
}
#endif // !FEATURE_REDHAWK
}

/*--------------------------------------------------------------------------*/
Expand Down
Loading