Skip to content

Commit ec2f534

Browse files
authored
Make DomainAssembly create its Assembly in its constructor and remove separate allocate load level (#107224)
There is no logical distinction between creating a `DomainAssembly` and an `Assembly` now. Making `DomainAssembly` create the `Assembly` as soon as it is constructed should make it so that we can switch assorted things that currently store/use `DomainAssembly` to `Assembly`, since they will be created at the same time.
1 parent f8e9dd1 commit ec2f534

File tree

8 files changed

+77
-166
lines changed

8 files changed

+77
-166
lines changed

src/coreclr/vm/appdomain.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ void SystemDomain::LoadBaseSystemClasses()
10351035

10361036
// Only partially load the system assembly. Other parts of the code will want to access
10371037
// the globals in this function before finishing the load.
1038-
m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_POST_ALLOCATE)->GetAssembly();
1038+
m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_BEFORE_TYPE_LOAD)->GetAssembly();
10391039

10401040
// Set up binder for CoreLib
10411041
CoreLibBinder::AttachModule(m_pSystemAssembly->GetModule());
@@ -2006,8 +2006,7 @@ static const char *fileLoadLevelName[] =
20062006
{
20072007
"CREATE", // FILE_LOAD_CREATE
20082008
"BEGIN", // FILE_LOAD_BEGIN
2009-
"ALLOCATE", // FILE_LOAD_ALLOCATE
2010-
"POST_ALLOCATE", // FILE_LOAD_POST_ALLOCATE
2009+
"BEFORE_TYPE_LOAD", // FILE_LOAD_BEFORE_TYPE_LOAD
20112010
"EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
20122011
"DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
20132012
"VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
@@ -2074,7 +2073,6 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
20742073
#ifndef DACCESS_COMPILE
20752074
switch(level)
20762075
{
2077-
case FILE_LOAD_ALLOCATE:
20782076
case FILE_LOAD_DELIVER_EVENTS:
20792077
case FILE_LOADED:
20802078
case FILE_ACTIVE: // The timing of stress logs is not critical, so even for the FILE_ACTIVE stage we need not do it while the m_pList lock is held.
@@ -2494,7 +2492,9 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
24942492

24952493
// Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
24962494
// a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
2497-
NewHolder<DomainAssembly> pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator);
2495+
AllocMemTracker amTracker;
2496+
AllocMemTracker *pamTracker = &amTracker;
2497+
NewHolder<DomainAssembly> pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator, pamTracker);
24982498

24992499
LoadLockHolder lock(this);
25002500

@@ -2511,6 +2511,7 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
25112511
registerNewAssembly = true;
25122512
fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly);
25132513
pDomainAssembly.SuppressRelease();
2514+
pamTracker->SuppressRelease();
25142515
if (pDomainAssembly->IsCollectible())
25152516
{
25162517
// We add the assembly to the LoaderAllocator only when we are sure that it can be added

src/coreclr/vm/assembly.cpp

Lines changed: 35 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar
436436
AppDomain* pDomain = ::GetAppDomain();
437437

438438
NewHolder<DomainAssembly> pDomainAssembly;
439+
Assembly* pAssem;
439440
BOOL createdNewAssemblyLoaderAllocator = FALSE;
440441

441442
{
@@ -479,7 +480,9 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar
479480
}
480481

481482
// Create a domain assembly
482-
pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator);
483+
pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator, pamTracker);
484+
pAssem = pDomainAssembly->GetAssembly();
485+
pAssem->m_isDynamic = true;
483486
if (pDomainAssembly->IsCollectible())
484487
{
485488
// We add the assembly to the LoaderAllocator only when we are sure that it can be added
@@ -489,66 +492,47 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar
489492
}
490493

491494
// Start loading process
495+
if (createdNewAssemblyLoaderAllocator)
492496
{
493-
// Create a concrete assembly
494-
// (!Do not remove scoping brace: order is important here: the Assembly holder must destruct before the AllocMemTracker!)
495-
NewHolder<Assembly> pAssem;
497+
GCX_PREEMP();
496498

497-
{
498-
GCX_PREEMP();
499-
// Assembly::Create will call SuppressRelease on the NewHolder that holds the LoaderAllocator when it transfers ownership
500-
pAssem = Assembly::Create(pPEAssembly, pDomainAssembly->GetDebuggerInfoBits(), pLoaderAllocator->IsCollectible(), pamTracker, pLoaderAllocator);
499+
// Initializing the virtual call stub manager is delayed to remove the need for the LoaderAllocator destructor to properly handle
500+
// uninitializing the VSD system. (There is a need to suspend the runtime, and that's tricky)
501+
pLoaderAllocator->InitVirtualCallStubManager();
502+
}
501503

502-
ReflectionModule* pModule = (ReflectionModule*) pAssem->GetModule();
504+
{
505+
GCX_PREEMP();
503506

504-
if (createdNewAssemblyLoaderAllocator)
505-
{
506-
// Initializing the virtual call stub manager is delayed to remove the need for the LoaderAllocator destructor to properly handle
507-
// uninitializing the VSD system. (There is a need to suspend the runtime, and that's tricky)
508-
pLoaderAllocator->InitVirtualCallStubManager();
509-
}
510-
}
507+
// Finish loading process
508+
// <TODO> would be REALLY nice to unify this with main loading loop </TODO>
509+
pDomainAssembly->Begin();
510+
pDomainAssembly->DeliverSyncEvents();
511+
pDomainAssembly->DeliverAsyncEvents();
512+
pDomainAssembly->FinishLoad();
513+
pDomainAssembly->ClearLoading();
514+
pDomainAssembly->m_level = FILE_ACTIVE;
515+
}
511516

512-
pAssem->m_isDynamic = true;
517+
{
518+
CANNOTTHROWCOMPLUSEXCEPTION();
519+
FAULT_FORBID();
513520

514-
//we need to suppress release for pAssem to avoid double release
515-
pAssem.SuppressRelease ();
521+
// Cannot fail after this point
516522

517-
{
518-
GCX_PREEMP();
519-
520-
// Finish loading process
521-
// <TODO> would be REALLY nice to unify this with main loading loop </TODO>
522-
pDomainAssembly->Begin();
523-
pDomainAssembly->SetAssembly(pAssem);
524-
pDomainAssembly->m_level = FILE_LOAD_ALLOCATE;
525-
pDomainAssembly->DeliverSyncEvents();
526-
pDomainAssembly->DeliverAsyncEvents();
527-
pDomainAssembly->FinishLoad();
528-
pDomainAssembly->ClearLoading();
529-
pDomainAssembly->m_level = FILE_ACTIVE;
530-
}
523+
pDomainAssembly.SuppressRelease();
524+
pamTracker->SuppressRelease();
531525

526+
// Once we reach this point, the loader allocator lifetime is controlled by the Assembly object.
527+
if (createdNewAssemblyLoaderAllocator)
532528
{
533-
CANNOTTHROWCOMPLUSEXCEPTION();
534-
FAULT_FORBID();
535-
536-
//Cannot fail after this point
537-
538-
pDomainAssembly.SuppressRelease(); // This also effectively suppresses the release of the pAssem
539-
pamTracker->SuppressRelease();
540-
541-
// Once we reach this point, the loader allocator lifetime is controlled by the Assembly object.
542-
if (createdNewAssemblyLoaderAllocator)
543-
{
544-
// Atomically transfer ownership to the managed heap
545-
pLoaderAllocator->ActivateManagedTracking();
546-
pLoaderAllocator.SuppressRelease();
547-
}
548-
549-
pAssem->SetIsTenured();
550-
pRetVal = pAssem;
529+
// Atomically transfer ownership to the managed heap
530+
pLoaderAllocator->ActivateManagedTracking();
531+
pLoaderAllocator.SuppressRelease();
551532
}
533+
534+
pAssem->SetIsTenured();
535+
pRetVal = pAssem;
552536
}
553537

554538
RETURN pRetVal;

src/coreclr/vm/ceeload.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4473,24 +4473,6 @@ VOID Module::EnsureActive()
44734473

44744474
#include <optdefault.h>
44754475

4476-
4477-
#ifndef DACCESS_COMPILE
4478-
4479-
VOID Module::EnsureAllocated()
4480-
{
4481-
CONTRACTL
4482-
{
4483-
THROWS;
4484-
GC_TRIGGERS;
4485-
MODE_ANY;
4486-
}
4487-
CONTRACTL_END;
4488-
4489-
GetDomainAssembly()->EnsureAllocated();
4490-
}
4491-
4492-
#endif // !DACCESS_COMPILE
4493-
44944476
CHECK Module::CheckActivated()
44954477
{
44964478
CONTRACTL

src/coreclr/vm/ceeload.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,6 @@ class Module : public ModuleBase
948948

949949
#ifndef DACCESS_COMPILE
950950
VOID EnsureActive();
951-
VOID EnsureAllocated();
952951
#endif
953952

954953
CHECK CheckActivated();

src/coreclr/vm/domainassembly.cpp

Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@
2424
#include "peimagelayout.inl"
2525

2626
#ifndef DACCESS_COMPILE
27-
DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator) :
28-
m_pAssembly(NULL),
29-
m_pPEAssembly(pPEAssembly),
30-
m_pModule(NULL),
31-
m_fCollectible(pLoaderAllocator->IsCollectible()),
32-
m_NextDomainAssemblyInSameALC(NULL),
33-
m_pLoaderAllocator(pLoaderAllocator),
34-
m_level(FILE_LOAD_CREATE),
35-
m_loading(TRUE),
36-
m_pError(NULL),
37-
m_bDisableActivationCheck(FALSE),
38-
m_fHostAssemblyPublished(FALSE),
39-
m_debuggerFlags(DACF_NONE),
40-
m_notifyflags(NOT_NOTIFIED),
41-
m_fDebuggerUnloadStarted(FALSE)
27+
DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator, AllocMemTracker* memTracker)
28+
: m_pAssembly(NULL)
29+
, m_pPEAssembly(pPEAssembly)
30+
, m_pModule(NULL)
31+
, m_fCollectible(pLoaderAllocator->IsCollectible())
32+
, m_NextDomainAssemblyInSameALC(NULL)
33+
, m_pLoaderAllocator(pLoaderAllocator)
34+
, m_level(FILE_LOAD_CREATE)
35+
, m_loading(TRUE)
36+
, m_pError(NULL)
37+
, m_bDisableActivationCheck(FALSE)
38+
, m_fHostAssemblyPublished(FALSE)
39+
, m_debuggerFlags(DACF_NONE)
40+
, m_notifyflags(NOT_NOTIFIED)
41+
, m_fDebuggerUnloadStarted(FALSE)
4242
{
4343
CONTRACTL
4444
{
@@ -53,6 +53,18 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader
5353
pPEAssembly->ValidateForExecution();
5454

5555
SetupDebuggingConfig();
56+
57+
// Create the Assembly
58+
NewHolder<Assembly> assembly = Assembly::Create(GetPEAssembly(), GetDebuggerInfoBits(), IsCollectible(), memTracker, IsCollectible() ? GetLoaderAllocator() : NULL);
59+
assembly->SetIsTenured();
60+
61+
m_pAssembly = assembly.Extract();
62+
m_pModule = m_pAssembly->GetModule();
63+
64+
m_pAssembly->SetDomainAssembly(this);
65+
66+
// Creating the Assembly should have ensured the PEAssembly is loaded
67+
_ASSERT(GetPEAssembly()->IsLoaded());
5668
}
5769

5870
DomainAssembly::~DomainAssembly()
@@ -319,12 +331,8 @@ BOOL DomainAssembly::DoIncrementalLoad(FileLoadLevel level)
319331
Begin();
320332
break;
321333

322-
case FILE_LOAD_ALLOCATE:
323-
Allocate();
324-
break;
325-
326-
case FILE_LOAD_POST_ALLOCATE:
327-
PostAllocate();
334+
case FILE_LOAD_BEFORE_TYPE_LOAD:
335+
BeforeTypeLoad();
328336
break;
329337

330338
case FILE_LOAD_EAGER_FIXUPS:
@@ -365,7 +373,7 @@ BOOL DomainAssembly::DoIncrementalLoad(FileLoadLevel level)
365373
return TRUE;
366374
}
367375

368-
void DomainAssembly::PostAllocate()
376+
void DomainAssembly::BeforeTypeLoad()
369377
{
370378
CONTRACTL
371379
{
@@ -482,19 +490,6 @@ void DomainAssembly::Activate()
482490
RETURN;
483491
}
484492

485-
void DomainAssembly::SetAssembly(Assembly* pAssembly)
486-
{
487-
STANDARD_VM_CONTRACT;
488-
489-
_ASSERTE(pAssembly->GetModule()->GetPEAssembly()==m_pPEAssembly);
490-
_ASSERTE(m_pAssembly == NULL);
491-
492-
m_pAssembly = pAssembly;
493-
m_pModule = pAssembly->GetModule();
494-
495-
pAssembly->SetDomainAssembly(this);
496-
}
497-
498493
void DomainAssembly::Begin()
499494
{
500495
STANDARD_VM_CONTRACT;
@@ -540,38 +535,6 @@ void DomainAssembly::UnregisterFromHostAssembly()
540535
}
541536
}
542537

543-
void DomainAssembly::Allocate()
544-
{
545-
CONTRACTL
546-
{
547-
INSTANCE_CHECK;
548-
STANDARD_VM_CHECK;
549-
INJECT_FAULT(COMPlusThrowOM(););
550-
PRECONDITION(m_pAssembly == NULL);
551-
}
552-
CONTRACTL_END;
553-
554-
AllocMemTracker amTracker;
555-
AllocMemTracker * pamTracker = &amTracker;
556-
557-
Assembly * pAssembly;
558-
{
559-
// Order is important here - in the case of an exception, the Assembly holder must destruct before the AllocMemTracker declared above.
560-
NewHolder<Assembly> assemblyHolder(NULL);
561-
562-
assemblyHolder = pAssembly = Assembly::Create(GetPEAssembly(), GetDebuggerInfoBits(), this->IsCollectible(), pamTracker, this->IsCollectible() ? this->GetLoaderAllocator() : NULL);
563-
assemblyHolder->SetIsTenured();
564-
565-
pamTracker->SuppressRelease();
566-
assemblyHolder.SuppressRelease();
567-
}
568-
569-
SetAssembly(pAssembly);
570-
571-
// Creating the Assembly should have ensured the PEAssembly is loaded
572-
_ASSERT(GetPEAssembly()->IsLoaded());
573-
}
574-
575538
void DomainAssembly::DeliverAsyncEvents()
576539
{
577540
CONTRACTL

src/coreclr/vm/domainassembly.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,14 @@ enum FileLoadLevel
3535

3636
FILE_LOAD_CREATE,
3737
FILE_LOAD_BEGIN,
38-
FILE_LOAD_ALLOCATE,
39-
FILE_LOAD_POST_ALLOCATE,
38+
FILE_LOAD_BEFORE_TYPE_LOAD,
4039
FILE_LOAD_EAGER_FIXUPS,
4140
FILE_LOAD_DELIVER_EVENTS,
4241
FILE_LOAD_VTABLE_FIXUPS,
4342
FILE_LOADED, // Loaded by not yet active
4443
FILE_ACTIVE // Fully active (constructors run & security checked)
4544
};
4645

47-
4846
enum NotificationStatus
4947
{
5048
NOT_NOTIFIED=0,
@@ -186,13 +184,6 @@ class DomainAssembly final
186184
return EnsureLoadLevel(FILE_ACTIVE);
187185
}
188186

189-
// Ensure that an assembly has reached at least the Allocated state. Throw if not.
190-
void EnsureAllocated()
191-
{
192-
WRAPPER_NO_CONTRACT;
193-
return EnsureLoadLevel(FILE_LOAD_ALLOCATE);
194-
}
195-
196187
// EnsureLoadLevel is a generic routine used to ensure that the file is not in a delay loaded
197188
// state (unless it needs to be.) This should be used when a particular level of loading
198189
// is required for an operation. Note that deadlocks are tolerated so the level may be one
@@ -260,16 +251,15 @@ class DomainAssembly final
260251
friend class Module;
261252
friend class FileLoadLock;
262253

263-
DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator);
254+
DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator, AllocMemTracker* memTracker);
264255

265256
BOOL DoIncrementalLoad(FileLoadLevel targetLevel);
266257
void ClearLoading() { LIMITED_METHOD_CONTRACT; m_loading = FALSE; }
267258
void SetLoadLevel(FileLoadLevel level) { LIMITED_METHOD_CONTRACT; m_level = level; }
268259

269260
#ifndef DACCESS_COMPILE
270261
void Begin();
271-
void Allocate();
272-
void PostAllocate();
262+
void BeforeTypeLoad();
273263
void EagerFixups();
274264
void VtableFixups();
275265
void DeliverSyncEvents();
@@ -283,7 +273,6 @@ class DomainAssembly final
283273

284274
// This should be used to permanently set the load to fail. Do not use with transient conditions
285275
void SetError(Exception *ex);
286-
void SetAssembly(Assembly* pAssembly);
287276

288277
void SetProfilerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|= PROFILER_NOTIFIED; }
289278
void SetDebuggerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NOTIFIED; }

0 commit comments

Comments
 (0)