Remove AppDomain unload (#20250)
authorJan Vorlicek <janvorli@microsoft.com>
Thu, 4 Oct 2018 08:18:23 +0000 (10:18 +0200)
committerGitHub <noreply@github.com>
Thu, 4 Oct 2018 08:18:23 +0000 (10:18 +0200)
* Remove AppDomain unload

This change removes all code in AppDomain that's related to AppDomain
unloading which is obsolete in CoreCLR. It also removes all calls to the
removed methods.
In few places, I have made the change simpler by taking into account the
fact that there is always just one AppDomain.

59 files changed:
src/classlibnative/bcltype/system.cpp
src/debug/daccess/dacdbiimpl.cpp
src/debug/ee/debugger.cpp
src/inc/clrconfigvalues.h
src/inc/utilcode.h
src/vm/amd64/UMThunkStub.asm
src/vm/amd64/asmconstants.h
src/vm/amd64/umthunkstub.S
src/vm/appdomain.cpp
src/vm/appdomain.hpp
src/vm/appdomain.inl
src/vm/appdomainnative.cpp
src/vm/appdomainnative.hpp
src/vm/arm/asmconstants.h
src/vm/arm/asmhelpers.S
src/vm/arm/asmhelpers.asm
src/vm/arm64/asmconstants.h
src/vm/arm64/asmhelpers.S
src/vm/arm64/asmhelpers.asm
src/vm/callhelpers.cpp
src/vm/ceemain.cpp
src/vm/codeversion.cpp
src/vm/comcallablewrapper.cpp
src/vm/cominterfacemarshaler.cpp
src/vm/comsynchronizable.cpp
src/vm/comtoclrcall.cpp
src/vm/corhost.cpp
src/vm/delegateinfo.h
src/vm/dispatchinfo.cpp
src/vm/dllimportcallback.cpp
src/vm/domainfile.cpp
src/vm/domainfile.h
src/vm/eeconfig.cpp
src/vm/eeconfig.h
src/vm/eepolicy.cpp
src/vm/eepolicy.h
src/vm/eventtrace.cpp
src/vm/finalizerthread.cpp
src/vm/finalizerthread.h
src/vm/gcenv.ee.cpp
src/vm/gchandleutilities.cpp
src/vm/i386/asmconstants.h
src/vm/i386/asmhelpers.S
src/vm/i386/asmhelpers.asm
src/vm/loaderallocator.cpp
src/vm/marshalnative.cpp
src/vm/methodtable.cpp
src/vm/nativeoverlapped.cpp
src/vm/object.cpp
src/vm/profilingenumerators.cpp
src/vm/stackprobe.cpp
src/vm/stacksampler.cpp
src/vm/stdinterfaces_wrapper.cpp
src/vm/testhookmgr.cpp
src/vm/threads.cpp
src/vm/threads.h
src/vm/threads.inl
src/vm/threadsuspend.cpp
src/vm/win32threadpool.h

index a28adac..942ac3d 100644 (file)
@@ -354,7 +354,7 @@ FCIMPL0(FC_BOOL_RET, SystemNative::HasShutdownStarted)
     // aggressively finalize objects referred to by static variables OR
     // if someone is unloading the current AppDomain AND we have started
     // finalizing objects referred to by static variables.
-    FC_RETURN_BOOL((g_fEEShutDown & ShutDown_Finalize2) || GetAppDomain()->IsFinalizing());
+    FC_RETURN_BOOL(g_fEEShutDown & ShutDown_Finalize2);
 }
 FCIMPLEND
 
index bed03ad..57f9f6b 100644 (file)
@@ -3604,10 +3604,6 @@ void DacDbiInterfaceImpl::GetCachedWinRTTypesForIIDs(
     DD_ENTER_MAY_THROW;
 
     AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
-    if (pAppDomain->IsUnloading())
-    {
-        return;
-    }
 
     {
         pTypes->Alloc(iids.Count());
@@ -3654,10 +3650,6 @@ void DacDbiInterfaceImpl::GetCachedWinRTTypes(
     DD_ENTER_MAY_THROW;
 
     AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
-    if (pAppDomain->IsUnloading())
-    {
-        return;
-    }
 
     InlineSArray<PTR_MethodTable, 32> rgMT;
     InlineSArray<GUID, 32> rgGuid;
@@ -4308,10 +4300,6 @@ void DacDbiInterfaceImpl::EnumerateAppDomains(
         // It's critical that we don't yield appdomains after the unload event has been sent.
         // See code:IDacDbiInterface#Enumeration for details.
         AppDomain * pAppDomain = iterator.GetDomain(); 
-        if (pAppDomain->IsUnloading())
-        {
-            continue;
-        }
         
         VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
         vmAppDomain.SetHostPtr(pAppDomain);
@@ -4338,10 +4326,6 @@ void  DacDbiInterfaceImpl::EnumerateAssembliesInAppDomain(
     // in the domain. This is to enforce rules at code:IDacDbiInterface#Enumeration.
     // See comment in code:DacDbiInterfaceImpl::EnumerateModulesInAssembly code for details.
     AppDomain * pAppDomain = vmAppDomain.GetDacPtr();
-    if (pAppDomain->IsUnloading())
-    {
-        return;
-    }
 
     // Pass the magical flags to the loader enumerator to get all Execution-only assemblies.
     iterator = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution));
@@ -4374,18 +4358,6 @@ void DacDbiInterfaceImpl::EnumerateModulesInAssembly(
 
     DomainAssembly * pDomainAssembly = vmAssembly.GetDacPtr();
 
-    // If the appdomain or assembly containing this module is unloading, then don't enumerate any modules.
-    // in the domain. This is to enforce rules at code:IDacDbiInterface#Enumeration, specifically
-    // that new objects are not available after the unload event is sent. 
-    // This is a very large hammer, but since modules only unload with appdomains or assemblies, we're 
-    // erring on the side of safety. If the debugger happens to have VMPTR_DomainFiles (CordbModules) already
-    // cached, it can still use those until the unload event. 
-    if (pDomainAssembly->IsUnloading())
-    {
-        return;
-    }
-    
-
     // If the domain is not yet fully-loaded, don't advertise it yet.
     // It's not ready to be inspected. 
     DomainModuleIterator iterator =  pDomainAssembly->IterateModules(kModIterIncludeLoaded);
index 839ed79..a2148b7 100644 (file)
@@ -10134,8 +10134,7 @@ BOOL Debugger::SendSystemClassLoadUnloadEvent(mdTypeDef classMetadataToken,
         // triggers too early in the loading process. FindDomainFile will not become
         // non-NULL until the module is fully loaded into the domain which is what we
         // want.
-        if ((classModule->FindDomainFile(pAppDomain) != NULL ) &&
-            !(fIsLoadEvent && pAppDomain->IsUnloading()) )
+        if (classModule->FindDomainFile(pAppDomain) != NULL )
         {
             // Find the Left Side module that this class belongs in.
             DebuggerModule* pModule = LookupOrCreateModule(classModule, pAppDomain);
index cf31bc5..58c3113 100644 (file)
@@ -783,7 +783,6 @@ CONFIG_DWORD_INFO_EX(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "", CLRConfig::R
 CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GenerateLongJumpDispatchStubRatio, W("GenerateLongJumpDispatchStubRatio"), "Useful for testing VSD on AMD64")
 CONFIG_DWORD_INFO_EX(INTERNAL_HashStack, W("HashStack"), 0, "", CLRConfig::REGUTIL_default)
 CONFIG_DWORD_INFO(INTERNAL_HostManagerConfig, W("HostManagerConfig"), (DWORD)-1, "")
-CONFIG_DWORD_INFO(INTERNAL_HostTestADUnload, W("HostTestADUnload"), 0, "Allows setting Rude unload as default")
 CONFIG_DWORD_INFO(INTERNAL_HostTestThreadAbort, W("HostTestThreadAbort"), 0, "")
 RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_IgnoreDllMainReturn, W("IgnoreDllMainReturn"), 0, "Don't check the return value of DllMain if this is set", CLRConfig::ConfigFile_ApplicationFirst)
 CONFIG_STRING_INFO(INTERNAL_InvokeHalt, W("InvokeHalt"), "Throws an assert when the given method is invoked through reflection.")
index 2356316..3c5a686 100644 (file)
@@ -4610,15 +4610,6 @@ inline BOOL IsFinalizerThread ()
     return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Finalizer);
 }
 
-inline BOOL IsADUnloadHelperThread ()
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ADUnloadHelper);
-}
-
 inline BOOL IsShutdownHelperThread ()
 {
     STATIC_CONTRACT_NOTHROW;
index 123a630..b7701d8 100644 (file)
@@ -18,7 +18,6 @@ extern TheUMEntryPrestubWorker:proc
 extern UMEntryPrestubUnwindFrameChainHandler:proc
 extern UMThunkStubUnwindFrameChainHandler:proc
 extern g_TrapReturningThreads:dword
-extern UM2MDoADCallBack:proc
 extern UMThunkStubRareDisableWorker:proc
 extern ReversePInvokeBadTransition:proc
 
@@ -188,14 +187,6 @@ HaveThread:
 
 InCooperativeMode:
 
-        mov             rax, [r12 + OFFSETOF__Thread__m_pDomain]
-        mov             eax, [rax + OFFSETOF__AppDomain__m_dwId]
-
-        mov             r11d, [METHODDESC_REGISTER + OFFSETOF__UMEntryThunk__m_dwDomainId]
-
-        cmp             rax, r11
-        jne             WrongAppDomain
-
         mov             r11, [METHODDESC_REGISTER + OFFSETOF__UMEntryThunk__m_pUMThunkMarshInfo]
         mov             eax, [r11 + OFFSETOF__UMThunkMarshInfo__m_cbActualArgSize]                      ; stack_args
         test            rax, rax                                                                        ; stack_args
@@ -322,137 +313,7 @@ CopyLoop:
         
         jmp             ArgumentsSetup
 
-
-WrongAppDomain:
-        ;
-        ; home register args to the stack
-        ;
-        mov             [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET +  0h], rcx
-        mov             [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET +  8h], rdx
-        mov             [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 10h], r8
-        mov             [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 18h], r9
-
-        ;
-        ; save off xmm registers
-        ;
-        movdqa          xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET +  0h], xmm0
-        movdqa          xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 10h], xmm1
-        movdqa          xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 20h], xmm2
-        movdqa          xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 30h], xmm3
-
-        ;
-        ; call our helper to perform the AD transtion 
-        ;
-        mov             rcx, METHODDESC_REGISTER
-        lea             r8,  [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET]
-        mov             rax, [METHODDESC_REGISTER + OFFSETOF__UMEntryThunk__m_pUMThunkMarshInfo]
-        mov             r9d, [rax + OFFSETOF__UMThunkMarshInfo__m_cbActualArgSize]
-        call            UM2MDoADCallBack
-
-        ; restore return value
-        mov             rax,  [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET +  0h]
-        movdqa          xmm0, xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET +  0h]
-
-        jmp             PostCall
-
 NESTED_END UMThunkStub, _TEXT
 
-;
-; EXTERN_C void __stdcall UM2MThunk_WrapperHelper(
-;       void *pThunkArgs,               ; rcx
-;       int argLen,                     ; rdx
-;       void *pAddr,                    ; r8            // not used
-;       UMEntryThunk *pEntryThunk,      ; r9
-;       Thread *pThread);               ; [entry_sp + 28h]
-;
-NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT
-
-
-UM2MThunk_WrapperHelper_STACK_FRAME_SIZE = 0
-
-; number of integer registers saved in prologue
-UM2MThunk_WrapperHelper_NUM_REG_PUSHES = 3
-UM2MThunk_WrapperHelper_STACK_FRAME_SIZE = UM2MThunk_WrapperHelper_STACK_FRAME_SIZE + (UM2MThunk_WrapperHelper_NUM_REG_PUSHES * 8)
-
-UM2MThunk_WrapperHelper_CALLEE_SCRATCH_SIZE = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES
-UM2MThunk_WrapperHelper_STACK_FRAME_SIZE = UM2MThunk_WrapperHelper_STACK_FRAME_SIZE + UM2MThunk_WrapperHelper_CALLEE_SCRATCH_SIZE
-
-; Ensure that rsp remains 16-byte aligned
-if ((UM2MThunk_WrapperHelper_STACK_FRAME_SIZE + 8) MOD 16) ne 0        ; +8 for caller-pushed return address
-UM2MThunk_WrapperHelper_STACK_FRAME_SIZE = UM2MThunk_WrapperHelper_STACK_FRAME_SIZE + 8
-endif
-
-UM2MThunk_WrapperHelper_FRAME_OFFSET = UM2MThunk_WrapperHelper_CALLEE_SCRATCH_SIZE
-UM2MThunk_WrapperHelper_FIXED_STACK_ALLOC_SIZE = UM2MThunk_WrapperHelper_STACK_FRAME_SIZE - (UM2MThunk_WrapperHelper_NUM_REG_PUSHES * 8)
-
-        push_nonvol_reg rsi
-        push_nonvol_reg rdi
-        push_nonvol_reg rbp
-        alloc_stack     UM2MThunk_WrapperHelper_FIXED_STACK_ALLOC_SIZE
-        set_frame       rbp, UM2MThunk_WrapperHelper_FRAME_OFFSET
-        END_PROLOGUE
-
-        ;
-        ; We are in cooperative mode and in the correct domain. 
-        ; The host has also been notified that we've entered the 
-        ; runtime.  All we have left to do is to copy the stack, 
-        ; setup the register args and then call the managed target
-        ;
-
-        test            rdx, rdx
-        jg              CopyStackArgs
-
-ArgumentsSetup:
-        mov             METHODDESC_REGISTER, r9
-
-        mov             rsi, rcx                ; rsi <- pThunkArgs
-        mov             rcx, [rsi +  0h]
-        mov             rdx, [rsi +  8h]
-        mov             r8,  [rsi + 10h]
-        mov             r9,  [rsi + 18h]
-
-        movdqa          xmm0, xmmword ptr [rsi + UMThunkStubAMD64_XMM_SAVE_OFFSET - UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET +  0h]
-        movdqa          xmm1, xmmword ptr [rsi + UMThunkStubAMD64_XMM_SAVE_OFFSET - UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 10h]
-        movdqa          xmm2, xmmword ptr [rsi + UMThunkStubAMD64_XMM_SAVE_OFFSET - UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 20h]
-        movdqa          xmm3, xmmword ptr [rsi + UMThunkStubAMD64_XMM_SAVE_OFFSET - UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 30h]
-
-        mov             rax, [METHODDESC_REGISTER + OFFSETOF__UMEntryThunk__m_pUMThunkMarshInfo]      ; rax <- UMThunkMarshInfo*
-        mov             rax, [rax + OFFSETOF__UMThunkMarshInfo__m_pILStub]                              ; rax <- Stub*
-        call            rax
-
-        ; make sure we don't trash the return value
-        mov             [rsi + 0h], rax
-        movdqa          xmmword ptr [rsi + UMThunkStubAMD64_XMM_SAVE_OFFSET - UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET +  0h], xmm0
-
-        lea             rsp, [rbp - UM2MThunk_WrapperHelper_FRAME_OFFSET + UM2MThunk_WrapperHelper_FIXED_STACK_ALLOC_SIZE]
-        pop             rbp
-        pop             rdi
-        pop             rsi
-        ret
-        
-
-CopyStackArgs:
-        ; rdx = cbStackArgs (with 20h for register args subtracted out already)
-        ; rcx = pSrcArgStack
-
-        sub             rsp, rdx
-        and             rsp, -16
-
-        mov             r8, rcx
-        
-        lea             rsi, [rcx + SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES]
-        lea             rdi, [rsp + UM2MThunk_WrapperHelper_CALLEE_SCRATCH_SIZE]
-
-        mov             rcx, rdx
-        shr             rcx, 3
-        
-        rep movsq
-        
-        mov             rcx, r8
-        
-        jmp             ArgumentsSetup
-        
-NESTED_END UM2MThunk_WrapperHelper, _TEXT
-
         end
 
index cadc10a..1af0786 100644 (file)
@@ -147,22 +147,22 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_pFrame
 ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_State
                     == offsetof(Thread, m_State));
 
-#define               OFFSETOF__Thread__m_pDomain                   0x20
+#define               OFFSETOF__Thread__m_pDomain                   0x18
 ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_pDomain
                     == offsetof(Thread, m_pDomain));
 
-#define               OFFSETOF__Thread__m_dwLockCount               0x28
+#define               OFFSETOF__Thread__m_dwLockCount               0x20
 ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_dwLockCount
                     == offsetof(Thread, m_dwLockCount));
 
-#define               OFFSETOF__Thread__m_ThreadId                  0x2C
+#define               OFFSETOF__Thread__m_ThreadId                  0x24
 ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_ThreadId
                     == offsetof(Thread, m_ThreadId));
 
-#define               OFFSET__Thread__m_alloc_context__alloc_ptr 0x60
+#define               OFFSET__Thread__m_alloc_context__alloc_ptr 0x58
 ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__alloc_ptr == offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_ptr));
 
-#define               OFFSET__Thread__m_alloc_context__alloc_limit 0x68
+#define               OFFSET__Thread__m_alloc_context__alloc_limit 0x60
 ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__alloc_limit == offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_limit));
 
 #define               OFFSETOF__gc_alloc_context__alloc_ptr 0x0
index 3e60bed..834f0ca 100644 (file)
@@ -196,15 +196,3 @@ LOCAL_LABEL(WrongAppDomain):
 #endif
 
 NESTED_END UMThunkStub, _TEXT
-
-//
-// EXTERN_C void __stdcall UM2MThunk_WrapperHelper(
-//       void *pThunkArgs,               // rdi
-//       int argLen,                     // rsi
-//       void *pAddr,                    // rdx            // not used
-//       UMEntryThunk *pEntryThunk,      // rcx
-//       Thread *pThread);               // r8
-//
-NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT, NoHandler
-        int3
-NESTED_END UM2MThunk_WrapperHelper, _TEXT
index 18478eb..8f8efcf 100644 (file)
@@ -142,11 +142,6 @@ CrstStatic          SystemDomain::m_DelayedUnloadCrst;
 
 ULONG               SystemDomain::s_dNumAppDomains = 0;
 
-AppDomain *         SystemDomain::m_pAppDomainBeingUnloaded = NULL;
-ADIndex             SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
-Thread            *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
-Thread            *SystemDomain::m_pAppDomainUnloadingThread = 0;
-
 ArrayListStatic     SystemDomain::m_appDomainIdList;
 
 DWORD               SystemDomain::m_dwLowestFreeIndex        = 0;
@@ -2215,8 +2210,7 @@ void SystemDomain::Stop()
     AppDomainIterator i(TRUE);
 
     while (i.Next())
-        if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
-            i.GetDomain()->Stop();
+        i.GetDomain()->Stop();
 }
 
 
@@ -2476,21 +2470,6 @@ void SystemDomain::LazyInitGlobalStringLiteralMap()
     }
 }
 
-void AppDomain::CreateADUnloadStartEvent()
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_NOTRIGGER;
-        SO_TOLERANT;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    g_pUnloadStartEvent = new CLREvent();
-    g_pUnloadStartEvent->CreateAutoEvent(FALSE);
-}
-
 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
 {
     CONTRACT_VOID
@@ -2526,7 +2505,7 @@ void AppDomain::CreateADUnloadStartEvent()
         for (i = 0 ; i < count ; i++)
         {
             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
-            if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
+            if (pAppDomain && pAppDomain->IsActive())
             {
 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
                 if (g_fEnableARM)
@@ -2654,7 +2633,7 @@ DWORD SystemDomain::GetTotalNumSizedRefHandles()
         for (i = 0 ; i < count ; i++)
         {
             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
-            if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
+            if (pAppDomain && pAppDomain->IsActive())
             {
                 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
             }
@@ -2850,7 +2829,6 @@ void SystemDomain::LoadDomain(AppDomain *pDomain)
     }
     CONTRACTL_END;
 
-    pDomain->SetCanUnload();    // by default can unload any domain
     SystemDomain::System()->AddDomain(pDomain);
 }
 
@@ -2995,12 +2973,8 @@ AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
     AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
 
 #ifndef CROSSGEN_COMPILE
-    if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
-        SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
-        SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
-        result=SystemDomain::System()->AppDomainBeingUnloaded();
     // If the current thread can't enter the AppDomain, then don't return it.
-    if (!result || !result->CanThreadEnter(GetThread()))
+    if (!result)
         return NULL;
 #endif // CROSSGEN_COMPILE
 
@@ -3913,11 +3887,6 @@ AppDomain::AppDomain()
     CONTRACTL_END;
 
     m_cRef=1;
-    m_pNextInDelayedUnloadList = NULL;
-    m_fRudeUnload = FALSE;
-    m_pUnloadRequestThread = NULL;
-    m_ADUnloadSink=NULL;
-
 
     // Initialize Shared state. Assemblies are loaded
     // into each domain by default.
@@ -3969,8 +3938,6 @@ AppDomain::AppDomain()
     m_ForceTrivialWaitOperations = false;
     m_Stage=STAGE_CREATING;
 
-    m_bForceGCOnUnload=FALSE;
-    m_bUnloadingFromUnloadEvent=FALSE;
 #ifdef _DEBUG
     m_dwIterHolders=0;
     m_dwRefTakers=0;
@@ -4026,9 +3993,6 @@ AppDomain::~AppDomain()
 
     m_AssemblyCache.Clear();
 
-    if (m_ADUnloadSink)
-        m_ADUnloadSink->Release();
-
     if(!g_fEEInit)
         Terminate();
 
@@ -4116,8 +4080,6 @@ void AppDomain::Init()
 
 #ifndef CROSSGEN_COMPILE
     PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
-
-    m_ADUnloadSink=new ADUnloadSink();
 #endif
 
     BaseDomain::Init();
@@ -4226,85 +4188,6 @@ BOOL AppDomain::IsCompilationDomain()
 
 #ifndef CROSSGEN_COMPILE
 
-extern int g_fADUnloadWorkerOK;
-
-// Notes:
-//   This helper will send the AppDomain creation notifications for profiler / debugger.
-//   If it throws, its backout code will also send a notification.
-//   If it succeeds, then we still need to send a AppDomainCreateFinished notification.
-void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
-{
-    CONTRACTL
-    {
-        THROWS;
-        MODE_COOPERATIVE;
-        GC_TRIGGERS;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    GCX_PREEMP();
-
-    pDomain.Assign(new AppDomain());
-    if (g_fADUnloadWorkerOK<0)
-    {
-        AppDomain::CreateADUnloadWorker();
-    }
-
-    //@todo: B#25921
-    // We addref Appdomain object here and notify a profiler that appdomain 
-    // creation has started, then return to managed code which will  call 
-    // the function that releases the appdomain and notifies a profiler that we finished
-    // creating the appdomain. If an exception is raised while we're in that managed code
-    // we will leak memory and the profiler will not be notified about the failure
-
-#ifdef PROFILING_SUPPORTED
-    // Signal profile if present.
-    {
-        BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
-        g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
-        END_PIN_PROFILER();
-    }
-    EX_TRY
-#endif // PROFILING_SUPPORTED
-    {
-        {
-            SystemDomain::LockHolder lh;
-            pDomain->Init(); 
-            // allocate a Virtual Call Stub Manager for this domain
-            pDomain->InitVSD();
-        }
-
-        pDomain->SetCanUnload();    // by default can unload any domain
-        
-        #ifdef DEBUGGING_SUPPORTED    
-        // Notify the debugger here, before the thread transitions into the 
-        // AD to finish the setup, and before any assemblies are loaded into it.
-        SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
-        #endif // DEBUGGING_SUPPORTED
-
-        STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
-        pDomain->LoadSystemAssemblies();
-        pDomain->SetupSharedStatics();
-
-        pDomain->SetStage(AppDomain::STAGE_ACTIVE);    
-    }        
-#ifdef PROFILING_SUPPORTED
-    EX_HOOK
-    {
-        // Need the first assembly loaded in to get any data on an app domain.
-        {
-            BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
-            g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
-            END_PIN_PROFILER();
-        }
-    }
-    EX_END_HOOK;
-
-    // On success, caller must still send the AppDomainCreationFinished notification.
-#endif // PROFILING_SUPPORTED
-}
-
 void AppDomain::Stop()
 {
     CONTRACTL
@@ -4517,20 +4400,6 @@ struct GetExposedObject_Args
     OBJECTREF *ref;
 };
 
-static void GetExposedObject_Wrapper(LPVOID ptr)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-    GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
-    *(args->ref) = args->pDomain->GetExposedObject();
-}
-
-
 OBJECTREF AppDomain::GetExposedObject()
 {
     CONTRACTL
@@ -4547,16 +4416,6 @@ OBJECTREF AppDomain::GetExposedObject()
     {
         APPDOMAINREF obj = NULL;
 
-        Thread *pThread = GetThread();
-        if (pThread->GetDomain() != this)
-        {
-            GCPROTECT_BEGIN(ref);
-            GetExposedObject_Args args = {this, &ref};
-            // call through DoCallBack with a domain transition
-            pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
-            GCPROTECT_END();
-            return ref;
-        }
         MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
 
         // Create the module object
@@ -5349,7 +5208,7 @@ CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
     if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
     {
         //cctor could have been interupted by ADU
-        CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
+        CHECK_MSG(pModule->CheckActivated(),
               "Managed code can only run when its module has been activated in the current app domain");
     }
 
@@ -5652,17 +5511,6 @@ struct LoadFileArgs
     DomainFile *result;
 };
 
-#ifndef CROSSGEN_COMPILE
-static void LoadDomainFile_Wrapper(void *ptr)
-{
-    WRAPPER_NO_CONTRACT;
-    STATIC_CONTRACT_SO_INTOLERANT;
-    GCX_PREEMP();
-    LoadFileArgs *args = (LoadFileArgs *) ptr;
-    args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
-}
-#endif // !CROSSGEN_COMPILE
-
 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
 {
     CONTRACT(DomainFile *)
@@ -5716,28 +5564,6 @@ DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetL
         RETURN pFile;
     }
 
-#ifndef CROSSGEN_COMPILE
-    // Make sure we are in the right domain.  Many of the load operations require the target domain
-    // to be the current app domain, most notably anything involving managed code or managed object
-    // creation.
-    if (this != GetAppDomain()
-        && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
-    {
-        // Transition to the correct app domain and perform the load there.
-        GCX_COOP();
-
-        // we will release the lock in the other app domain
-        lockRef.SuppressRelease();
-
-        if(!CanLoadCode() || GetDefaultContext() ==NULL)
-            COMPlusThrow(kAppDomainUnloadedException);
-        LoadFileArgs args = {pLock, targetLevel, NULL};
-        GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
-
-        RETURN args.result;
-    }
-#endif // CROSSGEN_COMPILE
-
     // Initialize a loading queue.  This will hold any loads which are triggered recursively but
     // which cannot be immediately satisfied due to anti-deadlock constraints.
 
@@ -7280,7 +7106,7 @@ ULONG AppDomain::Release()
     ULONG   cRef = InterlockedDecrement(&m_cRef);
     if (!cRef)
     {
-        _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
+        _ASSERTE (m_Stage == STAGE_CREATING);
         ADID adid=GetId();
         delete this;
         TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
@@ -7289,101 +7115,8 @@ ULONG AppDomain::Release()
 }
 
 
-AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
-BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
-
 #ifndef CROSSGEN_COMPILE
 
-void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
-{
-    CONTRACTL
-    {
-        THROWS;
-        MODE_COOPERATIVE;
-        GC_TRIGGERS;
-        INJECT_FAULT(COMPlusThrowOM(););
-        SO_INTOLERANT;
-    }
-    CONTRACTL_END;
-
-    AppDomain* pDomain = (AppDomain *) ptr;
-    pDomain->RaiseUnloadDomainEvent();
-}
-
-void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-    Thread *pThread = GetThread();
-    _ASSERTE (pThread && IsFinalizerThread());
-
-    // if we are not unloading domain now, do not process the event
-    if (SystemDomain::AppDomainBeingUnloaded() == NULL)
-    {
-        s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
-        s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
-            s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
-        FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
-        return;
-    }
-    FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
-    AppDomain::EnableADUnloadWorkerForFinalizer();
-    pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
-    s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
-    pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
-    s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
-        s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
-    FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
-    FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
-
-    if (pThread->IsAbortRequested())
-    {
-        pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
-    }
-}
-
-void AppDomain::RaiseUnloadDomainEvent()
-{
-    CONTRACTL
-    {
-        THROWS;
-        MODE_COOPERATIVE;
-        GC_TRIGGERS;
-        SO_INTOLERANT;
-    }
-    CONTRACTL_END;
-
-    Thread *pThread = GetThread();
-    if (this != pThread->GetDomain())
-    {
-        pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
-    }
-    else
-    {
-        struct _gc
-        {
-            APPDOMAINREF Domain;
-            OBJECTREF    Delegate;
-        } gc;
-        ZeroMemory(&gc, sizeof(gc));
-
-        GCPROTECT_BEGIN(gc);
-        gc.Domain = (APPDOMAINREF) GetRawExposedObject();
-        if (gc.Domain != NULL)
-        {
-            gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
-            if (gc.Delegate != NULL)
-                DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
-        }
-        GCPROTECT_END();
-    }
-}
-
 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
 {
     CONTRACTL
@@ -7593,8 +7326,6 @@ AppDomain::HasUnhandledExceptionEventHandler()
         NOTHROW;
     }
     CONTRACTL_END;
-    if (!CanThreadEnter(GetThread()))
-        return FALSE;
     if (GetRawExposedObject()==NULL)
         return FALSE;
     return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
@@ -7962,2657 +7693,1334 @@ void AppDomain::DetachRCWs()
 
 #endif // FEATURE_COMINTEROP
 
-BOOL AppDomain::CanThreadEnter(Thread *pThread)
-{
-    WRAPPER_NO_CONTRACT;
-
-    if (m_Stage < STAGE_EXITED)
-        return TRUE;
-
-    if (pThread == SystemDomain::System()->GetUnloadingThread())
-        return m_Stage < STAGE_FINALIZING;
-    if (pThread == FinalizerThread::GetFinalizerThread())
-        return m_Stage < STAGE_FINALIZED;
-
-    return FALSE;
-}
-
-void AppDomain::AllowThreadEntrance(AppDomain * pApp)
+void AppDomain::ExceptionUnwind(Frame *pFrame)
 {
     CONTRACTL
     {
-        NOTHROW;
-        GC_TRIGGERS;
+        DISABLED(GC_TRIGGERS);  // EEResourceException
+        DISABLED(THROWS);   // EEResourceException
         MODE_ANY;
-        FORBID_FAULT;
-        PRECONDITION(CheckPointer(pApp));
     }
     CONTRACTL_END;
 
-    if (pApp->GetUnloadRequestThread() == NULL)
-    {
-        // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
-        if (!pApp->IsUnloadingFromUnloadEvent())
-        {
-            pApp->SetStage(STAGE_UNLOAD_REQUESTED);
-            pApp->EnableADUnloadWorker(
-                 pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
-            return;
-        }
-    }
-
-    SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
-
-#ifdef FEATURE_COMINTEROP
-    if (pApp->m_pComCallWrapperCache)
-        pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
-#endif // FEATURE_COMINTEROP
+    LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
+#if _DEBUG_ADUNLOAD
+    printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
+#endif
+    Thread *pThread = GetThread();
+    _ASSERTE(pThread);
 
-    pApp->SetStage(STAGE_OPEN);
+    LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
 }
 
-void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
+BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
 {
     CONTRACTL
     {
-        DISABLED(NOTHROW);
-        DISABLED(GC_TRIGGERS);
+        THROWS;
+        GC_TRIGGERS;
         MODE_ANY;
-        DISABLED(FORBID_FAULT);
-        PRECONDITION(CheckPointer(pApp));
+        SO_INTOLERANT;
     }
     CONTRACTL_END;
 
-#ifdef FEATURE_COMINTEROP
-    // Set the flag on our CCW cache so stubs won't enter
-    if (pApp->m_pComCallWrapperCache)
-        pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
-#endif // FEATURE_COMINTEROP
-
-    SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
-    // Release our ID so remoting and thread pool won't enter
-    pApp->SetStage(STAGE_EXITED);
-};
-
-void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
-{
-    CONTRACTL
+    Thread *pThread = NULL;
+    DWORD nThreadsNeedMoreWork=0;
+    if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
     {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
+        Thread *pCurThread = GetThread();
+        if (pCurThread->CatchAtSafePoint())
+            pCurThread->PulseGCMode();
+
+        m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
+        return !nThreadsNeedMoreWork;
     }
-    CONTRACTL_END;
 
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
-         GetId().m_dwId, this, GetFriendlyNameForLogging()));
+    // For now piggyback on the GC's suspend EE mechanism
+    ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
+#ifdef _DEBUG
+    // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
+    _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
+#endif // _DEBUG
 
-    RestrictEnterHolder RestrictEnter(this);
+    int totalADCount = 0;
+    int finalizerADCount = 0;
+    pThread = NULL;
 
-    {
-        SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
-        SetStage(STAGE_EXITING);  // Note that we're trying to exit
-    }
+    RuntimeExceptionKind reKind = kLastException;
+    UINT resId = 0;
+    SmallStackSString ssThreadId;
 
-    // Raise the event indicating the domain is being unloaded.
-    if (GetDefaultContext())
+    while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
     {
-        FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
-
-        DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
-        //if (timeout == INFINITE)
-        //{
-        //    timeout = 20000; // 20 seconds
-        //}
-        DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
-        ULONGLONG curTime = CLRGetTickCount64();
-        ULONGLONG endTime = 0;
-        if (timeout != INFINITE)
+        // we already checked that we're not running in the unload domain
+        if (pThread == GetThread())
         {
-            endTime = curTime + timeout;
-            // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
-            timeout /= 5;
+            continue;
         }
 
-        while (s_pAppDomainToRaiseUnloadEvent != NULL)
-        {
-            FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
-            if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
-            {
-                if (CLRGetTickCount64() >= endTime)
-                {
-                    SString sThreadId;
-                    sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
-                    COMPlusThrow(kCannotUnloadAppDomainException,
-                                 IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
-                                 sThreadId);
-                }
-            }
+#ifdef _DEBUG
+        void PrintStackTraceWithADToLog(Thread *pThread);
+        if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
+            LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
+            PrintStackTraceWithADToLog(pThread);
+        }
+#endif // _DEBUG
+        int count = 0;
+        Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
+        if (! pFrame) {
+            _ASSERTE(count == 0);
+            continue;
         }
-    }
-
-    // Tell the tiered compilation manager to stop initiating any new work for background
-    // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
-    // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason 
-    // to take the risk of relying on them when we can easily augment with a cooperative 
-    // shutdown check. This notification only initiates the process of evacuating the threads
-    // and then the UnwindThreads() call below is where blocking will occur to ensure the threads 
-    // have exited the domain.
-    //
-#ifdef FEATURE_TIERED_COMPILATION
-    m_tieredCompilationManager.Shutdown();
-#endif
-
-    //
-    // Set up blocks so no threads can enter except for the finalizer and the thread
-    // doing the unload.
-    //
-
-    RestrictThreadEntrance(this);
 
-    // Cause existing threads to abort out of this domain.  This should ensure all
-    // normal threads are outside the domain, and we've already ensured that no new threads
-    // can enter.
+        if (pThread != FinalizerThread::GetFinalizerThread())
+        {
+            totalADCount += count;
+            nThreadsNeedMoreWork++;
+        }
+        else
+        {
+            finalizerADCount = count;
+        }
 
-    PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
+        // don't setup the exception info for the unloading thread unless it's the last one in
+        if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException)
+        {
+#ifdef AD_BREAK_ON_CANNOT_UNLOAD
+            static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
+            if (breakOnCannotUnload)
+                _ASSERTE(!"Cannot unload AD");
+#endif // AD_BREAK_ON_CANNOT_UNLOAD
+            reKind = kCannotUnloadAppDomainException;
+            resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
+            ssThreadId.Printf(W("%x"), pThread->GetThreadId());
+            STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
+            // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
+            // it's better to chew a little extra time here and make sure our counts are consistent
+        }
+        // only abort the thread requesting the unload if it's the last one in, that way it will get
+        // notification that the unload failed for some other thread not being aborted. And don't abort
+        // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
+        // then we will eventually get a CannotUnloadException on it.
 
+        if (pThread != FinalizerThread::GetFinalizerThread())
+        {
 
-    if (!NingenEnabled())
-    {
-        UnwindThreads();
+            STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
+            LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
+#if _DEBUG_ADUNLOAD
+            printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
+#endif
+            pThread->SetAbortRequest(EEPolicy::TA_V1Compatible);
+        }
+        TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
     }
-    
-    TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;    
-    ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
+    _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
 
-    RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
-#ifdef PROFILING_SUPPORTED
-    // Signal profile if present.
-    {
-        BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
-        GCX_PREEMP();
-        g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
-        END_PIN_PROFILER();
-    }
-#endif // PROFILING_SUPPORTED
-    COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
-    COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
+    //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
+    if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
+        FreeBuildDebugBreak();
 
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
-         GetId().m_dwId, this, GetFriendlyNameForLogging()));
+    // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
+    // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
+    // exit the domain gracefully.
+    // m_dwThreadEnterCount = totalADCount;
 
-    // Send ETW events for this domain's unload and potentially iterate through this
-    // domain's modules & assemblies to send events for their unloads as well.  This
-    // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
-    // this before any finalization occurs at all.
-    ETW::LoaderLog::DomainUnload(this);
+    // CommonTripThread will handle the abort for any threads that we've marked
+    ThreadSuspend::RestartEE(FALSE, TRUE);
+    if (reKind != kLastException)
+        COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
 
-    CodeVersionManager::OnAppDomainExit(this);
+    _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
+    
+    m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
+    return (totalADCount == 0);
+}
 
-    //
-    // Spin running finalizers until we flush them all.  We need to make multiple passes
-    // in case the finalizers create more finalizable objects.  This is important to clear
-    // the finalizable objects as roots, as well as to actually execute the finalizers. This
-    // will only finalize instances instances of types that aren't potentially agile becuase we can't
-    // risk finalizing agile objects. So we will be left with instances of potentially agile types
-    // in handles or statics.
-    //
-    // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time.  Eventually
-    // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
-    // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
-    //
+void AppDomain::UnwindThreads()
+{
+    // This function should guarantee appdomain
+    // consistency even if it fails. Everything that is going
+    // to make the appdomain impossible to reenter
+    // should be factored out
 
-    SetStage(STAGE_FINALIZING);
+    // <TODO>@todo: need real synchronization here!!!</TODO>
+    CONTRACTL
+    {
+        MODE_COOPERATIVE;
+        THROWS;
+        GC_TRIGGERS;
+    }
+    CONTRACTL_END;
 
-    // Flush finalizers now.
-    FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
-    
-    DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
+    int retryCount = -1;
+    m_dwThreadsStillInAppDomain=(ULONG)-1;
     ULONGLONG startTime = CLRGetTickCount64();
-    ULONGLONG elapsedTime = 0;
-    DWORD finalizerWait = 0;
 
-    while (FinalizerThread::GetUnloadingAppDomain() != NULL)
-    {
+    // Force threads to go through slow path during AD unload.
+    TSSuspendHolder shTrap;
+
+    BOOL fMarkUnloadRequestThread = TRUE;
 
+    // now wait for all the threads running in our AD to get out
+    do
+    {
+        DWORD timeout = GetEEPolicy()->GetTimeout(OPR_AppDomainUnload);
+        EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_AppDomainUnload, NULL);
+        if (timeout != INFINITE && action >= eExitProcess) {
+            // Escalation policy specified.
+            ULONGLONG curTime = CLRGetTickCount64();
+            ULONGLONG elapseTime = curTime - startTime;
+            if (elapseTime > timeout)
+            {
+                // Escalate
+                switch (action)
+                {
+                case eExitProcess:
+                case eFastExitProcess:
+                case eRudeExitProcess:
+                case eDisableRuntime:
+                    GetEEPolicy()->NotifyHostOnTimeout(OPR_AppDomainUnload, action);
+                    EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
+                    _ASSERTE (!"Should not reach here");
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+#ifdef _DEBUG
+        if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
+            DumpADThreadTrack();
+#endif // _DEBUG
+        if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
+            break;
         if (timeout != INFINITE)
         {
-            elapsedTime = CLRGetTickCount64() - startTime;
+            // Turn off the timeout used by AD.
+            retryCount = 1;
         }
-        if (timeout > elapsedTime)
+        else
         {
-            finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
+            // GCStress takes a long time to unwind, due to expensive creation of
+            // a threadabort exception.
+            if (!GCStress<cfg_any>::IsEnabled())
+                ++retryCount;
+            LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
+#if _DEBUG_ADUNLOAD
+            printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
+#endif
         }
-        FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
-        if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
+
+        if (m_dwThreadEnterCount != 0)
         {
-            elapsedTime = CLRGetTickCount64() - startTime;
-            if (timeout <= elapsedTime)
-            {
-                SetRudeUnload();
-                // TODO: Consider escalation from RudeAppDomain
-                timeout = INFINITE;
-            }
+#ifdef _DEBUG
+            GetThread()->UserSleep(20);
+#else // !_DEBUG
+            GetThread()->UserSleep(10);
+#endif // !_DEBUG
         }
     }
+    while (TRUE) ;
+}
 
-    tpAdUnloadHolder.SuppressRelease();
-    PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
-
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
-         GetId().m_dwId, this, GetFriendlyNameForLogging()));
-
-
-    AppDomainRefHolder This(this);
-    AddRef();           // Hold a reference so CloseDomain won't delete us yet
-    CloseDomain();      // Remove ourself from the list of app domains
-
-    // This needs to be done prior to destroying the handle tables below.
-    ReleaseDomainBoundInfo();
-
-    //
-    // It should be impossible to run non-mscorlib code in this domain now.
-    // Cleanup all of our roots except the handles. We do this to allow as many
-    // finalizers as possible to run correctly. If we delete the handles, they
-    // can't run.
-    //
-    if (!NingenEnabled())
+void AppDomain::ClearGCRoots()
+{
+    CONTRACTL
     {
+        GC_TRIGGERS;
+        MODE_COOPERATIVE;
+        NOTHROW;
     }
+    CONTRACTL_END;
 
-    ClearGCRoots();
-    ClearGCHandles();
+    Thread *pThread = NULL;
+    ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
 
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
-         GetId().m_dwId, this, GetFriendlyNameForLogging()));
+    // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
+    // this point, so only need to synchronize the preemptive mode threads.
+    ExecutionManager::Unload(GetLoaderAllocator());
 
-    if (fAsyncExit && fRunFinalizers)
+    while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
     {
-        GCX_PREEMP();
-        m_AssemblyCache.Clear();
-        ClearFusionContext();
-        ReleaseFiles();
-        if (!NingenEnabled())
+        // Delete the thread local static store
+        pThread->DeleteThreadStaticData(this);
+
+        // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
+        if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
         {
-            AddMemoryPressure();
+            // Never delete a handle to a preallocated exception object.
+            if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
+            {
+                DestroyHandle(pThread->m_LastThrownObjectHandle);
+            }
+
+            pThread->m_LastThrownObjectHandle = NULL;
         }
+
+        // Clear out the exceptions objects held by a thread.
+        pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
     }
-    SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
-    SystemDomain::SetUnloadDomainCleared();
-    if (m_dwId.m_dwId!=0)
-        SystemDomain::ReleaseAppDomainId(m_dwId);
-#ifdef PROFILING_SUPPORTED
-    // Always signal profile if present, even when failed.
+
+    //delete them while we still have the runtime suspended
+    // This must be deleted before the loader heaps are deleted.
+    if (m_pMarshalingData != NULL)
     {
-        BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
-        GCX_PREEMP();
-        g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
-        END_PIN_PROFILER();
+        delete m_pMarshalingData;
+        m_pMarshalingData = NULL;
     }
-#endif // PROFILING_SUPPORTED
 
+    if (m_pLargeHeapHandleTable != NULL)
+    {
+        delete m_pLargeHeapHandleTable;
+        m_pLargeHeapHandleTable = NULL;
+    }
+
+    ThreadSuspend::RestartEE(FALSE, TRUE);
 }
 
-void AppDomain::Close()
+#ifdef _DEBUG
+
+void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
 {
     CONTRACTL
     {
-        GC_TRIGGERS;
         NOTHROW;
+        GC_NOTRIGGER;
+        // REENTRANT
+        PRECONDITION(CheckPointer(pThread));
+        PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
     }
     CONTRACTL_END;
 
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
-         GetId().m_dwId, this, GetFriendlyNameForLogging()));
+    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
+        ;
+    if (m_pThreadTrackInfoList == NULL)
+        m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
+    // If we don't assert here, we will AV in the for loop below
+    _ASSERTE(m_pThreadTrackInfoList);
 
-    {
-        GCX_PREEMP();
-        RemoveMemoryPressure();
+    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
+
+    ThreadTrackInfo *pTrack = NULL;
+    int i;
+    for (i=0; i < pTrackList->Count(); i++) {
+        if ((*(pTrackList->Get(i)))->pThread == pThread) {
+            pTrack = *(pTrackList->Get(i));
+            break;
+        }
+    }
+    if (! pTrack) {
+        pTrack = new (nothrow) ThreadTrackInfo;
+        // If we don't assert here, we will AV in the for loop below.
+        _ASSERTE(pTrack);
+        pTrack->pThread = pThread;
+        ThreadTrackInfo **pSlot = pTrackList->Append();
+        *pSlot = pTrack;
     }
-    _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
+
+    InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
+    Frame **pSlot;
+    if (pTrack)
     {
-        SystemDomain::LockHolder lh;    // Avoid races with AppDomainIterator
-        SetStage(STAGE_CLOSED);
+        pSlot = pTrack->frameStack.Insert(0);
+        *pSlot = pFrame;
     }
+    int totThreads = 0;
+    for (i=0; i < pTrackList->Count(); i++)
+        totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
+    _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
 
-    // CONSIDER: move releasing remoting cache from managed code to here.
+    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
 }
 
 
-void AppDomain::ResetUnloadRequestThread(ADID Id)
+void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
 {
     CONTRACTL
     {
+        if (GetThread()) {MODE_COOPERATIVE;}
         NOTHROW;
-        MODE_ANY;
-        PRECONDITION(!IsADUnloadHelperThread());
+        GC_NOTRIGGER;
     }
     CONTRACTL_END;
 
-    GCX_COOP();
-    AppDomainFromIDHolder ad(Id, TRUE);
-    if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
+    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
+        ;
+    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
+    _ASSERTE(pTrackList);
+    ThreadTrackInfo *pTrack = NULL;
+    int i;
+    for (i=0; i < pTrackList->Count(); i++)
     {
-        Thread *pThread = ad->GetUnloadRequestThread();
-        if(pThread==GetThread())
+        if ((*(pTrackList->Get(i)))->pThread == pThread)
         {
-            ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
-
-            if(pThread)
-            {
-                if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
-                {
-                    pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
-                }
-                ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
-                pThread->ResetBeginAbortedForADUnload();
-            }
-            
-            ad->SetUnloadRequestThread(NULL);
-        }
+            pTrack = *(pTrackList->Get(i));
+            break;
+        }
     }
-}
+    _ASSERTE(pTrack);
+    _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
+    pTrack->frameStack.Delete(0);
+    InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
 
+    int totThreads = 0;
+    for (i=0; i < pTrackList->Count(); i++)
+        totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
+    _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
 
-int g_fADUnloadWorkerOK = -1;
+    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
+}
 
-HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
+void AppDomain::DumpADThreadTrack()
 {
     CONTRACTL
     {
-        if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
-        MODE_ANY;
-        if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
-        FORBID_FAULT;
+        NOTHROW;
+        GC_NOTRIGGER;
+        MODE_COOPERATIVE;
     }
     CONTRACTL_END;
 
-    if (dwId==(ADID)DefaultADID)
-        return COR_E_CANNOTUNLOADAPPDOMAIN;
-
-    Thread *pThread = GetThread();
-
-    // Finalizer thread can not wait until AD unload is done,
-    // because AD unload is going to wait for Finalizer Thread.
-    if (fSync && pThread == FinalizerThread::GetFinalizerThread() && 
-        !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
-        return COR_E_CANNOTUNLOADAPPDOMAIN;
-
-
-    // AD unload helper thread should have been created.
-    _ASSERTE (g_fADUnloadWorkerOK == 1);
-
-    _ASSERTE (!IsADUnloadHelperThread());
-
-    BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
-
-    if (fIsRaisingUnloadEvent)
-    {
-        AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
-
-        if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
-            return COR_E_APPDOMAINUNLOADED;
-
-        pApp->EnableADUnloadWorker();
-
-        return S_FALSE;
-    }
-
-
-    ADUnloadSinkHolder pSink;
+    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
+        ;
+    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
+    if (!pTrackList)
+        goto end;
 
     {
-        SystemDomain::LockHolder ulh;
-
-        AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
-
-        if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
-            return COR_E_APPDOMAINUNLOADED;
-
-        if (g_fADUnloadWorkerOK != 1)
-        {
-            _ASSERTE(FALSE);
-            return E_UNEXPECTED;
-        }
-
-        if (!fSync)
+        LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
+             m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
+        int totThreads = 0;
+        for (int i=0; i < pTrackList->Count(); i++)
         {
-            pApp->EnableADUnloadWorker();
-            return S_OK;
+            ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
+            if (pTrack->frameStack.Count()==0)
+                continue;
+            LOG((LF_APPDOMAIN, LL_INFO100, "  ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
+            totThreads += pTrack->frameStack.Count();
+            for (int j=0; j < pTrack->frameStack.Count(); j++)
+                LOG((LF_APPDOMAIN, LL_INFO100, "      frame %8.8x\n", *(pTrack->frameStack.Get(j))));
         }
+        _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
+    }
+end:
+    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
+}
+#endif // _DEBUG
 
-        pSink = pApp->PrepareForWaitUnloadCompletion();
-
-        pApp->EnableADUnloadWorker();
 
-        // release the holders - we don't care anymore if the appdomain is gone
-    }
+#endif // CROSSGEN_COMPILE
 
-#ifdef FEATURE_TESTHOOKS        
-    if (fExceptionsPassThrough)
-    {
-        CONTRACT_VIOLATION(FaultViolation);
-        return UnloadWaitNoCatch(dwId,pSink);
-    }
-#endif            
+void *SharedDomain::operator new(size_t size, void *pInPlace)
+{
+    LIMITED_METHOD_CONTRACT;
+    return pInPlace;
+}
 
-    return UnloadWait(dwId,pSink);
+void SharedDomain::operator delete(void *pMem)
+{
+    LIMITED_METHOD_CONTRACT;
+    // Do nothing - new() was in-place
 }
 
-HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
+
+void SharedDomain::Attach()
 {
     CONTRACTL
     {
-        NOTHROW;
+        THROWS;
+        GC_TRIGGERS;
         MODE_ANY;
-        if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
+        INJECT_FAULT(COMPlusThrowOM(););
     }
     CONTRACTL_END;
-    
-    HRESULT hr=S_OK;
-    EX_TRY
-    {
-        // IF you ever try to change this to something not using events, please address the fact that
-        // AppDomain::StopEEAndUnwindThreads relies on that events are used.
 
-        pSink->WaitUnloadCompletion();
-    }
-    EX_CATCH_HRESULT(hr);
+    // Create the global SharedDomain and initialize it.
+    m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
+    SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
+    // This cannot fail since g_pSharedDomainMemory is a static array.
+    CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
+
+    LOG((LF_CLASSLOADER,
+         LL_INFO10,
+         "Created shared domain at %p\n",
+         m_pSharedDomain));
 
-    if (SUCCEEDED(hr))
-        hr=pSink->GetUnloadResult();
+    // We need to initialize the memory pools etc. for the system domain.
+    m_pSharedDomain->Init(); // Setup the memory heaps
 
-    if (FAILED(hr))
-    {
-        ResetUnloadRequestThread(Id);
-    }
-    return hr;
+    // allocate a Virtual Call Stub Manager for the shared domain
+    m_pSharedDomain->InitVSD();
 }
 
-#ifdef FEATURE_TESTHOOKS        
-HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
+#ifndef CROSSGEN_COMPILE
+void SharedDomain::Detach()
 {
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_MODE_ANY;    
-
-    Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
-
-    // IF you ever try to change this to something not using events, please address the fact that
-    // AppDomain::StopEEAndUnwindThreads relies on that events are used.
-    pSink->WaitUnloadCompletion();
+    if (m_pSharedDomain)
+    {
+        m_pSharedDomain->Terminate();
+        delete m_pSharedDomain;
+        m_pSharedDomain = NULL;
+    }
+}
+#endif // CROSSGEN_COMPILE
 
-    HRESULT hr = pSink->GetUnloadResult();
+#endif // !DACCESS_COMPILE
 
-    if (SUCCEEDED(hr))
-        resetUnloadHolder.SuppressRelease();
+SharedDomain *SharedDomain::GetDomain()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
 
-    return hr;
+    return m_pSharedDomain;
 }
-#endif
 
-void AppDomain::Unload(BOOL fForceUnload)
+#ifndef DACCESS_COMPILE
+
+#define INITIAL_ASSEMBLY_MAP_SIZE 17
+void SharedDomain::Init()
 {
     CONTRACTL
     {
         THROWS;
-        MODE_COOPERATIVE;
         GC_TRIGGERS;
+        MODE_ANY;
         INJECT_FAULT(COMPlusThrowOM(););
     }
     CONTRACTL_END;
 
-#ifdef FEATURE_MULTICOREJIT
-
-    // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
-    GetMulticoreJitManager().StopProfile(true);
-
-#endif
-
-    Thread *pThread = GetThread();
+    BaseDomain::Init();
 
+#ifdef FEATURE_LOADER_OPTIMIZATION
+    m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
 
-    if (! fForceUnload && !g_pConfig->AppDomainUnload())
-        return;
+    LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
+    m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
+#endif // FEATURE_LOADER_OPTIMIZATION 
 
-    EPolicyAction action;
-    EClrOperation operation;
-    if (!IsRudeUnload())
-    {
-        operation = OPR_AppDomainUnload;
-    }
-    else
-    {
-        operation = OPR_AppDomainRudeUnload;
-    }
-    action = GetEEPolicy()->GetDefaultAction(operation,NULL);
-    GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
+    ETW::LoaderLog::DomainLoad(this);
+}
 
-    switch (action)
-    {
-    case eUnloadAppDomain:
-        break;
-    case eRudeUnloadAppDomain:
-        SetRudeUnload();
-        break;
-    case eExitProcess:
-    case eFastExitProcess:
-    case eRudeExitProcess:
-    case eDisableRuntime:
-        EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
-        _ASSERTE (!"Should not get here");
-        break;
-    default:
-        break;
-    }
+#ifndef CROSSGEN_COMPILE
+void SharedDomain::Terminate()
+{
+    // make sure we delete the StringLiteralMap before unloading
+    // the asemblies since the string literal map entries can
+    // point to metadata string literals.
+    GetLoaderAllocator()->CleanupStringLiteralMap();
 
-#if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
-    static int unloadCount = 0;
-#endif
+#ifdef FEATURE_LOADER_OPTIMIZATION    
+    PtrHashMap::PtrIterator i = m_assemblyMap.begin();
 
-#ifdef AD_LOG_MEMORY
+    while (!i.end())
     {
-        GCX_PREEMP();
-        static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
-        typedef void (__cdecl *LogItFcn) ( int );
-        static LogItFcn pLogIt = NULL;
-
-        if (logMemory && ! pLogIt)
-        {
-            HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
-            if (hMod)
-            {
-                pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
-                if (pLogIt)
-                {
-                    pLogIt(9999);
-                    pLogIt(9999);
-                }
-            }
-        }
+        Assembly *pAssembly = (Assembly*) i.GetValue();
+        delete pAssembly;
+        ++i;
     }
-#endif // AD_LOG_MEMORY
-
-    if (IsDefaultDomain() && !IsSingleAppDomain())
-        COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
-
-    _ASSERTE(CanUnload());
-
-    if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
-        COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
 
-    _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
-
-    // should not be running in this AD because unload spawned thread in default domain
-    if (!NingenEnabled())
+    ListLockEntry* pElement;
+    pElement = m_FileCreateLock.Pop(TRUE);
+    while (pElement)
     {
-        _ASSERTE(!pThread->IsRunningIn(this, NULL));
-    }
-
-
-#ifdef APPDOMAIN_STATE
-    _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
+#ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
+        _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
 #endif
-
-    LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
-
-    STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
-
-    UnloadHolder hold(this);
-
-    SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
-    SystemDomain::System()->SetUnloadingThread(pThread);
-
-
-#ifdef _DEBUG
-    static int dumpSB = -1;
-
-    if (dumpSB == -1)
-        dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
-
-    if (dumpSB > 1)
-    {
-        LogSpewAlways("Starting unload %3.3d\n", unloadCount);
-        DumpSyncBlockCache();
+        delete(pElement);
+        pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
     }
-#endif // _DEBUG
-
-    BOOL bForceGC=m_bForceGCOnUnload;
-
-#ifdef AD_LOG_MEMORY
-    if (pLogIt)
-        bForceGC=TRUE;
-#endif // AD_LOG_MEMORY
-
-#ifdef AD_SNAPSHOT
-    static int takeSnapShot = -1;
-
-    if (takeSnapShot == -1)
-        takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
-
-    if (takeSnapShot)
-        bForceGC=TRUE;
-#endif // AD_SNAPSHOT
+    m_FileCreateLock.Destroy();
+#endif // FEATURE_LOADER_OPTIMIZATION    
+    BaseDomain::Terminate();
+}
+#endif // CROSSGEN_COMPILE
 
-#ifdef _DEBUG
-    if (dumpSB > 0)
-        bForceGC=TRUE;
-#endif // _DEBUG
-    static int cfgForceGC = -1;
 
-    if (cfgForceGC == -1)
-        cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
 
-    bForceGC=bForceGC||cfgForceGC;
-    AppDomainRefHolder This(this);
-    AddRef();
+#ifdef FEATURE_LOADER_OPTIMIZATION
 
-    // Do the actual unloading
-    {
-        // We do not want other threads to abort the current one.
-        ThreadPreventAsyncHolder preventAsync;
-        Exit(TRUE, !bForceGC);
-    }
-    if(bForceGC)
+BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
+{
+    CONTRACTL
     {
-        GCHeapUtilities::GetGCHeap()->GarbageCollect();
-        FinalizerThread::FinalizerThreadWait();
-        SetStage(STAGE_COLLECTED);
-        Close(); //NOTHROW!
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
     }
+    CONTRACTL_END;
 
-#ifdef AD_LOG_MEMORY
-    if (pLogIt)
-    {
-        GCX_PREEMP();
-        pLogIt(unloadCount);
-    }
-#endif // AD_LOG_MEMORY
+    // This is the input to the lookup
+    SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
 
-#ifdef AD_SNAPSHOT
-    if (takeSnapShot)
+    // This is the value stored in the table
+    Assembly *pAssembly = (Assembly *) u2;
+    if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
     {
-        char buffer[1024];
-        sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
-        system(buffer);
-        sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
-        system(buffer);
-        int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
-        if (takeDHSnapShot)
-        {
-            sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
-            system(buffer);
-        }
-    }
-#endif // AD_SNAPSHOT
+        if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
+            return FALSE;
 
-#ifdef _DEBUG
-    if (dumpSB > 0)
-    {
-        // do extra finalizer wait to remove any leftover sb entries
-        FinalizerThread::FinalizerThreadWait();
-        GCHeapUtilities::GetGCHeap()->GarbageCollect();
-        FinalizerThread::FinalizerThreadWait();
-        LogSpewAlways("Done unload %3.3d\n", unloadCount);
-        DumpSyncBlockCache();
-        ShutdownLogging();
-        WCHAR buffer[128];
-        swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
-        _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
-        // this will open a new file
-        InitLogging();
+        return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
     }
-#endif // _DEBUG
+    else
+    if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
+        return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
+    else
+    if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
+        return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
+     _ASSERTE(!"Unexpected type of assembly locator");
+    return FALSE;
 }
 
-void AppDomain::ExceptionUnwind(Frame *pFrame)
+DWORD SharedAssemblyLocator::Hash()
 {
     CONTRACTL
     {
-        DISABLED(GC_TRIGGERS);  // EEResourceException
-        DISABLED(THROWS);   // EEResourceException
+        THROWS;
+        GC_TRIGGERS;
         MODE_ANY;
+        INJECT_FAULT(COMPlusThrowOM(););
     }
     CONTRACTL_END;
+    if (m_type==DOMAINASSEMBLY)
+        return GetDomainAssembly()->HashIdentity();
+    if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
+        return GetPEAssembly()->HashIdentity();
+     _ASSERTE(!"Unexpected type of assembly locator");
+     return 0;
+}
 
-    LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
-#if _DEBUG_ADUNLOAD
-    printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
-#endif
-    Thread *pThread = GetThread();
-    _ASSERTE(pThread);
-
-    if (! pThread->ShouldChangeAbortToUnload(pFrame))
+Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
+{
+    CONTRACTL
     {
-        LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
-        return;
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        INJECT_FAULT(COMPlusThrowOM(););
     }
+    CONTRACTL_END;
 
-    LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
+    Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
+    if (match != (Assembly *) INVALIDENTRY)
+        return match;
+    else
+        return NULL;
+}
 
-    GCX_COOP();
-    OBJECTREF throwable = NULL;
-    EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
-    throwable = e.GetThrowable();
+SIZE_T SharedDomain::GetShareableAssemblyCount()
+{
+    LIMITED_METHOD_CONTRACT;
 
-    // reset the exception to an AppDomainUnloadedException
-    if (throwable != NULL)
-    {
-        GetThread()->SafeSetThrowables(throwable);
-    }
+    return m_assemblyMap.GetCount();
 }
 
-BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
+void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
 {
     CONTRACTL
     {
         THROWS;
         GC_TRIGGERS;
         MODE_ANY;
-        SO_INTOLERANT;
+        INJECT_FAULT(COMPlusThrowOM(););
     }
     CONTRACTL_END;
 
-    Thread *pThread = NULL;
-    DWORD nThreadsNeedMoreWork=0;
-    if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
-    {
-        Thread *pCurThread = GetThread();
-        if (pCurThread->CatchAtSafePoint())
-            pCurThread->PulseGCMode();
-
-        {
-            // We know which thread is not in the domain now.  We just need to
-            // work on those threads.  We do not need to suspend the runtime.
-            ThreadStoreLockHolder tsl;
-
-            while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
-            {
-                if (pThread == pCurThread)
-                {
-                    continue;
-                }
-
-                if (pThread == FinalizerThread::GetFinalizerThread())
-                {
-                    continue;
-                }
-
-                if (pThread->GetUnloadBoundaryFrame() == NULL)
-                {
-                    continue;
-                }
-
-                // A thread may have UnloadBoundaryFrame set if
-                // 1. Being unloaded by AD unload helper thread
-                // 2. Escalation from OOM or SO triggers AD unload
-                // Here we only need to work on threads that are in the domain.  If we work on other threads,
-                // those threads may be stucked in a finally, and we will not be able to escalate for them,
-                // therefore AD unload is blocked.
-                if (pThread->IsBeingAbortedForADUnload() ||
-                    pThread == SystemDomain::System()->GetUnloadRequestingThread())
-                {
-                    nThreadsNeedMoreWork++;
-                }
-
-                if (!(IsRudeUnload() ||
-                      (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
-                {
-                    continue;
-                }
-
-                if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
-                {
-                    // Mark thread for abortion only once; later on interrupt only
-                    *pFMarkUnloadRequestThread = FALSE;
-                    pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
-                }
-                else
-                {
-                    if (pThread->m_State & Thread::TS_Interruptible)
-                    {
-                        pThread->UserInterrupt(Thread::TI_Abort);
-                    }
-                }
-
-                if (pThread->PreemptiveGCDisabledOther())
-                {
-        #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
-                    Thread::SuspendThreadResult str = pThread->SuspendThread();
-                    if (str == Thread::STR_Success)
-                    {
-                        if (pThread->PreemptiveGCDisabledOther() &&
-                            (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
-                        {
-                            pThread->HandleJITCaseForAbort();
-                        }
-                        pThread->ResumeThread();
-                    }
-        #endif
-                }
-            }
-        } // ThreadStoreLockHolder
-
-        m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
-        return !nThreadsNeedMoreWork;
-    }
-
-    // For now piggyback on the GC's suspend EE mechanism
-    ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
-#ifdef _DEBUG
-    // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
-    _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
-#endif // _DEBUG
-
-    int totalADCount = 0;
-    int finalizerADCount = 0;
-    pThread = NULL;
-
-    RuntimeExceptionKind reKind = kLastException;
-    UINT resId = 0;
-    SmallStackSString ssThreadId;
+    // We have a lock on the file. There should be no races to add the same assembly.
 
-    while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
     {
-        // we already checked that we're not running in the unload domain
-        if (pThread == GetThread())
-        {
-            continue;
-        }
-
-#ifdef _DEBUG
-        void PrintStackTraceWithADToLog(Thread *pThread);
-        if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
-            LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
-            PrintStackTraceWithADToLog(pThread);
-        }
-#endif // _DEBUG
-        int count = 0;
-        Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
-        if (! pFrame) {
-            _ASSERTE(count == 0);
-            if (pThread->IsBeingAbortedForADUnload())
-            {
-                pThread->ResetBeginAbortedForADUnload();
-            }
-            continue;
-        }
+        LockHolder holder(this);
 
-        if (pThread != FinalizerThread::GetFinalizerThread())
-        {
-            totalADCount += count;
-            nThreadsNeedMoreWork++;
-            pThread->SetUnloadBoundaryFrame(pFrame);
-        }
-        else
+        EX_TRY
         {
-            finalizerADCount = count;
+            pAssembly->SetIsTenured();
+            m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
         }
-
-        // don't setup the exception info for the unloading thread unless it's the last one in
-        if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
-            (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
+        EX_HOOK
         {
-#ifdef AD_BREAK_ON_CANNOT_UNLOAD
-            static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
-            if (breakOnCannotUnload)
-                _ASSERTE(!"Cannot unload AD");
-#endif // AD_BREAK_ON_CANNOT_UNLOAD
-            reKind = kCannotUnloadAppDomainException;
-            resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
-            ssThreadId.Printf(W("%x"), pThread->GetThreadId());
-            STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
-            // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
-            // it's better to chew a little extra time here and make sure our counts are consistent
+            // There was an error adding the assembly to the assembly hash (probably an OOM),
+            // so we need to unset the tenured bit so that correct cleanup can happen.
+            pAssembly->UnsetIsTenured();
         }
-        // only abort the thread requesting the unload if it's the last one in, that way it will get
-        // notification that the unload failed for some other thread not being aborted. And don't abort
-        // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
-        // then we will eventually get a CannotUnloadException on it.
+        EX_END_HOOK
+    }
 
-        if (pThread != FinalizerThread::GetFinalizerThread() &&
-            // If the domain is rudely unloaded, we will unwind the requesting thread out
-            // Rude unload is going to succeed, or escalated to disable runtime or higher.
-            (IsRudeUnload() ||
-             (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
-            )
-           )
-        {
+    LOG((LF_CODESHARING,
+         LL_INFO100,
+         "Successfully added shareable assembly \"%s\".\n",
+         pAssembly->GetManifestFile()->GetSimpleName()));
+}
 
-            STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
-            LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
-#if _DEBUG_ADUNLOAD
-            printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
-#endif
-            if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
-            {
-                // Mark thread for abortion only once; later on interrupt only
-                *pFMarkUnloadRequestThread = FALSE;
-            }
-            pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
-        }
-        TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
-    }
-    _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
+#endif // FEATURE_LOADER_OPTIMIZATION
+#endif // !DACCESS_COMPILE
 
-    //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
-    if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
-        FreeBuildDebugBreak();
+DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
+{
+    CONTRACTL {
+        NOTHROW;
+        GC_NOTRIGGER;
+        SO_TOLERANT;
+    } CONTRACTL_END;
 
-    // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
-    // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
-    // exit the domain gracefully.
-    // m_dwThreadEnterCount = totalADCount;
+    {   // SO tolerance exception for debug-only assertion.
+        CONTRACT_VIOLATION(SOToleranceViolation);
+        CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
+    }
 
-    if (reKind != kLastException)
+    if (pMT->IsDynamicStatics())
     {
-        pThread = NULL;
-        while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
-        {
-            if (pThread->IsBeingAbortedForADUnload())
-            {
-                pThread->ResetBeginAbortedForADUnload();
-            }
-        }
+        _ASSERTE(!pMT->ContainsGenericVariables());
+        DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
+        if(m_aDynamicEntries <= dynamicClassID)
+            return FALSE;
+        return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
+    }
+    else
+    {
+        if (iClassIndex == (DWORD)-1)
+            iClassIndex = pMT->GetClassIndex();
+        return GetPrecomputedStaticsClassData()[iClassIndex];
     }
-
-    // CommonTripThread will handle the abort for any threads that we've marked
-    ThreadSuspend::RestartEE(FALSE, TRUE);
-    if (reKind != kLastException)
-        COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
-
-    _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
-    
-    m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
-    return (totalADCount == 0);
 }
 
-void AppDomain::UnwindThreads()
-{
-    // This function should guarantee appdomain
-    // consistency even if it fails. Everything that is going
-    // to make the appdomain impossible to reenter
-    // should be factored out
+#ifndef DACCESS_COMPILE
 
-    // <TODO>@todo: need real synchronization here!!!</TODO>
+void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
+{
     CONTRACTL
     {
-        MODE_COOPERATIVE;
         THROWS;
         GC_TRIGGERS;
+        MODE_ANY;
     }
     CONTRACTL_END;
 
-    int retryCount = -1;
-    m_dwThreadsStillInAppDomain=(ULONG)-1;
-    ULONGLONG startTime = CLRGetTickCount64();
+    BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
 
-    if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
-        !IsRudeUnload())
-    {
-        GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
-        SetRudeUnload();
-    }
+    _ASSERTE(!IsClassInitialized(pMT));
+    _ASSERTE(!IsClassInitError(pMT));
 
-    // Force threads to go through slow path during AD unload.
-    TSSuspendHolder shTrap;
+    SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
+}
 
-    BOOL fCurrentUnloadMode = IsRudeUnload();
-    BOOL fMarkUnloadRequestThread = TRUE;
+void DomainLocalModule::SetClassInitError(MethodTable* pMT)
+{
+    WRAPPER_NO_CONTRACT;
 
-    // now wait for all the threads running in our AD to get out
-    do
-    {
-        DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
-        EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
-        if (timeout != INFINITE && action > eUnloadAppDomain) {
-            // Escalation policy specified.
-            ULONGLONG curTime = CLRGetTickCount64();
-            ULONGLONG elapseTime = curTime - startTime;
-            if (elapseTime > timeout)
-            {
-                // Escalate
-                switch (action)
-                {
-                case eRudeUnloadAppDomain:
-                    GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
-                    SetRudeUnload();
-                    STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
-                    break;
-                case eExitProcess:
-                case eFastExitProcess:
-                case eRudeExitProcess:
-                case eDisableRuntime:
-                    GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
-                    EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
-                    _ASSERTE (!"Should not reach here");
-                    break;
-                default:
-                    break;
-                }
-            }
-        }
-#ifdef _DEBUG
-        if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
-            DumpADThreadTrack();
-#endif // _DEBUG
-        BOOL fNextUnloadMode = IsRudeUnload();
-        if (fCurrentUnloadMode != fNextUnloadMode)
-        {
-            // We have changed from normal unload to rude unload.  We need to mark the thread
-            // with RudeAbort, but we can only do this safely if the runtime is suspended.
-            fCurrentUnloadMode = fNextUnloadMode;
-            retryCount = -1;
-        }
-        if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
-            break;
-        if (timeout != INFINITE)
-        {
-            // Turn off the timeout used by AD.
-            retryCount = 1;
-        }
-        else
-        {
-            // GCStress takes a long time to unwind, due to expensive creation of
-            // a threadabort exception.
-            if (!GCStress<cfg_any>::IsEnabled())
-                ++retryCount;
-            LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
-#if _DEBUG_ADUNLOAD
-            printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
-#endif
-        }
+    BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
 
-        if (m_dwThreadEnterCount != 0)
-        {
-#ifdef _DEBUG
-            GetThread()->UserSleep(20);
-#else // !_DEBUG
-            GetThread()->UserSleep(10);
-#endif // !_DEBUG
-        }
+    SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
+}
+
+void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
+{
+    CONTRACTL {
+        THROWS;
+        GC_TRIGGERS;
+        PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
+        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
+        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
+    } CONTRACTL_END;
+
+    if (pMT->IsDynamicStatics())
+    {
+        _ASSERTE(!pMT->ContainsGenericVariables());
+        DWORD dwID = pMT->GetModuleDynamicEntryID();
+        EnsureDynamicClassIndex(dwID);
+        m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
+    }
+    else
+    {
+        GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
     }
-    while (TRUE) ;
 }
 
-void AppDomain::ClearGCHandles()
+void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
 {
     CONTRACTL
     {
+        THROWS;
         GC_TRIGGERS;
-        MODE_COOPERATIVE;
-        NOTHROW;
+        MODE_ANY;
+        INJECT_FAULT(COMPlusThrowOM(););
+        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
+        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
     }
     CONTRACTL_END;
 
-    SetStage(STAGE_HANDLETABLE_NOACCESS);
+    if (dwID < m_aDynamicEntries)
+    {
+        _ASSERTE(m_pDynamicClassTable.Load() != NULL);
+        return;
+    }
+
+    SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
+    while (aDynamicEntries <= dwID)
+    {
+        aDynamicEntries *= 2;
+    }
+
+    DynamicClassInfo* pNewDynamicClassTable;
+    pNewDynamicClassTable = (DynamicClassInfo*)
+        (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
+            S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
+
+    memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
+
+    // Note: Memory allocated on loader heap is zero filled
+    // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
 
-    GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
+    _ASSERTE(m_aDynamicEntries%2 == 0);
 
-    // Remove our handle store as a source of GC roots
-    m_handleStore->Uproot();
+    // Commit new dynamic table. The lock-free helpers depend on the order.
+    MemoryBarrier();
+    m_pDynamicClassTable = pNewDynamicClassTable;
+    MemoryBarrier();
+    m_aDynamicEntries = aDynamicEntries;
 }
 
-void AppDomain::ClearGCRoots()
+#ifndef CROSSGEN_COMPILE
+void    DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
 {
     CONTRACTL
     {
+        THROWS;
         GC_TRIGGERS;
-        MODE_COOPERATIVE;
-        NOTHROW;
+        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
+        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
     }
     CONTRACTL_END;
 
-    Thread *pThread = NULL;
-    ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
+    _ASSERTE(!pMT->ContainsGenericVariables());
+    _ASSERTE(!pMT->IsSharedByGenericInstantiations());
+    _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
+    _ASSERTE(pMT->IsDynamicStatics());
 
-    // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
-    // this point, so only need to synchronize the preemptive mode threads.
-    ExecutionManager::Unload(GetLoaderAllocator());
+    DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
 
-    while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
-    {
-        // Delete the thread local static store
-        pThread->DeleteThreadStaticData(this);
+    EnsureDynamicClassIndex(dynamicEntryIDIndex);
 
-        // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
-        if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
+    _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
+
+    EEClass *pClass = pMT->GetClass();
+
+    DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
+    DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
+
+    _ASSERTE(!IsClassAllocated(pMT));
+    _ASSERTE(!IsClassInitialized(pMT));
+    _ASSERTE(!IsClassInitError(pMT));
+
+    DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
+
+    // We need this check because maybe a class had a cctor but no statics
+    if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
+    {
+        if (pDynamicStatics == NULL)
         {
-            // Never delete a handle to a preallocated exception object.
-            if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
+            LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
+
+            if (pMT->Collectible())
             {
-                DestroyHandle(pThread->m_LastThrownObjectHandle);
+                pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
             }
+            else
+            {
+                SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
 
-            pThread->m_LastThrownObjectHandle = NULL;
-        }
+#ifdef FEATURE_64BIT_ALIGNMENT
+                // Allocate memory with extra alignment only if it is really necessary
+                if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
+                {
+                    static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
+                    pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
+                }
+                else
+#endif
+                    pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
+            }
 
-        // Clear out the exceptions objects held by a thread.
-        pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
-    }
+            // Note: Memory allocated on loader heap is zero filled
 
-    //delete them while we still have the runtime suspended
-    // This must be deleted before the loader heaps are deleted.
-    if (m_pMarshalingData != NULL)
-    {
-        delete m_pMarshalingData;
-        m_pMarshalingData = NULL;
-    }
+            m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
+        }
 
-    if (m_pLargeHeapHandleTable != NULL)
-    {
-        delete m_pLargeHeapHandleTable;
-        m_pLargeHeapHandleTable = NULL;
+        if (pMT->Collectible() && (dwStaticBytes != 0))
+        {
+            GCX_COOP();
+            OBJECTREF nongcStaticsArray = NULL;
+            GCPROTECT_BEGIN(nongcStaticsArray);
+#ifdef FEATURE_64BIT_ALIGNMENT
+            // Allocate memory with extra alignment only if it is really necessary
+            if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
+                nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
+            else
+#endif
+                nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
+            ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
+            GCPROTECT_END();
+        }
+        if (dwNumHandleStatics > 0)
+        {
+            if (!pMT->Collectible())
+            {
+                GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
+                                                              &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
+            }
+            else
+            {
+                GCX_COOP();
+                OBJECTREF gcStaticsArray = NULL;
+                GCPROTECT_BEGIN(gcStaticsArray);
+                gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
+                ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
+                GCPROTECT_END();
+            }
+        }
     }
-
-    ThreadSuspend::RestartEE(FALSE, TRUE);
 }
 
-#ifdef _DEBUG
 
-void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
+void DomainLocalModule::PopulateClass(MethodTable *pMT)
 {
     CONTRACTL
     {
-        NOTHROW;
-        GC_NOTRIGGER;
-        // REENTRANT
-        PRECONDITION(CheckPointer(pThread));
-        PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
+        THROWS;
+        GC_TRIGGERS;
     }
     CONTRACTL_END;
 
-    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
-        ;
-    if (m_pThreadTrackInfoList == NULL)
-        m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
-    // If we don't assert here, we will AV in the for loop below
-    _ASSERTE(m_pThreadTrackInfoList);
+    _ASSERTE(!pMT->ContainsGenericVariables());
 
-    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
+    // <todo> the only work actually done here for non-dynamics is the freezing related work.
+    // See if we can eliminate this and make this a dynamic-only path </todo>
+    DWORD iClassIndex = pMT->GetClassIndex();
 
-    ThreadTrackInfo *pTrack = NULL;
-    int i;
-    for (i=0; i < pTrackList->Count(); i++) {
-        if ((*(pTrackList->Get(i)))->pThread == pThread) {
-            pTrack = *(pTrackList->Get(i));
-            break;
-        }
-    }
-    if (! pTrack) {
-        pTrack = new (nothrow) ThreadTrackInfo;
-        // If we don't assert here, we will AV in the for loop below.
-        _ASSERTE(pTrack);
-        pTrack->pThread = pThread;
-        ThreadTrackInfo **pSlot = pTrackList->Append();
-        *pSlot = pTrack;
-    }
-
-    InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
-    Frame **pSlot;
-    if (pTrack)
+    if (!IsClassAllocated(pMT, iClassIndex))
     {
-        pSlot = pTrack->frameStack.Insert(0);
-        *pSlot = pFrame;
-    }
-    int totThreads = 0;
-    for (i=0; i < pTrackList->Count(); i++)
-        totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
-    _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
+        BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
 
-    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
-}
+        if (!IsClassAllocated(pMT, iClassIndex))
+        {
+            // Allocate dynamic space if necessary
+            if (pMT->IsDynamicStatics())
+                AllocateDynamicClass(pMT);
+
+            // determine flags to set on the statics block
+            DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
 
+            if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
+            {
+                _ASSERTE(!IsClassInitialized(pMT));
+                _ASSERTE(!IsClassInitError(pMT));
+                dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
+            }
 
-void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
-{
-    CONTRACTL
-    {
-        if (GetThread()) {MODE_COOPERATIVE;}
-        NOTHROW;
-        GC_NOTRIGGER;
-    }
-    CONTRACTL_END;
+            if (pMT->Collectible())
+            {
+                dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
+            }
 
-    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
-        ;
-    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
-    _ASSERTE(pTrackList);
-    ThreadTrackInfo *pTrack = NULL;
-    int i;
-    for (i=0; i < pTrackList->Count(); i++)
-    {
-        if ((*(pTrackList->Get(i)))->pThread == pThread)
-        {
-            pTrack = *(pTrackList->Get(i));
-            break;
+            // Set all flags at the same time to avoid races
+            SetClassFlags(pMT, dwFlags);
         }
     }
-    _ASSERTE(pTrack);
-    _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
-    pTrack->frameStack.Delete(0);
-    InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
-
-    int totThreads = 0;
-    for (i=0; i < pTrackList->Count(); i++)
-        totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
-    _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
 
-    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
+    return;
 }
+#endif // CROSSGEN_COMPILE
 
-void AppDomain::DumpADThreadTrack()
+void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
 {
     CONTRACTL
     {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_COOPERATIVE;
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        INJECT_FAULT(COMPlusThrowOM(););
+        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
+        PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
     }
     CONTRACTL_END;
 
-    while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
-        ;
-    ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
-    if (!pTrackList)
-        goto end;
+    if (m_aModuleIndices > index.m_dwIndex)
+    {
+        _ASSERTE(m_pModuleSlots != NULL);
+        return;
+    }
 
+    SIZE_T aModuleIndices = max(16, m_aModuleIndices);
+    while (aModuleIndices <= index.m_dwIndex)
     {
-        LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
-             m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
-        int totThreads = 0;
-        for (int i=0; i < pTrackList->Count(); i++)
-        {
-            ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
-            if (pTrack->frameStack.Count()==0)
-                continue;
-            LOG((LF_APPDOMAIN, LL_INFO100, "  ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
-            totThreads += pTrack->frameStack.Count();
-            for (int j=0; j < pTrack->frameStack.Count(); j++)
-                LOG((LF_APPDOMAIN, LL_INFO100, "      frame %8.8x\n", *(pTrack->frameStack.Get(j))));
-        }
-        _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
+        aModuleIndices *= 2;
     }
-end:
-    InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
-}
-#endif // _DEBUG
 
+    PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
 
-#endif // CROSSGEN_COMPILE
+    memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
+
+    // Note: Memory allocated on loader heap is zero filled
+    // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
+
+    // Commit new table. The lock-free helpers depend on the order.
+    MemoryBarrier();
+    m_pModuleSlots = pNewModuleSlots;
+    MemoryBarrier();
+    m_aModuleIndices = aModuleIndices;
 
-void *SharedDomain::operator new(size_t size, void *pInPlace)
-{
-    LIMITED_METHOD_CONTRACT;
-    return pInPlace;
 }
 
-void SharedDomain::operator delete(void *pMem)
+void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
 {
-    LIMITED_METHOD_CONTRACT;
-    // Do nothing - new() was in-place
+    // Need to synchronize with table growth in this domain
+    BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
+
+    EnsureModuleIndex(index);
+
+    _ASSERTE(index.m_dwIndex < m_aModuleIndices);
+
+    // We would like this assert here, unfortunately, loading a module in this appdomain can fail
+    // after here  and we will keep the module around and reuse the slot when we retry (if
+    // the failure happened due to a transient error, such as OOM). In that case the slot wont
+    // be null.
+    //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
+
+    m_pModuleSlots[index.m_dwIndex] = pLocalModule;
 }
 
+#ifndef CROSSGEN_COMPILE
 
-void SharedDomain::Attach()
+DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
 {
     CONTRACTL
     {
-        THROWS;
-        GC_TRIGGERS;
         MODE_ANY;
+        GC_TRIGGERS;
+        THROWS;
         INJECT_FAULT(COMPlusThrowOM(););
     }
     CONTRACTL_END;
 
-    // Create the global SharedDomain and initialize it.
-    m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
-    SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
-    // This cannot fail since g_pSharedDomainMemory is a static array.
-    CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
+    OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
 
-    LOG((LF_CLASSLOADER,
-         LL_INFO10,
-         "Created shared domain at %p\n",
-         m_pSharedDomain));
 
-    // We need to initialize the memory pools etc. for the system domain.
-    m_pSharedDomain->Init(); // Setup the memory heaps
+    DomainAssembly* pResolvedAssembly = NULL;
+    _ASSERTE(strcmp(szName, g_AppDomainClassName));
 
-    // allocate a Virtual Call Stub Manager for the shared domain
-    m_pSharedDomain->InitVSD();
-}
+    GCX_COOP();
 
-#ifndef CROSSGEN_COMPILE
-void SharedDomain::Detach()
-{
-    if (m_pSharedDomain)
+    struct _gc {
+        OBJECTREF AppDomainRef;
+        OBJECTREF AssemblyRef;
+        STRINGREF str;
+    } gc;
+    ZeroMemory(&gc, sizeof(gc));
+
+    GCPROTECT_BEGIN(gc);
+    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
     {
-        m_pSharedDomain->Terminate();
-        delete m_pSharedDomain;
-        m_pSharedDomain = NULL;
-    }
-}
-#endif // CROSSGEN_COMPILE
+        if (pAssembly != NULL)
+            gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
 
-#endif // !DACCESS_COMPILE
+        MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
 
-SharedDomain *SharedDomain::GetDomain()
-{
-    LIMITED_METHOD_DAC_CONTRACT;
+        gc.str = StringObject::NewString(szName);
+        ARG_SLOT args[3] =
+        {
+            ObjToArgSlot(gc.AppDomainRef),
+            ObjToArgSlot(gc.AssemblyRef),
+            ObjToArgSlot(gc.str)
+        };
+        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
 
-    return m_pSharedDomain;
+        if (ResultingAssemblyRef != NULL)
+        {
+            pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
+
+            if (pResultingAssemblyRef)
+                *pResultingAssemblyRef = ResultingAssemblyRef;
+            else
+            {
+                if (pResolvedAssembly->IsCollectible())
+                {
+                    COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
+                }
+            }
+        }
+    }
+    GCPROTECT_END();
+
+    return pResolvedAssembly;
 }
 
-#ifndef DACCESS_COMPILE
 
-#define INITIAL_ASSEMBLY_MAP_SIZE 17
-void SharedDomain::Init()
+Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
 {
-    CONTRACTL
+    CONTRACT(Assembly*)
     {
         THROWS;
         GC_TRIGGERS;
         MODE_ANY;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
         INJECT_FAULT(COMPlusThrowOM(););
     }
-    CONTRACTL_END;
+    CONTRACT_END;
 
-    BaseDomain::Init();
+    Assembly* pResolvedAssembly = NULL;
 
-#ifdef FEATURE_LOADER_OPTIMIZATION
-    m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
+    GCX_COOP();
 
-    LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
-    m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
-#endif // FEATURE_LOADER_OPTIMIZATION 
+    struct _gc {
+        OBJECTREF AppDomainRef;
+        OBJECTREF AssemblyRef;
+        STRINGREF str;
+    } gc;
+    ZeroMemory(&gc, sizeof(gc));
 
-    ETW::LoaderLog::DomainLoad(this);
-}
-
-#ifndef CROSSGEN_COMPILE
-void SharedDomain::Terminate()
-{
-    // make sure we delete the StringLiteralMap before unloading
-    // the asemblies since the string literal map entries can
-    // point to metadata string literals.
-    GetLoaderAllocator()->CleanupStringLiteralMap();
-
-#ifdef FEATURE_LOADER_OPTIMIZATION    
-    PtrHashMap::PtrIterator i = m_assemblyMap.begin();
-
-    while (!i.end())
-    {
-        Assembly *pAssembly = (Assembly*) i.GetValue();
-        delete pAssembly;
-        ++i;
-    }
-
-    ListLockEntry* pElement;
-    pElement = m_FileCreateLock.Pop(TRUE);
-    while (pElement)
-    {
-#ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
-        _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
-#endif
-        delete(pElement);
-        pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
-    }
-    m_FileCreateLock.Destroy();
-#endif // FEATURE_LOADER_OPTIMIZATION    
-    BaseDomain::Terminate();
-}
-#endif // CROSSGEN_COMPILE
-
-
-
-#ifdef FEATURE_LOADER_OPTIMIZATION
-
-BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    // This is the input to the lookup
-    SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
-
-    // This is the value stored in the table
-    Assembly *pAssembly = (Assembly *) u2;
-    if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
-    {
-        if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
-            return FALSE;
-
-        return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
-    }
-    else
-    if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
-        return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
-    else
-    if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
-        return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
-     _ASSERTE(!"Unexpected type of assembly locator");
-    return FALSE;
-}
-
-DWORD SharedAssemblyLocator::Hash()
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-    if (m_type==DOMAINASSEMBLY)
-        return GetDomainAssembly()->HashIdentity();
-    if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
-        return GetPEAssembly()->HashIdentity();
-     _ASSERTE(!"Unexpected type of assembly locator");
-     return 0;
-}
-
-Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
-    if (match != (Assembly *) INVALIDENTRY)
-        return match;
-    else
-        return NULL;
-}
-
-SIZE_T SharedDomain::GetShareableAssemblyCount()
-{
-    LIMITED_METHOD_CONTRACT;
-
-    return m_assemblyMap.GetCount();
-}
-
-void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    // We have a lock on the file. There should be no races to add the same assembly.
-
-    {
-        LockHolder holder(this);
-
-        EX_TRY
-        {
-            pAssembly->SetIsTenured();
-            m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
-        }
-        EX_HOOK
-        {
-            // There was an error adding the assembly to the assembly hash (probably an OOM),
-            // so we need to unset the tenured bit so that correct cleanup can happen.
-            pAssembly->UnsetIsTenured();
-        }
-        EX_END_HOOK
-    }
-
-    LOG((LF_CODESHARING,
-         LL_INFO100,
-         "Successfully added shareable assembly \"%s\".\n",
-         pAssembly->GetManifestFile()->GetSimpleName()));
-}
-
-#endif // FEATURE_LOADER_OPTIMIZATION
-#endif // !DACCESS_COMPILE
-
-DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-        SO_TOLERANT;
-    } CONTRACTL_END;
-
-    {   // SO tolerance exception for debug-only assertion.
-        CONTRACT_VIOLATION(SOToleranceViolation);
-        CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
-    }
-
-    if (pMT->IsDynamicStatics())
-    {
-        _ASSERTE(!pMT->ContainsGenericVariables());
-        DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
-        if(m_aDynamicEntries <= dynamicClassID)
-            return FALSE;
-        return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
-    }
-    else
-    {
-        if (iClassIndex == (DWORD)-1)
-            iClassIndex = pMT->GetClassIndex();
-        return GetPrecomputedStaticsClassData()[iClassIndex];
-    }
-}
-
-#ifndef DACCESS_COMPILE
-
-void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
-
-    _ASSERTE(!IsClassInitialized(pMT));
-    _ASSERTE(!IsClassInitError(pMT));
-
-    SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
-}
-
-void DomainLocalModule::SetClassInitError(MethodTable* pMT)
-{
-    WRAPPER_NO_CONTRACT;
-
-    BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
-
-    SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
-}
-
-void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
-        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
-        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
-    } CONTRACTL_END;
-
-    if (pMT->IsDynamicStatics())
-    {
-        _ASSERTE(!pMT->ContainsGenericVariables());
-        DWORD dwID = pMT->GetModuleDynamicEntryID();
-        EnsureDynamicClassIndex(dwID);
-        m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
-    }
-    else
-    {
-        GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
-    }
-}
-
-void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
-        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
-    }
-    CONTRACTL_END;
-
-    if (dwID < m_aDynamicEntries)
-    {
-        _ASSERTE(m_pDynamicClassTable.Load() != NULL);
-        return;
-    }
-
-    SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
-    while (aDynamicEntries <= dwID)
-    {
-        aDynamicEntries *= 2;
-    }
-
-    DynamicClassInfo* pNewDynamicClassTable;
-    pNewDynamicClassTable = (DynamicClassInfo*)
-        (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
-            S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
-
-    memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
-
-    // Note: Memory allocated on loader heap is zero filled
-    // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
-
-    _ASSERTE(m_aDynamicEntries%2 == 0);
-
-    // Commit new dynamic table. The lock-free helpers depend on the order.
-    MemoryBarrier();
-    m_pDynamicClassTable = pNewDynamicClassTable;
-    MemoryBarrier();
-    m_aDynamicEntries = aDynamicEntries;
-}
-
-#ifndef CROSSGEN_COMPILE
-void    DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
-        PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
-    }
-    CONTRACTL_END;
-
-    _ASSERTE(!pMT->ContainsGenericVariables());
-    _ASSERTE(!pMT->IsSharedByGenericInstantiations());
-    _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
-    _ASSERTE(pMT->IsDynamicStatics());
-
-    DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
-
-    EnsureDynamicClassIndex(dynamicEntryIDIndex);
-
-    _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
-
-    EEClass *pClass = pMT->GetClass();
-
-    DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
-    DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
-
-    _ASSERTE(!IsClassAllocated(pMT));
-    _ASSERTE(!IsClassInitialized(pMT));
-    _ASSERTE(!IsClassInitError(pMT));
-
-    DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
-
-    // We need this check because maybe a class had a cctor but no statics
-    if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
-    {
-        if (pDynamicStatics == NULL)
-        {
-            LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
-
-            if (pMT->Collectible())
-            {
-                pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
-            }
-            else
-            {
-                SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
-
-#ifdef FEATURE_64BIT_ALIGNMENT
-                // Allocate memory with extra alignment only if it is really necessary
-                if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
-                {
-                    static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
-                    pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
-                }
-                else
-#endif
-                    pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
-            }
-
-            // Note: Memory allocated on loader heap is zero filled
-
-            m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
-        }
-
-        if (pMT->Collectible() && (dwStaticBytes != 0))
-        {
-            GCX_COOP();
-            OBJECTREF nongcStaticsArray = NULL;
-            GCPROTECT_BEGIN(nongcStaticsArray);
-#ifdef FEATURE_64BIT_ALIGNMENT
-            // Allocate memory with extra alignment only if it is really necessary
-            if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
-                nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
-            else
-#endif
-                nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
-            ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
-            GCPROTECT_END();
-        }
-        if (dwNumHandleStatics > 0)
-        {
-            if (!pMT->Collectible())
-            {
-                GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
-                                                              &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
-            }
-            else
-            {
-                GCX_COOP();
-                OBJECTREF gcStaticsArray = NULL;
-                GCPROTECT_BEGIN(gcStaticsArray);
-                gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
-                ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
-                GCPROTECT_END();
-            }
-        }
-    }
-}
-
-
-void DomainLocalModule::PopulateClass(MethodTable *pMT)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-    }
-    CONTRACTL_END;
-
-    _ASSERTE(!pMT->ContainsGenericVariables());
-
-    // <todo> the only work actually done here for non-dynamics is the freezing related work.
-    // See if we can eliminate this and make this a dynamic-only path </todo>
-    DWORD iClassIndex = pMT->GetClassIndex();
-
-    if (!IsClassAllocated(pMT, iClassIndex))
-    {
-        BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
-
-        if (!IsClassAllocated(pMT, iClassIndex))
-        {
-            // Allocate dynamic space if necessary
-            if (pMT->IsDynamicStatics())
-                AllocateDynamicClass(pMT);
-
-            // determine flags to set on the statics block
-            DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
-
-            if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
-            {
-                _ASSERTE(!IsClassInitialized(pMT));
-                _ASSERTE(!IsClassInitError(pMT));
-                dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
-            }
-
-            if (pMT->Collectible())
-            {
-                dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
-            }
-
-            // Set all flags at the same time to avoid races
-            SetClassFlags(pMT, dwFlags);
-        }
-    }
-
-    return;
-}
-#endif // CROSSGEN_COMPILE
-
-void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-        // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
-        PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
-    }
-    CONTRACTL_END;
-
-    if (m_aModuleIndices > index.m_dwIndex)
-    {
-        _ASSERTE(m_pModuleSlots != NULL);
-        return;
-    }
-
-    SIZE_T aModuleIndices = max(16, m_aModuleIndices);
-    while (aModuleIndices <= index.m_dwIndex)
-    {
-        aModuleIndices *= 2;
-    }
-
-    PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
-
-    memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
-
-    // Note: Memory allocated on loader heap is zero filled
-    // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
-
-    // Commit new table. The lock-free helpers depend on the order.
-    MemoryBarrier();
-    m_pModuleSlots = pNewModuleSlots;
-    MemoryBarrier();
-    m_aModuleIndices = aModuleIndices;
-
-}
-
-void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
-{
-    // Need to synchronize with table growth in this domain
-    BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
-
-    EnsureModuleIndex(index);
-
-    _ASSERTE(index.m_dwIndex < m_aModuleIndices);
-
-    // We would like this assert here, unfortunately, loading a module in this appdomain can fail
-    // after here  and we will keep the module around and reuse the slot when we retry (if
-    // the failure happened due to a transient error, such as OOM). In that case the slot wont
-    // be null.
-    //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
-
-    m_pModuleSlots[index.m_dwIndex] = pLocalModule;
-}
-
-#ifndef CROSSGEN_COMPILE
-
-DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
-{
-    CONTRACTL
-    {
-        MODE_ANY;
-        GC_TRIGGERS;
-        THROWS;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
-
-
-    DomainAssembly* pResolvedAssembly = NULL;
-    _ASSERTE(strcmp(szName, g_AppDomainClassName));
-
-    GCX_COOP();
-
-    struct _gc {
-        OBJECTREF AppDomainRef;
-        OBJECTREF AssemblyRef;
-        STRINGREF str;
-    } gc;
-    ZeroMemory(&gc, sizeof(gc));
-
-    GCPROTECT_BEGIN(gc);
-    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
-    {
-        if (pAssembly != NULL)
-            gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
-
-        MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
-
-        gc.str = StringObject::NewString(szName);
-        ARG_SLOT args[3] =
-        {
-            ObjToArgSlot(gc.AppDomainRef),
-            ObjToArgSlot(gc.AssemblyRef),
-            ObjToArgSlot(gc.str)
-        };
-        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
-
-        if (ResultingAssemblyRef != NULL)
-        {
-            pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
-
-            if (pResultingAssemblyRef)
-                *pResultingAssemblyRef = ResultingAssemblyRef;
-            else
-            {
-                if (pResolvedAssembly->IsCollectible())
-                {
-                    COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
-                }
-            }
-        }
-    }
-    GCPROTECT_END();
-
-    return pResolvedAssembly;
-}
-
-
-Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
-{
-    CONTRACT(Assembly*)
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACT_END;
-
-    Assembly* pResolvedAssembly = NULL;
-
-    GCX_COOP();
-
-    struct _gc {
-        OBJECTREF AppDomainRef;
-        OBJECTREF AssemblyRef;
-        STRINGREF str;
-    } gc;
-    ZeroMemory(&gc, sizeof(gc));
-
-    GCPROTECT_BEGIN(gc);
-    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
-    {
-        if (pAssembly != NULL)
-            gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
-
-        MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
-        gc.str = StringObject::NewString(szName);
-        ARG_SLOT args[3] =
-        {
-            ObjToArgSlot(gc.AppDomainRef),
-            ObjToArgSlot(gc.AssemblyRef),
-            ObjToArgSlot(gc.str)
-        };
-        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
-        if (ResultingAssemblyRef != NULL)
-        {
-            pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
-            if (pResolvedAssembly->IsCollectible())
-            {
-                COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
-            }
-        }
-    }
-    GCPROTECT_END();
-
-    RETURN pResolvedAssembly;
-}
-
-
-Assembly * 
-AppDomain::RaiseAssemblyResolveEvent(
-    AssemblySpec * pSpec, 
-    BOOL           fPreBind)
-{
-    CONTRACT(Assembly*)
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACT_END;
-
-    BinderMethodID methodId;
-    StackSString ssName;
-    pSpec->GetFileOrDisplayName(0, ssName);
-    
-    if (!fPreBind) 
-    {
-        methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE;  // post-bind execution event (the classic V1.0 event)
-    }
-    else
-    {
-        RETURN NULL;
-    }
-        
-
-    // Elevate threads allowed loading level.  This allows the host to load an assembly even in a restricted
-    // condition.  Note, however, that this exposes us to possible recursion failures, if the host tries to
-    // load the assemblies currently being loaded.  (Such cases would then throw an exception.)
-
-    OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
-    OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
-
-    GCX_COOP();
-
-    Assembly* pAssembly = NULL;
-
-    struct _gc {
-        OBJECTREF AppDomainRef;
-        OBJECTREF AssemblyRef;
-        STRINGREF str;
-    } gc;
-    ZeroMemory(&gc, sizeof(gc));
-
-    GCPROTECT_BEGIN(gc);
-    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
-    {
-        if (pSpec->GetParentAssembly() != NULL)
-        {
-            {
-                gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
-            }
-        }
-        MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
-
-        gc.str = StringObject::NewString(ssName);
-        ARG_SLOT args[3] = {
-            ObjToArgSlot(gc.AppDomainRef),
-            ObjToArgSlot(gc.AssemblyRef),
-            ObjToArgSlot(gc.str)
-        };
-            
-        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
-            
-        if (ResultingAssemblyRef != NULL)
-        {
-            pAssembly = ResultingAssemblyRef->GetAssembly();
-            if (pAssembly->IsCollectible())
-            {
-                COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
-            }
-        }
-    }
-    GCPROTECT_END();
-
-    if (pAssembly != NULL)
-    {
-        // Check that the public key token matches the one specified in the spec
-        // MatchPublicKeys throws as appropriate
-        pSpec->MatchPublicKeys(pAssembly);
-    }
-
-    RETURN pAssembly;
-} // AppDomain::RaiseAssemblyResolveEvent
-
-
-//---------------------------------------------------------------------------------------
-//
-// Determine the type of AppDomainManager to use for the default AppDomain
-//
-// Notes:
-//   v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
-//   domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
-//   appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
-//   fully trusted.  
-//
-
-void AppDomain::InitializeDefaultDomainManager()
-{
-    CONTRACTL
-    {
-        MODE_COOPERATIVE;
-        GC_TRIGGERS;
-        THROWS;
-        INJECT_FAULT(COMPlusThrowOM(););
-        PRECONDITION(GetId().m_dwId == DefaultADID);
-    }
-    CONTRACTL_END;
-
-    OBJECTREF orThis = GetExposedObject();
-    GCPROTECT_BEGIN(orThis);
-
-    MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
-    ARG_SLOT args[] =
-    {
-        ObjToArgSlot(orThis)
-    };
-
-    initCompatFlags.Call(args);
-
-    GCPROTECT_END();
-}
-
-CLREvent * AppDomain::g_pUnloadStartEvent;
-
-void AppDomain::CreateADUnloadWorker()
-{
-    STANDARD_VM_CONTRACT;
-
-    // Do not create adUnload thread if there is only default domain
-    if(IsSingleAppDomain())
-        return;
-
-Retry:
-    BOOL fCreator = FALSE;
-    if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1)  //we're first
-    {
-#ifdef _TARGET_X86_  // use the smallest possible stack on X86 
-        DWORD stackSize = 128 * 1024;
-#else
-        DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
-#endif
-        Thread *pThread = SetupUnstartedThread();
-        if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
-        {
-            fCreator = TRUE;
-            DWORD dwRet;
-            dwRet = pThread->StartThread();
-
-            // When running under a user mode native debugger there is a race
-            // between the moment we've created the thread (in CreateNewThread) and 
-            // the moment we resume it (in StartThread); the debugger may receive 
-            // the "ct" (create thread) notification, and it will attempt to 
-            // suspend/resume all threads in the process.  Now imagine the debugger
-            // resumes this thread first, and only later does it try to resume the
-            // newly created thread (the ADU worker thread).  In these conditions our
-            // call to ResumeThread may come before the debugger's call to ResumeThread
-            // actually causing dwRet to equal 2.
-            // We cannot use IsDebuggerPresent() in the condition below because the 
-            // debugger may have been detached between the time it got the notification
-            // and the moment we execute the test below.
-            _ASSERTE(dwRet == 1 || dwRet == 2);
-        }
-        else
-        {
-            pThread->DecExternalCount(FALSE);
-            FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
-            ThrowOutOfMemory();
-        }
-    }
-
-    YIELD_WHILE (g_fADUnloadWorkerOK == -2);
-
-    if (g_fADUnloadWorkerOK == -1) {
-        if (fCreator)
-        {
-            ThrowOutOfMemory();
-        }
-        else
-        {
-            goto Retry;
-        }
-    }
-}
-
-/*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_TRIGGERS;
-    STATIC_CONTRACT_MODE_COOPERATIVE;
-    ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
-    HRESULT hr=S_OK;
-
-    EX_TRY
-    {
-        pDomain->Unload(FALSE);
-    }
-    EX_CATCH_HRESULT(hr);
-
-    if(pADUnloadSink)
-    {
-        SystemDomain::LockHolder lh;
-        pADUnloadSink->ReportUnloadResult(hr,NULL);
-        pADUnloadSink->Release();
-    }
-}
-
-void AppDomain::DoADUnloadWork()
-{
-    CONTRACTL
+    GCPROTECT_BEGIN(gc);
+    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
     {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    DWORD i = 1;
-    while (TRUE) {
-
-        AppDomain *pDomainToUnload = NULL;
+        if (pAssembly != NULL)
+            gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
 
+        MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
+        gc.str = StringObject::NewString(szName);
+        ARG_SLOT args[3] =
         {
-            // Take the lock so that no domain can be added or removed from the system domain
-            SystemDomain::LockHolder lh;
-
-            DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
-            for (; i <= numDomain; i ++) {
-                AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
-                //
-                // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
-                // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
-                // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
-                //
-                if (pDomain && pDomain->IsUnloadRequested())
-                {
-                    pDomainToUnload = pDomain;
-                    i ++;
-                    break;
-                }
+            ObjToArgSlot(gc.AppDomainRef),
+            ObjToArgSlot(gc.AssemblyRef),
+            ObjToArgSlot(gc.str)
+        };
+        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
+        if (ResultingAssemblyRef != NULL)
+        {
+            pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
+            if (pResolvedAssembly->IsCollectible())
+            {
+                COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
             }
         }
-
-        if (!pDomainToUnload) {
-            break;
-        }
-
-        // We are the only thread that can unload domains so no one else can delete the appdomain
-        ADUnloadWorkerHelper(pDomainToUnload);            
     }
-}
-
-static void DoADUnloadWorkHelper()
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_TRIGGERS;
-    STATIC_CONTRACT_MODE_COOPERATIVE;
+    GCPROTECT_END();
 
-    EX_TRY {
-        AppDomain::DoADUnloadWork();
-    }
-    EX_CATCH
-    {
-    }
-    EX_END_CATCH(SwallowAllExceptions);
+    RETURN pResolvedAssembly;
 }
 
-ULONGLONG g_ObjFinalizeStartTime = 0;
-Volatile<BOOL> g_FinalizerIsRunning = FALSE;
-Volatile<ULONG> g_FinalizerLoopCount = 0;
-
-ULONGLONG GetObjFinalizeStartTime()
-{
-    LIMITED_METHOD_CONTRACT;
-    return g_ObjFinalizeStartTime;
-}
 
-void FinalizerThreadAbortOnTimeout()
+Assembly * 
+AppDomain::RaiseAssemblyResolveEvent(
+    AssemblySpec * pSpec, 
+    BOOL           fPreBind)
 {
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_MODE_COOPERATIVE;
-    STATIC_CONTRACT_GC_TRIGGERS;
-
+    CONTRACT(Assembly*)
     {
-        // If finalizer thread is blocked because scheduler is running another task,
-        // or it is waiting for another thread, we first see if we get finalizer thread
-        // running again.
-        Thread::ThreadAbortWatchDog();
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+        INJECT_FAULT(COMPlusThrowOM(););
     }
+    CONTRACT_END;
 
-    EX_TRY
+    BinderMethodID methodId;
+    StackSString ssName;
+    pSpec->GetFileOrDisplayName(0, ssName);
+    
+    if (!fPreBind) 
     {
-        Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
-        EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
-        switch (action)
-        {
-        case eAbortThread:
-            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
-            pFinalizerThread->UserAbort(Thread::TAR_Thread,
-                                        EEPolicy::TA_Safe,
-                                        INFINITE,
-                                        Thread::UAC_FinalizerTimeout);
-            break;
-        case eRudeAbortThread:
-            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
-            pFinalizerThread->UserAbort(Thread::TAR_Thread,
-                                        EEPolicy::TA_Rude,
-                                        INFINITE,
-                                        Thread::UAC_FinalizerTimeout);
-            break;
-        case eUnloadAppDomain:
-            {
-                AppDomain *pDomain = pFinalizerThread->GetDomain();
-                pFinalizerThread->UserAbort(Thread::TAR_Thread,
-                                            EEPolicy::TA_Safe,
-                                            INFINITE,
-                                            Thread::UAC_FinalizerTimeout);
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                }
-            }
-            break;
-        case eRudeUnloadAppDomain:
-            {
-                AppDomain *pDomain = pFinalizerThread->GetDomain();
-                pFinalizerThread->UserAbort(Thread::TAR_Thread,
-                                            EEPolicy::TA_Rude,
-                                            INFINITE,
-                                            Thread::UAC_FinalizerTimeout);
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-            }
-            break;
-        case eExitProcess:
-        case eFastExitProcess:
-        case eRudeExitProcess:
-        case eDisableRuntime:
-            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
-            EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
-            _ASSERTE (!"Should not get here");
-            break;
-        default:
-            break;
-        }
+        methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE;  // post-bind execution event (the classic V1.0 event)
     }
-    EX_CATCH
+    else
     {
+        RETURN NULL;
     }
-    EX_END_CATCH(SwallowAllExceptions);
-}
-
-enum WorkType
-{
-    WT_UnloadDomain = 0x1,
-    WT_ThreadAbort = 0x2,
-    WT_FinalizerThread = 0x4,
-    WT_ClearCollectedDomains=0x8
-};
-
-static Volatile<DWORD> s_WorkType = 0;
-
+        
 
-DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        DISABLED(GC_TRIGGERS);
+    // Elevate threads allowed loading level.  This allows the host to load an assembly even in a restricted
+    // condition.  Note, however, that this exposes us to possible recursion failures, if the host tries to
+    // load the assemblies currently being loaded.  (Such cases would then throw an exception.)
 
-        // This function will always be at the very bottom of the stack. The only
-        // user code it calls is the AppDomainUnload notifications which we will
-        // not be hardenning for Whidbey.
-        //
-        ENTRY_POINT;
-    }
-    CONTRACTL_END;
+    OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
+    OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
 
-    BEGIN_ENTRYPOINT_NOTHROW;
+    GCX_COOP();
 
-    ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
+    Assembly* pAssembly = NULL;
 
-    Thread *pThread = (Thread*)args;
-    bool fOK = (pThread->HasStarted() != 0);
+    struct _gc {
+        OBJECTREF AppDomainRef;
+        OBJECTREF AssemblyRef;
+        STRINGREF str;
+    } gc;
+    ZeroMemory(&gc, sizeof(gc));
 
+    GCPROTECT_BEGIN(gc);
+    if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
     {
-        GCX_MAYBE_PREEMP(fOK);
-
-        _ASSERTE (g_fADUnloadWorkerOK == -2);
-
-        FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
-
-        if (!fOK)
+        if (pSpec->GetParentAssembly() != NULL)
         {
-            DestroyThread(pThread);
-            goto Exit;
-        }
-
-        pThread->SetBackground(TRUE);
-
-        pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
-
-        while (TRUE) {
-            DWORD TAtimeout = INFINITE;
-            ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
-            ULONGLONG curTime = CLRGetTickCount64();
-            if (endTime <= curTime) {
-                TAtimeout = 5;
-            }
-            else
-            {
-                ULONGLONG diff = endTime - curTime;
-                if (diff < MAXULONG)
-                {
-                    TAtimeout = (DWORD)diff;
-                }
-            }
-            ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
-            DWORD finalizeTimeout = INFINITE;
-            DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
-            if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
-            {
-                if (finalizeStartTime == 0)
-                {
-                    finalizeTimeout = finalizeTimeoutSetting;
-                }
-                else
-                {
-                    endTime = finalizeStartTime + finalizeTimeoutSetting;
-                    if (endTime <= curTime) {
-                        finalizeTimeout = 0;
-                    }
-                    else
-                    {
-                        ULONGLONG diff = endTime - curTime;
-                        if (diff < MAXULONG)
-                        {
-                            finalizeTimeout = (DWORD)diff;
-                        }
-                    }
-                }
-            }
-
-            if (AppDomain::HasWorkForFinalizerThread())
-            {
-                if (finalizeTimeout > finalizeTimeoutSetting)
-                {
-                    finalizeTimeout = finalizeTimeoutSetting;
-                }
-            }
-
-            DWORD timeout = INFINITE;
-            if (finalizeTimeout <= TAtimeout)
-            {
-                timeout = finalizeTimeout;
-            }
-            else
-            {
-                timeout = TAtimeout;
-            }
-
-            if (timeout != 0)
-            {
-                LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
-                g_pUnloadStartEvent->Wait(timeout,FALSE);
-            }
-
-            if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
-            {
-                STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
-                FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
-                // only watch finalizer thread is finalizer method or unloadevent is being processed
-                if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
-                {
-                    if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
-                    {
-                        GCX_COOP();
-                        FinalizerThreadAbortOnTimeout();
-                    }
-                }
-                if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
-                {
-                    GCX_COOP();
-                    FinalizerThreadAbortOnTimeout();
-                }
-            }
-
-            if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
-            {
-                STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
-                FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
-                GCX_COOP();
-                Thread::ThreadAbortWatchDog();
-            }
-
-            if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
             {
-                STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
-                FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
-                GCX_COOP();
-                DoADUnloadWorkHelper();
+                gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
             }
+        }
+        MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
 
-            if ((s_WorkType & WT_ClearCollectedDomains) != 0)
+        gc.str = StringObject::NewString(ssName);
+        ARG_SLOT args[3] = {
+            ObjToArgSlot(gc.AppDomainRef),
+            ObjToArgSlot(gc.AssemblyRef),
+            ObjToArgSlot(gc.str)
+        };
+            
+        ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
+            
+        if (ResultingAssemblyRef != NULL)
+        {
+            pAssembly = ResultingAssemblyRef->GetAssembly();
+            if (pAssembly->IsCollectible())
             {
-                STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
-                FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
-                GCX_COOP();
-                SystemDomain::System()->ClearCollectedDomains();
+                COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
             }
-
         }
-Exit:;
-    }
-
-    END_ENTRYPOINT_NOTHROW;
-
-    return 0;
-}
+    }
+    GCPROTECT_END();
 
-void AppDomain::EnableADUnloadWorker()
-{
-    CONTRACTL
+    if (pAssembly != NULL)
     {
-        NOTHROW;
-        GC_NOTRIGGER;
-        SO_TOLERANT; // Called during a SO
+        // Check that the public key token matches the one specified in the spec
+        // MatchPublicKeys throws as appropriate
+        pSpec->MatchPublicKeys(pAssembly);
     }
-    CONTRACTL_END;
 
-    EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
+    RETURN pAssembly;
+} // AppDomain::RaiseAssemblyResolveEvent
 
-#ifdef _DEBUG
-    DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
-    if (hostTestADUnload == 2) {
-        type = EEPolicy::ADU_Rude;
-    }
-#endif // _DEBUG
 
-    EnableADUnloadWorker(type);
-}
+//---------------------------------------------------------------------------------------
+//
+// Determine the type of AppDomainManager to use for the default AppDomain
+//
+// Notes:
+//   v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
+//   domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
+//   appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
+//   fully trusted.  
+//
 
-void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
+void AppDomain::InitializeDefaultDomainManager()
 {
     CONTRACTL
     {
-        NOTHROW;
-        GC_NOTRIGGER;
-        SO_TOLERANT; // Called during a SO
+        MODE_COOPERATIVE;
+        GC_TRIGGERS;
+        THROWS;
+        INJECT_FAULT(COMPlusThrowOM(););
+        PRECONDITION(GetId().m_dwId == DefaultADID);
     }
     CONTRACTL_END;
 
-    FastInterlockOr (&s_WorkType, WT_UnloadDomain);
-
-    LONG stage = m_Stage;
-    static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
-
-    _ASSERTE(!IsDefaultDomain());
-
-    // Mark unload requested.
-    if (type == EEPolicy::ADU_Rude) {
-        SetRudeUnload();
-    }
-    while (stage < STAGE_UNLOAD_REQUESTED) {
-        stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
-    }
+    OBJECTREF orThis = GetExposedObject();
+    GCPROTECT_BEGIN(orThis);
 
-    if (!fHasStack)
+    MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
+    ARG_SLOT args[] =
     {
-        // Can not call Set due to limited stack.
-        return;
-    }
-    LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
-    g_pUnloadStartEvent->Set();
-}
+        ObjToArgSlot(orThis)
+    };
 
-void AppDomain::EnableADUnloadWorkerForThreadAbort()
-{
-    LIMITED_METHOD_CONTRACT;
-    STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
-    LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
-    FastInterlockOr (&s_WorkType, WT_ThreadAbort);
-    g_pUnloadStartEvent->Set();
+    initCompatFlags.Call(args);
+
+    GCPROTECT_END();
 }
 
+ULONGLONG g_ObjFinalizeStartTime = 0;
+Volatile<BOOL> g_FinalizerIsRunning = FALSE;
+Volatile<ULONG> g_FinalizerLoopCount = 0;
 
-void AppDomain::EnableADUnloadWorkerForFinalizer()
+ULONGLONG GetObjFinalizeStartTime()
 {
     LIMITED_METHOD_CONTRACT;
-    if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
-    {
-        LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
-        FastInterlockOr (&s_WorkType, WT_FinalizerThread);
-        g_pUnloadStartEvent->Set();
-    }
+    return g_ObjFinalizeStartTime;
 }
 
-void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
+void FinalizerThreadAbortOnTimeout()
 {
-    LIMITED_METHOD_CONTRACT;
-    LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
-    FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
-    g_pUnloadStartEvent->Set();
-}
-
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_MODE_COOPERATIVE;
+    STATIC_CONTRACT_GC_TRIGGERS;
 
-void SystemDomain::ClearCollectedDomains()
-{
-    CONTRACTL
     {
-        GC_TRIGGERS;
-        NOTHROW;
-        MODE_COOPERATIVE;
+        // If finalizer thread is blocked because scheduler is running another task,
+        // or it is waiting for another thread, we first see if we get finalizer thread
+        // running again.
+        Thread::ThreadAbortWatchDog();
     }
-    CONTRACTL_END;
-        
-    AppDomain* pDomainsToClear=NULL;
+
+    EX_TRY
     {
-        CrstHolder lh(&m_DelayedUnloadCrst); 
-        for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
+        Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
+        EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
+        switch (action)
         {
-            if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
+        case eAbortThread:
+            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
+            pFinalizerThread->UserAbort(Thread::TAR_Thread,
+                                        EEPolicy::TA_Safe,
+                                        INFINITE,
+                                        Thread::UAC_FinalizerTimeout);
+            break;
+        case eRudeAbortThread:
+            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
+            pFinalizerThread->UserAbort(Thread::TAR_Thread,
+                                        EEPolicy::TA_Rude,
+                                        INFINITE,
+                                        Thread::UAC_FinalizerTimeout);
+            break;
+        case eUnloadAppDomain:
             {
-                AppDomain* pAppDomain=*ppDomain;
-                *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
-                pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
-                pDomainsToClear=pAppDomain;
+                AppDomain *pDomain = pFinalizerThread->GetDomain();
+                pFinalizerThread->UserAbort(Thread::TAR_Thread,
+                                            EEPolicy::TA_Safe,
+                                            INFINITE,
+                                            Thread::UAC_FinalizerTimeout);
             }
-            else
-                ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
+            break;
+        case eRudeUnloadAppDomain:
+            {
+                AppDomain *pDomain = pFinalizerThread->GetDomain();
+                pFinalizerThread->UserAbort(Thread::TAR_Thread,
+                                            EEPolicy::TA_Rude,
+                                            INFINITE,
+                                            Thread::UAC_FinalizerTimeout);
+            }
+            break;
+        case eExitProcess:
+        case eFastExitProcess:
+        case eRudeExitProcess:
+        case eDisableRuntime:
+            GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
+            EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
+            _ASSERTE (!"Should not get here");
+            break;
+        default:
+            break;
         }
     }
-        
-    for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
+    EX_CATCH
     {
-        AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
-        pDomain->Close(); //NOTHROW!
-        pDomain->Release();
-        pDomain=pNext;
     }
+    EX_END_CATCH(SwallowAllExceptions);
 }
-void SystemDomain::ProcessClearingDomains()
+
+enum WorkType
 {
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;           
-    }
-    CONTRACTL_END;
-    CrstHolder lh(&m_DelayedUnloadCrst); 
+    WT_UnloadDomain = 0x1,
+    WT_ThreadAbort = 0x2,
+    WT_FinalizerThread = 0x4
+};
 
-    for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
-    {
-        if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
-        {
-            AppDomain* pAppDomain=*ppDomain;
-            pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
-        }
-        ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
-    }
-        
-    if (!m_UnloadIsAsync)
-    {
-        // For synchronous mode, we are now done with the list.
-        m_pDelayedUnloadList = NULL;    
-    }
-}
+static Volatile<DWORD> s_WorkType = 0;
 
-void SystemDomain::ProcessDelayedUnloadDomains()
+void SystemDomain::ProcessDelayedUnloadLoaderAllocators()
 {
     CONTRACTL
     {
@@ -10626,25 +9034,11 @@ void SystemDomain::ProcessDelayedUnloadDomains()
     if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
         iGCRefPoint--;
 
-    BOOL bAppDomainToCleanup = FALSE;
     LoaderAllocator * pAllocatorsToDelete = NULL;
 
     {
         CrstHolder lh(&m_DelayedUnloadCrst); 
 
-        for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
-        {
-            if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
-            {
-                // Compare with 0 to handle overflows gracefully
-                if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
-                {
-                    bAppDomainToCleanup=TRUE;
-                    pDomain->SetStage(AppDomain::STAGE_COLLECTED);
-                }
-            }
-        }
-
         LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
         while (*ppAllocator!= NULL)
         {
@@ -10663,9 +9057,6 @@ void SystemDomain::ProcessDelayedUnloadDomains()
         }
     }
 
-    if (bAppDomainToCleanup)
-        AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
-
     // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of 
     // there is not guaranteed to be one, and it is not that expensive operation anyway.
     while (pAllocatorsToDelete != NULL)
@@ -10678,159 +9069,6 @@ void SystemDomain::ProcessDelayedUnloadDomains()
 
 #endif // CROSSGEN_COMPILE
 
-AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
-{
-    WRAPPER_NO_CONTRACT;
-    ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
-#ifdef _DEBUG
-    m_bAcquired=false;   
-    m_bChecked=false;
-    m_type=synctype;
-    
-#endif
-    Assign(adId, bUnsafePoint);
-}
-
-AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
-{
-    LIMITED_METHOD_CONTRACT;
-    ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
-    m_pDomain=NULL;
-#ifdef _DEBUG
-    m_bAcquired=false;
-    m_bChecked=false;
-    m_type=synctype;
-#endif
-}
-
-#ifndef CROSSGEN_COMPILE
-void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_NOTRIGGER;
-        PRECONDITION(CheckPointer(this));
-        PRECONDITION(m_UnloadCompleteEvent.IsValid());
-    }
-    CONTRACTL_END;
-
-    //pException is unused;
-    m_UnloadResult=hr;
-    m_UnloadCompleteEvent.Set();
-};
-
-void ADUnloadSink::WaitUnloadCompletion()
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        PRECONDITION(CheckPointer(this));
-        PRECONDITION(m_UnloadCompleteEvent.IsValid());
-    }
-    CONTRACTL_END;
-
-    CONTRACT_VIOLATION(FaultViolation);
-    m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
-};
-
-ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_NOTRIGGER;
-        PRECONDITION(SystemDomain::IsUnderDomainLock());
-        FORBID_FAULT;
-    }
-    CONTRACTL_END;
-
-    ADUnloadSink* pADSink=GetADUnloadSink();
-    PREFIX_ASSUME(pADSink!=NULL);
-    if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
-    {
-        pADSink->Reset();
-        SetUnloadRequestThread(GetThread());
-    }
-    return pADSink;
-};
-
-ADUnloadSink::ADUnloadSink()
-{
-    CONTRACTL
-    {
-        CONSTRUCTOR_CHECK;
-        THROWS;
-        GC_NOTRIGGER;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM(););
-    }
-    CONTRACTL_END;
-
-    m_cRef=1;
-    m_UnloadCompleteEvent.CreateManualEvent(FALSE);
-    m_UnloadResult=S_OK;
-};
-
-ADUnloadSink::~ADUnloadSink()
-{
-    CONTRACTL
-    {
-        DESTRUCTOR_CHECK;
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-    m_UnloadCompleteEvent.CloseEvent();
-
-};
-
-
-ULONG ADUnloadSink::AddRef()
-{
-    LIMITED_METHOD_CONTRACT;
-    return InterlockedIncrement(&m_cRef);
-};
-
-ULONG ADUnloadSink::Release()
-{
-    LIMITED_METHOD_CONTRACT;
-    ULONG ulRef = InterlockedDecrement(&m_cRef);
-    if (ulRef == 0)
-    {
-        delete this;
-    }
-    return ulRef;
-};
-
-void ADUnloadSink::Reset()
-{
-    LIMITED_METHOD_CONTRACT;
-    m_UnloadResult=S_OK;
-    m_UnloadCompleteEvent.Reset();
-}
-
-ADUnloadSink* AppDomain::GetADUnloadSink()
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE(SystemDomain::IsUnderDomainLock());
-    if(m_ADUnloadSink)
-        m_ADUnloadSink->AddRef();
-    return m_ADUnloadSink;
-};
-
-ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
-{
-    // unload thread only. Doesn't need to have AD lock
-    LIMITED_METHOD_CONTRACT;
-    if(m_ADUnloadSink)
-        m_ADUnloadSink->AddRef();
-    return m_ADUnloadSink;
-}
-#endif // CROSSGEN_COMPILE
-
 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
 {
     CONTRACT_VOID
index eb28f3a..5ffc1b2 100644 (file)
@@ -1230,8 +1230,6 @@ public:
     STRINGREF *IsStringInterned(STRINGREF *pString);
     STRINGREF *GetOrInternString(STRINGREF *pString);
 
-    virtual BOOL CanUnload()   { LIMITED_METHOD_CONTRACT; return FALSE; }    // can never unload BaseDomain
-
     // Returns an array of OBJECTREF* that can be used to store domain specific data.
     // Statics and reflection info (Types, MemberInfo,..) are stored this way
     // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation
@@ -1587,35 +1585,6 @@ enum
     ATTACH_ALL = 0x7
 };
 
-class ADUnloadSink
-{
-    
-protected:
-    ~ADUnloadSink();
-    CLREvent m_UnloadCompleteEvent;
-    HRESULT   m_UnloadResult;
-    Volatile<LONG> m_cRef;
-public:
-    ADUnloadSink();
-    void ReportUnloadResult (HRESULT hr, OBJECTREF* pException);
-    void WaitUnloadCompletion();
-    HRESULT GetUnloadResult() {LIMITED_METHOD_CONTRACT; return m_UnloadResult;};
-    void Reset();
-    ULONG AddRef();
-    ULONG Release();
-};
-
-
-FORCEINLINE void ADUnloadSink__Release(ADUnloadSink* pADSink)
-{
-    WRAPPER_NO_CONTRACT;
-
-    if (pADSink)
-        pADSink->Release();
-}
-
-typedef Wrapper <ADUnloadSink*,DoNothing,ADUnloadSink__Release,NULL> ADUnloadSinkHolder;
-
 // This filters the output of IterateAssemblies. This ought to be declared more locally
 // but it would result in really verbose callsites.
 //
@@ -1957,7 +1926,6 @@ template <class AppDomainType> class AppDomainCreationHolder;
 // 
 class AppDomain : public BaseDomain
 {
-    friend class ADUnloadSink;
     friend class SystemDomain;
     friend class AssemblySink;
     friend class AppDomainNative;
@@ -1968,7 +1936,6 @@ class AppDomain : public BaseDomain
     friend class RCWCache;
     friend class ClrDataAccess;
     friend class CheckAsmOffsets;
-    friend class AppDomainFromIDHolder;
 
     VPTR_VTABLE_CLASS(AppDomain, BaseDomain)
 
@@ -1977,7 +1944,6 @@ public:
     AppDomain();
     virtual ~AppDomain();
 #endif
-    static void DoADUnloadWork();
     DomainAssembly* FindDomainAssembly(Assembly*);
     void EnterContext(Thread* pThread, Context* pCtx,ContextTransitionFrame *pFrame);
 
@@ -1992,10 +1958,6 @@ public:
     // Initializes an AppDomain. (this functions is not called from the SystemDomain)
     void Init();
 
-    // creates only unamaged part
-    static void CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& result);
-
-
 #if defined(FEATURE_COMINTEROP)
     HRESULT SetWinrtApplicationContext(SString &appLocalWinMD);
 #endif // FEATURE_COMINTEROP
@@ -2591,8 +2553,6 @@ public:
 
     void SetupSharedStatics();
 
-    ADUnloadSink* PrepareForWaitUnloadCompletion();
-
     //****************************************************************************************
     //
     // Create a quick lookup for classes loaded into this domain based on their GUID.
@@ -2844,20 +2804,6 @@ public:
         return dac_cast<PTR_CompilationDomain>(this);
     }
 
-    void SetCanUnload()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        m_dwFlags |= APP_DOMAIN_CAN_BE_UNLOADED;
-    }
-
-    BOOL CanUnload()
-    {
-        LIMITED_METHOD_CONTRACT;
-        STATIC_CONTRACT_SO_TOLERANT;
-        return m_dwFlags & APP_DOMAIN_CAN_BE_UNLOADED;
-    }
-
     void SetRemotingConfigured()
     {
         LIMITED_METHOD_CONTRACT;
@@ -2886,14 +2832,6 @@ public:
         return m_dwFlags & ORPHANED_LOCKS;
     }
 
-    // This function is used to relax asserts in the lock accounting.
-    // It returns true if we are fine with hosed lock accounting in this domain.
-    BOOL OkToIgnoreOrphanedLocks()
-    {
-        WRAPPER_NO_CONTRACT;
-        return HasOrphanedLocks() && m_Stage >= STAGE_UNLOAD_REQUESTED;
-    }
-
     static void ExceptionUnwind(Frame *pFrame);
 
 #ifdef _DEBUG
@@ -2974,7 +2912,7 @@ public:
     BOOL CanLoadCode()
     {
         LIMITED_METHOD_CONTRACT;
-        return m_Stage >= STAGE_READYFORMANAGEDCODE && m_Stage < STAGE_CLOSED;        
+        return m_Stage >= STAGE_READYFORMANAGEDCODE;
     }
 
     void SetAnonymouslyHostedDynamicMethodsAssembly(DomainAssembly * pDomainAssembly)
@@ -2991,11 +2929,6 @@ public:
         return m_anonymouslyHostedDynamicMethodsAssembly;
     }
 
-    BOOL HasUnloadStarted()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_Stage>=STAGE_EXITED;
-    }
     static void RefTakerAcquire(AppDomain* pDomain)
     {
         WRAPPER_NO_CONTRACT;
@@ -3052,7 +2985,7 @@ public:
     {
         LIMITED_METHOD_DAC_CONTRACT;
 
-        return m_Stage >= STAGE_ACTIVE && m_Stage < STAGE_CLOSED;
+        return m_Stage >= STAGE_ACTIVE;
     }
     // Range for normal execution of code in the appdomain, currently used for
     // appdomain resource monitoring since we don't care to update resource usage
@@ -3073,7 +3006,7 @@ public:
         // There is no risk of races under DAC, so we will pretend to be unconditionally valid.
         return TRUE;
 #else
-        return m_Stage > STAGE_CREATING && m_Stage < STAGE_CLOSED;
+        return m_Stage > STAGE_CREATING;
 #endif
     }
 
@@ -3103,14 +3036,6 @@ public:
 #endif
     BOOL IsRunningIn(Thread* pThread);
 
-    BOOL IsUnloading()
-    {
-        LIMITED_METHOD_CONTRACT;
-        SUPPORTS_DAC;
-
-        return m_Stage > STAGE_UNLOAD_REQUESTED;
-    }
-
     BOOL NotReadyForManagedCode()
     {
         LIMITED_METHOD_CONTRACT;
@@ -3118,67 +3043,6 @@ public:
         return m_Stage < STAGE_READYFORMANAGEDCODE;
     }
 
-    void SetFinalized()
-    {
-        LIMITED_METHOD_CONTRACT;
-        SetStage(STAGE_FINALIZED);
-    }
-
-    BOOL IsFinalizing()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return m_Stage >= STAGE_FINALIZING;
-    }
-
-    BOOL IsFinalized()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return m_Stage >= STAGE_FINALIZED;
-    }
-
-    BOOL NoAccessToHandleTable()
-    {
-        LIMITED_METHOD_CONTRACT;
-        SUPPORTS_DAC;
-
-        return m_Stage >= STAGE_HANDLETABLE_NOACCESS;
-    }
-
-    // Checks whether the given thread can enter the app domain
-    BOOL CanThreadEnter(Thread *pThread);
-
-    // Following two are needed for the Holder
-    static void SetUnloadInProgress(AppDomain *pThis) PUB;
-    static void SetUnloadComplete(AppDomain *pThis) PUB;
-    // Predicates for GC asserts
-    BOOL ShouldHaveFinalization()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return ((DWORD) m_Stage) < STAGE_COLLECTED;
-    }
-    BOOL ShouldHaveCode()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return ((DWORD) m_Stage) < STAGE_COLLECTED;
-    }
-    BOOL ShouldHaveRoots()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return ((DWORD) m_Stage) < STAGE_CLEARED;
-    }
-    BOOL ShouldHaveInstances()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return ((DWORD) m_Stage) < STAGE_COLLECTED;
-    }
-
-
     static void RaiseExitProcessEvent();
     Assembly* RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName);
     DomainAssembly* RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef);
@@ -3376,20 +3240,7 @@ private:
 
     friend class DomainAssembly;
 
-public:
-    static void ProcessUnloadDomainEventOnFinalizeThread();
-    static BOOL HasWorkForFinalizerThread()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return s_pAppDomainToRaiseUnloadEvent != NULL;
-    }
-
 private:
-    static AppDomain* s_pAppDomainToRaiseUnloadEvent;
-    static BOOL s_fProcessUnloadDomainEvent;
-
-    void RaiseUnloadDomainEvent();
-    static void RaiseUnloadDomainEvent_Wrapper(LPVOID /* AppDomain * */);
 
     BOOL RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating);
     BOOL HasUnhandledExceptionEventHandler();
@@ -3406,25 +3257,24 @@ private:
     };
 
 
-    static void AllowThreadEntrance(AppDomain *pApp);
-    static void RestrictThreadEntrance(AppDomain *pApp);
-
-    typedef Holder<AppDomain*,DoNothing<AppDomain*>,AppDomain::AllowThreadEntrance,NULL> RestrictEnterHolder;
-    
     enum Stage {
         STAGE_CREATING,
         STAGE_READYFORMANAGEDCODE,
         STAGE_ACTIVE,
         STAGE_OPEN,
-        STAGE_UNLOAD_REQUESTED,
-        STAGE_EXITING,
-        STAGE_EXITED,
-        STAGE_FINALIZING,
-        STAGE_FINALIZED,
-        STAGE_HANDLETABLE_NOACCESS,
-        STAGE_CLEARED,
-        STAGE_COLLECTED,
-        STAGE_CLOSED
+        // Don't delete the following *_DONOTUSE members and in case a new member needs to be added,
+        // add it at the end. The reason is that debugger stuff has its own copy of this enum and 
+        // it can use the members that are marked as *_DONOTUSE here when debugging older version 
+        // of the runtime.
+        STAGE_UNLOAD_REQUESTED_DONOTUSE,
+        STAGE_EXITING_DONOTUSE,
+        STAGE_EXITED_DONOTUSE,
+        STAGE_FINALIZING_DONOTUSE,
+        STAGE_FINALIZED_DONOTUSE,
+        STAGE_HANDLETABLE_NOACCESS_DONOTUSE,
+        STAGE_CLEARED_DONOTUSE,
+        STAGE_COLLECTED_DONOTUSE,
+        STAGE_CLOSED_DONOTUSE
     };
     void SetStage(Stage stage)
     {
@@ -3442,22 +3292,12 @@ private:
         while (lastStage !=stage) 
             lastStage = (Stage)FastInterlockCompareExchange((LONG*)&m_Stage,stage,lastStage);
     };
-    void Exit(BOOL fRunFinalizers, BOOL fAsyncExit);
-    void Close();
     void ClearGCRoots();
-    void ClearGCHandles();
     void UnwindThreads();
     // Return TRUE if EE is stopped
     // Return FALSE if more work is needed
     BOOL StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread);
 
-    // Use Rude Abort to unload the domain.
-    BOOL m_fRudeUnload;
-
-    Thread *m_pUnloadRequestThread;
-    ADUnloadSink*   m_ADUnloadSink;
-    BOOL  m_bForceGCOnUnload;
-    BOOL  m_bUnloadingFromUnloadEvent;
     AppDomainLoaderAllocator m_LoaderAllocator;
 
     // List of unloaded LoaderAllocators, protected by code:GetLoaderAllocatorReferencesLock (for now)
@@ -3468,53 +3308,6 @@ public:
     // Register the loader allocator for deletion in code:ShutdownFreeLoaderAllocators.
     void RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator);
     
-    AppDomain * m_pNextInDelayedUnloadList;
-    
-    void SetForceGCOnUnload(BOOL bSet)
-    {
-        m_bForceGCOnUnload=bSet;
-    }
-
-    void SetUnloadingFromUnloadEvent()
-    {
-        m_bUnloadingFromUnloadEvent=TRUE;
-    }
-
-    BOOL IsUnloadingFromUnloadEvent()
-    {
-        return m_bUnloadingFromUnloadEvent;
-    }
-    
-    void SetRudeUnload()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        m_fRudeUnload = TRUE;
-    }
-
-    BOOL IsRudeUnload()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return m_fRudeUnload;
-    }
-
-    ADUnloadSink* GetADUnloadSink();
-    ADUnloadSink* GetADUnloadSinkForUnload();
-    void SetUnloadRequestThread(Thread *pThread)
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        m_pUnloadRequestThread = pThread;
-    }
-
-    Thread *GetUnloadRequestThread()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return m_pUnloadRequestThread;
-    }
-
 public:
     void SetGCRefPoint(int gccounter)
     {
@@ -3538,17 +3331,9 @@ public:
     
     void AddMemoryPressure();
     void RemoveMemoryPressure();
-    void Unload(BOOL fForceUnload);
-    static HRESULT UnloadById(ADID Id, BOOL fSync, BOOL fExceptionsPassThrough=FALSE);
-    static HRESULT UnloadWait(ADID Id, ADUnloadSink* pSink);
-#ifdef FEATURE_TESTHOOKS        
-    static HRESULT UnloadWaitNoCatch(ADID Id, ADUnloadSink* pSink);
-#endif
-    static void ResetUnloadRequestThread(ADID Id);
 
     void UnlinkClass(MethodTable *pMT);
 
-    typedef Holder<AppDomain *, AppDomain::SetUnloadInProgress, AppDomain::SetUnloadComplete> UnloadHolder;
     Assembly *GetRootAssembly()
     {
         LIMITED_METHOD_CONTRACT;
@@ -3745,7 +3530,6 @@ public:
         LOAD_SYSTEM_ASSEMBLY_EVENT_SENT =   0x0040,
         REMOTING_CONFIGURED_FOR_DOMAIN =    0x0100,
         COMPILATION_DOMAIN =                0x0400, // Are we ngenning?
-        APP_DOMAIN_CAN_BE_UNLOADED =        0x0800, // if need extra bits, can derive this at runtime
         ORPHANED_LOCKS =                    0x1000, // Orphaned locks exist in this appdomain.
         PASSIVE_DOMAIN =                    0x2000, // Can we execute code in this AppDomain
         VERIFICATION_DOMAIN =               0x4000, // This is a verification domain
@@ -3764,30 +3548,8 @@ public:
     ArrayList m_NativeDllSearchDirectories;
     BOOL m_ReversePInvokeCanEnter;
     bool m_ForceTrivialWaitOperations;
-    // Section to support AD unload due to escalation
-public:
-    static void CreateADUnloadWorker();
-
-    static void CreateADUnloadStartEvent();
-
-    static DWORD WINAPI ADUnloadThreadStart(void *args);
 
-    // Default is safe unload with test hook
-    void EnableADUnloadWorker();
-
-    // If called to handle stack overflow, we can not set event, since the thread has limit stack.
-    void EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack = TRUE);
-
-    static void EnableADUnloadWorkerForThreadAbort();
-    static void EnableADUnloadWorkerForFinalizer();
-    static void EnableADUnloadWorkerForCollectedADCleanup();
-
-    BOOL IsUnloadRequested()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        return (m_Stage == STAGE_UNLOAD_REQUESTED);
-    }
+public:
 
     BOOL IsImageFromTrustedPath(PEImage* pImage);
 
@@ -3800,8 +3562,6 @@ public:
 #endif
 
     private:
-    static void ADUnloadWorkerHelper(AppDomain *pDomain);
-    static CLREvent * g_pUnloadStartEvent;
 
 #ifdef DACCESS_COMPILE
 public:
@@ -4070,50 +3830,6 @@ typedef Wrapper<AppDomain*,AppDomain::RefTakerAcquire,AppDomain::RefTakerRelease
 // Just a ref holder
 typedef ReleaseHolder<AppDomain> AppDomainRefHolder;
 
-// This class provides a way to access AppDomain by ID
-// without risking the appdomain getting invalid in the process
-class AppDomainFromIDHolder
-{
-public:
-    enum SyncType  
-    {
-        SyncType_GC,     // Prevents AD from being unloaded by forbidding GC for the lifetime of the object
-        SyncType_ADLock  // Prevents AD from being unloaded by requiring ownership of DomainLock for the lifetime of the object
-    };
-protected:    
-    AppDomain* m_pDomain;
-#ifdef _DEBUG    
-    BOOL       m_bAcquired;
-    BOOL       m_bChecked;
-    SyncType   m_type;
-#endif
-public:
-    DEBUG_NOINLINE AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype=SyncType_GC);
-    DEBUG_NOINLINE AppDomainFromIDHolder(SyncType synctype=SyncType_GC);
-    DEBUG_NOINLINE ~AppDomainFromIDHolder();
-
-       void* GetAddress() { return m_pDomain; }        // Used to get an identfier for ETW
-    void Assign(ADID adId, BOOL bUnsafePoint);
-    void ThrowIfUnloaded();
-    void Release();
-    BOOL IsUnloaded() 
-    {
-        LIMITED_METHOD_CONTRACT;
-#ifdef _DEBUG
-        m_bChecked=TRUE; 
-        if (m_pDomain==NULL)
-        {
-            // no need to enforce anything
-            Release(); 
-        }
-#endif
-        return m_pDomain==NULL;
-    };
-    AppDomain* operator->();
-};  // class AppDomainFromIDHolder
-
-
-
 typedef VPTR(class SystemDomain) PTR_SystemDomain;
 
 class SystemDomain : public BaseDomain
@@ -4122,7 +3838,6 @@ class SystemDomain : public BaseDomain
     friend class AppDomainIterator;
     friend class UnsafeAppDomainIterator;
     friend class ClrDataAccess;
-    friend class AppDomainFromIDHolder;
     friend Frame *Thread::IsRunningIn(AppDomain* pDomain, int *count);
 
     VPTR_VTABLE_CLASS(SystemDomain, BaseDomain)
@@ -4280,15 +3995,6 @@ public:
     // Use an already exising & inited Application Domain (e.g. a subclass).
     static void LoadDomain(AppDomain     *pDomain);
 
-#ifndef DACCESS_COMPILE
-    static void MakeUnloadable(AppDomain* pApp)
-    {
-        WRAPPER_NO_CONTRACT;
-        System()->AddDomain(pApp);
-        pApp->SetCanUnload();
-    }
-#endif // DACCESS_COMPILE
-
     //****************************************************************************************
     // Methods used to get the callers module and hence assembly and app domain.
     __declspec(deprecated("This method is deprecated, use the version that takes a StackCrawlMark instead"))
@@ -4403,31 +4109,7 @@ public:
     DWORD RequireAppDomainCleanup()
     {
         LIMITED_METHOD_CONTRACT;
-        return m_pDelayedUnloadList != 0 || m_pDelayedUnloadListOfLoaderAllocators != 0;
-    }
-
-    void AddToDelayedUnloadList(AppDomain* pDomain, BOOL bAsync)
-    {
-        CONTRACTL
-        {
-            NOTHROW;
-            GC_NOTRIGGER;
-            MODE_COOPERATIVE;
-        }
-        CONTRACTL_END;
-        m_UnloadIsAsync = bAsync;
-        
-        CrstHolder lh(&m_DelayedUnloadCrst);
-        pDomain->m_pNextInDelayedUnloadList=m_pDelayedUnloadList;
-        m_pDelayedUnloadList=pDomain;
-        if (m_UnloadIsAsync)
-        {
-            pDomain->AddRef();
-            int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
-            if (GCHeapUtilities::IsGCInProgress())
-                iGCRefPoint++;
-            pDomain->SetGCRefPoint(iGCRefPoint);
-        }
+        return m_pDelayedUnloadListOfLoaderAllocators != 0;
     }
 
     void AddToDelayedUnloadList(LoaderAllocator * pAllocator)
@@ -4450,74 +4132,8 @@ public:
         pAllocator->SetGCRefPoint(iGCRefPoint);
     }
 
-    void ClearCollectedDomains();
-    void ProcessClearingDomains();
-    void ProcessDelayedUnloadDomains();
+    void ProcessDelayedUnloadLoaderAllocators();
     
-    static void SetUnloadInProgress(AppDomain *pDomain)
-    {
-        WRAPPER_NO_CONTRACT;
-
-        _ASSERTE(m_pAppDomainBeingUnloaded == NULL);
-        m_pAppDomainBeingUnloaded = pDomain;
-        m_dwIndexOfAppDomainBeingUnloaded = pDomain->GetIndex();
-    }
-
-    static void SetUnloadDomainCleared()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        // about to delete, so clear this pointer so nobody uses it
-        m_pAppDomainBeingUnloaded = NULL;
-    }
-    static void SetUnloadComplete()
-    {
-        LIMITED_METHOD_CONTRACT;
-
-        // should have already cleared the AppDomain* prior to delete
-        // either we succesfully unloaded and cleared or we failed and restored the ID
-        _ASSERTE(m_pAppDomainBeingUnloaded == NULL && m_dwIndexOfAppDomainBeingUnloaded.m_dwIndex != 0
-            || m_pAppDomainBeingUnloaded && SystemDomain::GetAppDomainAtId(m_pAppDomainBeingUnloaded->GetId()) != NULL);
-        m_pAppDomainBeingUnloaded = NULL;
-        m_pAppDomainUnloadingThread = NULL;
-    }
-
-    static AppDomain *AppDomainBeingUnloaded()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_pAppDomainBeingUnloaded;
-    }
-
-    static ADIndex IndexOfAppDomainBeingUnloaded()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_dwIndexOfAppDomainBeingUnloaded;
-    }
-
-    static void SetUnloadRequestingThread(Thread *pRequestingThread)
-    {
-        LIMITED_METHOD_CONTRACT;
-        m_pAppDomainUnloadRequestingThread = pRequestingThread;
-    }
-
-    static Thread *GetUnloadRequestingThread()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_pAppDomainUnloadRequestingThread;
-    }
-
-    static void SetUnloadingThread(Thread *pUnloadingThread)
-    {
-        LIMITED_METHOD_CONTRACT;
-        m_pAppDomainUnloadingThread = pUnloadingThread;
-    }
-
-    static Thread *GetUnloadingThread()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_pAppDomainUnloadingThread;
-    }
-
     static void EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc);
 
 #endif // DACCESS_COMPILE
@@ -4620,9 +4236,7 @@ private:
         STANDARD_VM_CONTRACT;
 
         m_pDefaultDomain = NULL;
-        m_pDelayedUnloadList=NULL;
         m_pDelayedUnloadListOfLoaderAllocators=NULL;
-        m_UnloadIsAsync = FALSE;
 
         m_GlobalAllocator.Init(this);
     }
@@ -4650,9 +4264,6 @@ private:
     // Global domain that every one uses
     SPTR_DECL(SystemDomain, m_pSystemDomain);
 
-    AppDomain* m_pDelayedUnloadList;
-    BOOL m_UnloadIsAsync;
-
     LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
 
 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
@@ -4668,20 +4279,6 @@ private:
 
     static ArrayListStatic  m_appDomainIdList;
 
-    // only one ad can be unloaded at a time
-    static AppDomain*   m_pAppDomainBeingUnloaded;
-    // need this so can determine AD being unloaded after it has been deleted
-    static ADIndex      m_dwIndexOfAppDomainBeingUnloaded;
-
-    // if had to spin off a separate thread to do the unload, this is the original thread.
-    // allows us to delay aborting it until it's the last one so that it can receive
-    // notification of an unload failure
-    static Thread *m_pAppDomainUnloadRequestingThread;
-
-    // this is the thread doing the actual unload. He's allowed to enter the domain
-    // even if have started unloading.
-    static Thread *m_pAppDomainUnloadingThread;
-
     static GlobalStringLiteralMap *m_pGlobalStringLiteralMap;
 
     static ULONG       s_dNumAppDomains;  // Maintain a count of children app domains.
@@ -5082,17 +4679,6 @@ protected:
         {
             m_pDomain->Release();
         }
-        else
-        {
-            STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Unload domain during creation [%d] %p\n", m_pDomain->GetId().m_dwId, m_pDomain);
-            SystemDomain::MakeUnloadable(m_pDomain);
-#ifdef _DEBUG
-            DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
-            m_pDomain->EnableADUnloadWorker(hostTestADUnload != 2?EEPolicy::ADU_Safe:EEPolicy::ADU_Rude);
-#else
-            m_pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-#endif
-        }
     };
     
 public:
index 7fb4a95..37fb501 100644 (file)
 
 #include "appdomain.hpp"
 
-inline void AppDomain::SetUnloadInProgress(AppDomain *pThis)
-{
-    WRAPPER_NO_CONTRACT;
-
-    SystemDomain::System()->SetUnloadInProgress(pThis);
-}
-
-inline void AppDomain::SetUnloadComplete(AppDomain *pThis)
-{
-    GCX_COOP();
-
-    SystemDomain::System()->SetUnloadComplete();
-}
-
 inline  void AppDomain::EnterContext(Thread* pThread, Context* pCtx,ContextTransitionFrame *pFrame)
 {
     CONTRACTL
@@ -48,118 +34,6 @@ inline  void AppDomain::EnterContext(Thread* pThread, Context* pCtx,ContextTrans
     pThread->EnterContextRestricted(pCtx,pFrame);
 };
 
-
-inline AppDomainFromIDHolder::~AppDomainFromIDHolder()
-{
-    WRAPPER_NO_CONTRACT;
-#ifdef _DEBUG
-    if(m_bAcquired)
-        Release();
-#endif    
-}
-
-inline void AppDomainFromIDHolder::Release()
-{
-    //do not use real contract here!
-    WRAPPER_NO_CONTRACT;
-#ifdef _DEBUG
-    if(m_bAcquired)
-    {
-        if (m_type==SyncType_GC)
-#ifdef ENABLE_CONTRACTS_IMPL
-        {
-            if (GetThread())
-            {
-                STRESS_LOG1(LF_APPDOMAIN, LL_INFO10000, "AppDomainFromIDHolder::Assign is allowing GC - %08x",this);
-                GetThread()->EndForbidGC();
-            }
-            else
-            {
-                if (!IsGCThread())
-                {
-                    _ASSERTE(!"Should not be called from a non GC thread");
-                }
-            }
-        }
-#else
-            m_pDomain=NULL;
-#endif
-        else
-        if (m_type==SyncType_ADLock)
-            SystemDomain::m_SystemDomainCrst.SetCantLeave(FALSE);
-        else
-        {
-            _ASSERTE(!"Unknown type");        
-        }
-        m_pDomain=NULL;
-        m_bAcquired=FALSE;
-    }
-#endif
-}
-
-inline void AppDomainFromIDHolder::Assign(ADID id, BOOL bUnsafePoint)
-{
-    //do not use real contract here!
-    WRAPPER_NO_CONTRACT;
-    TESTHOOKCALL(AppDomainCanBeUnloaded(id.m_dwId, bUnsafePoint));
-#ifdef _DEBUG
-    m_bChecked=FALSE;
-    if (m_type==SyncType_GC)
-    {
-#ifdef ENABLE_CONTRACTS_IMPL
-        if (GetThread())
-        {
-            _ASSERTE(GetThread()->PreemptiveGCDisabled());
-            STRESS_LOG1(LF_APPDOMAIN, LL_INFO10000, "AppDomainFromIDHolder::Assign is forbidding GC - %08x",this);
-            GetThread()->BeginForbidGC(__FILE__, __LINE__);
-        }
-        else
-        {
-            if (!IsGCThread())
-            {
-                _ASSERTE(!"Should not be called from a non GC thread");
-            }
-        }
-#endif
-    }
-    else
-    if (m_type==SyncType_ADLock)    
-    {
-        _ASSERTE(SystemDomain::m_SystemDomainCrst.OwnedByCurrentThread());
-        SystemDomain::m_SystemDomainCrst.SetCantLeave(TRUE);
-    }
-    else
-    {
-        _ASSERT(!"NI");
-    }
-
-    m_bAcquired=TRUE;
- #endif
-    m_pDomain=SystemDomain::GetAppDomainAtId(id);
-
-}
-
-
-
-inline void AppDomainFromIDHolder::ThrowIfUnloaded()
-{
-    STATIC_CONTRACT_THROWS;
-    if (IsUnloaded())
-    {
-        COMPlusThrow(kAppDomainUnloadedException);
-    }
-#ifdef _DEBUG
-    m_bChecked=TRUE;
-#endif
-}
-
-inline AppDomain* AppDomainFromIDHolder::operator ->()
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE(m_bChecked && m_bAcquired);    
-    return m_pDomain;
-}
-
 inline DomainAssembly* AppDomain::FindDomainAssembly(Assembly* assembly)
 {
     CONTRACTL
index 713856f..3b2a538 100644 (file)
@@ -302,34 +302,6 @@ FCIMPL2(Object*, AppDomainNative::GetAssemblies, AppDomainBaseObject* refThisUNS
 } // AppDomainNative::GetAssemblies
 FCIMPLEND
 
-
-FCIMPL1(void, AppDomainNative::Unload, INT32 dwId)
-{
-    FCALL_CONTRACT;
-
-    HELPER_METHOD_FRAME_BEGIN_0();
-
-    IfFailThrow(AppDomain::UnloadById(ADID(dwId),TRUE));
-
-    HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-FCIMPL1(FC_BOOL_RET, AppDomainNative::IsDomainIdValid, INT32 dwId)
-{
-    FCALL_CONTRACT;
-
-    BOOL retVal = FALSE;
-    HELPER_METHOD_FRAME_BEGIN_RET_0()
-
-    AppDomainFromIDHolder ad((ADID)dwId, TRUE);
-    retVal=!ad.IsUnloaded();
-    HELPER_METHOD_FRAME_END();
-    FC_RETURN_BOOL(retVal);
-}
-FCIMPLEND
-
-
 FCIMPL1(INT32, AppDomainNative::GetId, AppDomainBaseObject* refThisUNSAFE)
 {
     FCALL_CONTRACT;
index 9728ef8..dc1b133 100644 (file)
@@ -28,11 +28,8 @@ public:
     static FCDECL2(Object*, GetOrInternString, AppDomainBaseObject* refThisUNSAFE, StringObject* pStringUNSAFE);
     static FCDECL1(void, CreateContext, AppDomainBaseObject *refThisUNSAFE);
     static void QCALLTYPE SetupBindingPaths(__in_z LPCWSTR wszTrustedPlatformAssemblies, __in_z LPCWSTR wszPlatformResourceRoots, __in_z LPCWSTR wszAppPaths, __in_z LPCWSTR wszAppNiPaths, __in_z LPCWSTR appLocalWinMD);
-    static FCDECL1(void, Unload, INT32 dwId);
     static FCDECL1(Object*, GetDynamicDir, AppDomainBaseObject* refThisUNSAFE);
     static FCDECL1(INT32, GetId, AppDomainBaseObject* refThisUNSAFE);
-    static FCDECL1(INT32, GetIdForUnload, AppDomainBaseObject* refDomainUNSAFE);
-    static FCDECL1(FC_BOOL_RET, IsDomainIdValid, INT32 dwId);
     static FCDECL1(void, ForceToSharedDomain, Object* pObjectUNSAFE);
     static FCDECL1(LPVOID,  GetFusionContext, AppDomainBaseObject* refThis);
     static FCDECL2(Object*, IsStringInterned, AppDomainBaseObject* refThis, StringObject* pString);
index 5af778b..c57c92a 100644 (file)
@@ -179,7 +179,7 @@ ASMCONSTANTS_C_ASSERT(Thread__m_pFrame == offsetof(Thread, m_pFrame));
 #define Thread_m_pFrame Thread__m_pFrame
 
 #ifndef CROSSGEN_COMPILE
-#define               Thread__m_pDomain                 0x14
+#define               Thread__m_pDomain                 0x10
 ASMCONSTANTS_C_ASSERT(Thread__m_pDomain == offsetof(Thread, m_pDomain));
 
 #define               AppDomain__m_dwId                 0x04
index 22ec7c1..feadaa8 100644 (file)
@@ -341,14 +341,7 @@ LOCAL_LABEL(UMThunkStub_HaveThread):
 
 LOCAL_LABEL(UMThunkStub_InCooperativeMode):
         ldr                 r12, [r7, #UMThunkStub_HiddenArgOffset]
-
-        ldr                 r0, [r5, #Thread__m_pDomain]
-        ldr                 r1, [r12, #UMEntryThunk__m_dwDomainId]
-        ldr                 r0, [r0, #AppDomain__m_dwId]
         ldr                 r3, [r12, #UMEntryThunk__m_pUMThunkMarshInfo]
-        cmp                 r0, r1
-        bne                 LOCAL_LABEL(UMThunkStub_WrongAppDomain)
-
         ldr                 r2, [r3, #UMThunkMarshInfo__m_cbActualArgSize]
         cbz                 r2, LOCAL_LABEL(UMThunkStub_ArgumentsSetup)
 
@@ -401,95 +394,8 @@ LOCAL_LABEL(UMThunkStub_DoTrapReturningThreads):
         add                 sp, #SIZEOF__FloatArgumentRegisters
         b                   LOCAL_LABEL(UMThunkStub_InCooperativeMode)
 
-LOCAL_LABEL(UMThunkStub_WrongAppDomain):
-        sub                 sp, #SIZEOF__FloatArgumentRegisters
-        vstm                sp, {d0-d7}
-
-        ldr                 r0, [r7, #UMThunkStub_HiddenArgOffset]  // UMEntryThunk* pUMEntry
-        mov                 r2, r7              // void * pArgs
-        // remaining arguments are unused
-        bl                  C_FUNC(UM2MDoADCallBack)
-
-        // Restore non-FP return value.
-        ldr                 r0, [r7, #0]
-        ldr                 r1, [r7, #4]
-
-        // Restore FP return value or HFA.
-        vldm                sp, {d0-d3}
-        b                   LOCAL_LABEL(UMThunkStub_PostCall)
-
         NESTED_END UMThunkStub,_TEXT
 
-// UM2MThunk_WrapperHelper(void *pThunkArgs,             // r0
-//                         int cbStackArgs,              // r1 (unused)
-//                         void *pAddr,                  // r2 (unused)
-//                         UMEntryThunk *pEntryThunk,    // r3
-//                         Thread *pThread)              // [sp, #0]
-
-        NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT, NoHandler
-
-        PROLOG_PUSH         "{r4-r7,r11,lr}"
-        PROLOG_STACK_SAVE_OFFSET   r7, #12
-
-        CHECK_STACK_ALIGNMENT
-
-        mov                 r12, r3                     // r12 = UMEntryThunk *
-
-        //
-        // Note that layout of the arguments is given by UMThunkStub frame
-        //
-        mov                 r5, r0                      // r5 = pArgs
-
-        ldr                 r3, [r12, #UMEntryThunk__m_pUMThunkMarshInfo]
-        
-        ldr                 r2, [r3, #UMThunkMarshInfo__m_cbActualArgSize]
-        cbz                 r2, LOCAL_LABEL(UM2MThunk_WrapperHelper_ArgumentsSetup)
-
-        add                 r0, r5, #UMThunkStub_StackArgsSize // Source pointer
-        add                 r0, r0, r2
-        lsr                 r1, r2, #2      // Count of stack slots to copy
-
-        and                 r2, r2, #4      // Align the stack
-        sub                 sp, sp, r2
-
-LOCAL_LABEL(UM2MThunk_WrapperHelper_StackLoop):
-        ldr                 r2, [r0,#-4]!
-        str                 r2, [sp,#-4]!
-        subs                r1, r1, #1
-        bne                 LOCAL_LABEL(UM2MThunk_WrapperHelper_StackLoop)
-
-LOCAL_LABEL(UM2MThunk_WrapperHelper_ArgumentsSetup):
-        ldr                 r4, [r3, #UMThunkMarshInfo__m_pILStub]
-
-        // reload floating point registers
-        sub                 r6, r5, #SIZEOF__FloatArgumentRegisters
-        vldm                r6, {d0-d7}
-
-        // reload argument registers
-        ldm                 r5, {r0-r3}
-
-        CHECK_STACK_ALIGNMENT
-
-        blx                 r4
-
-        // Save non-floating point return
-        str                 r0, [r5, #0]
-        str                 r1, [r5, #4]
-
-        // Save FP return value or HFA.
-        vstm                r6, {d0-d3}
-
-#ifdef _DEBUG
-        // trash the floating point registers to ensure that the HFA return values 
-        // won't survive by accident
-        vldm                sp, {d0-d3}
-#endif
-
-        EPILOG_STACK_RESTORE_OFFSET r7, #12
-        EPILOG_POP          "{r4-r7,r11,pc}"
-
-        NESTED_END UM2MThunk_WrapperHelper, _TEXT
-
 // ------------------------------------------------------------------
 
         NESTED_ENTRY ThePreStub, _TEXT, NoHandler
index 60def08..c0fef0c 100644 (file)
@@ -22,7 +22,6 @@
     IMPORT TheUMEntryPrestubWorker
     IMPORT CreateThreadBlockThrow
     IMPORT UMThunkStubRareDisableWorker
-    IMPORT UM2MDoADCallBack
     IMPORT PreStubWorker
     IMPORT PreStubGetMethodDescForCompactEntryPoint
     IMPORT NDirectImportWorker
@@ -404,13 +403,7 @@ UMThunkStub_HaveThread
 UMThunkStub_InCooperativeMode
         ldr                 r12, [r7, #UMThunkStub_HiddenArg]
 
-        ldr                 r0, [r5, #Thread__m_pDomain]
-        ldr                 r1, [r12, #UMEntryThunk__m_dwDomainId]
-        ldr                 r0, [r0, #AppDomain__m_dwId]
         ldr                 r3, [r12, #UMEntryThunk__m_pUMThunkMarshInfo]
-        cmp                 r0, r1
-        bne                 UMThunkStub_WrongAppDomain
-
         ldr                 r2, [r3, #UMThunkMarshInfo__m_cbActualArgSize]
         cbz                 r2, UMThunkStub_ArgumentsSetup
 
@@ -463,96 +456,8 @@ UMThunkStub_DoTrapReturningThreads
         add                 sp, #SIZEOF__FloatArgumentRegisters
         b                   UMThunkStub_InCooperativeMode
 
-UMThunkStub_WrongAppDomain
-        sub                 sp, #SIZEOF__FloatArgumentRegisters
-        vstm                sp, {d0-d7}
-
-        ldr                 r0, [r7, #UMThunkStub_HiddenArg]  ; UMEntryThunk* pUMEntry
-        mov                 r2, r7              ; void * pArgs
-        ; remaining arguments are unused
-        bl                  UM2MDoADCallBack
-
-        ; Restore non-FP return value.
-        ldr                 r0, [r7, #0]
-        ldr                 r1, [r7, #4]
-
-        ; Restore FP return value or HFA.
-        vldm                sp, {d0-d3}
-        b                   UMThunkStub_PostCall
-
-        NESTED_END
-
-; UM2MThunk_WrapperHelper(void *pThunkArgs,             // r0
-;                         int cbStackArgs,              // r1 (unused)
-;                         void *pAddr,                  // r2 (unused)
-;                         UMEntryThunk *pEntryThunk,    // r3
-;                         Thread *pThread)              // [sp, #0]
-
-        NESTED_ENTRY UM2MThunk_WrapperHelper
-
-        PROLOG_PUSH         {r4-r7,r11,lr}
-        PROLOG_STACK_SAVE   r7
-
-        CHECK_STACK_ALIGNMENT
-
-        mov                 r12, r3                     // r12 = UMEntryThunk *
-
-        ;
-        ; Note that layout of the arguments is given by UMThunkStub frame
-        ;
-        mov                 r5, r0                      // r5 = pArgs
-
-        ldr                 r3, [r12, #UMEntryThunk__m_pUMThunkMarshInfo]
-        
-        ldr                 r2, [r3, #UMThunkMarshInfo__m_cbActualArgSize]
-        cbz                 r2, UM2MThunk_WrapperHelper_ArgumentsSetup
-
-        add                 r0, r5, #UMThunkStub_StackArgs ; Source pointer
-        add                 r0, r0, r2
-        lsr                 r1, r2, #2      ; Count of stack slots to copy
-
-        and                 r2, r2, #4      ; Align the stack
-        sub                 sp, sp, r2
-
-UM2MThunk_WrapperHelper_StackLoop
-        ldr                 r2, [r0,#-4]!
-        str                 r2, [sp,#-4]!
-        subs                r1, r1, #1
-        bne                 UM2MThunk_WrapperHelper_StackLoop
-
-UM2MThunk_WrapperHelper_ArgumentsSetup
-        ldr                 r4, [r3, #UMThunkMarshInfo__m_pILStub]
-
-        ; reload floating point registers
-        sub                 r6, r5, #SIZEOF__FloatArgumentRegisters
-        vldm                r6, {d0-d7}
-
-        ; reload argument registers
-        ldm                 r5, {r0-r3}
-
-        CHECK_STACK_ALIGNMENT
-
-        blx                 r4
-
-        ; Save non-floating point return
-        str                 r0, [r5, #0]
-        str                 r1, [r5, #4]
-
-        ; Save FP return value or HFA.
-        vstm                r6, {d0-d3}
-
-#ifdef _DEBUG
-        ;; trash the floating point registers to ensure that the HFA return values 
-        ;; won't survive by accident
-        vldm                sp, {d0-d3}
-#endif
-
-        EPILOG_STACK_RESTORE r7
-        EPILOG_POP          {r4-r7,r11,pc}
-
         NESTED_END
 
-
 ; ------------------------------------------------------------------
 
         NESTED_ENTRY ThePreStub
index 262e481..7d0a9f7 100644 (file)
@@ -46,7 +46,7 @@ ASMCONSTANTS_C_ASSERT(Thread__m_pFrame == offsetof(Thread, m_pFrame));
 #define Thread_m_fPreemptiveGCDisabled Thread__m_fPreemptiveGCDisabled
 
 #ifndef CROSSGEN_COMPILE
-#define               Thread__m_pDomain                 0x20
+#define               Thread__m_pDomain                 0x18
 ASMCONSTANTS_C_ASSERT(Thread__m_pDomain == offsetof(Thread, m_pDomain));
 
 #define               AppDomain__m_dwId                 0x08
index e138feb..aa79b4d 100644 (file)
@@ -767,15 +767,6 @@ LOCAL_LABEL(UMThunkStub_HaveThread):
 
 LOCAL_LABEL(UMThunkStub_InCooperativeMode):
     ldr x12, [fp, #UMThunkStub_HiddenArg] // x12 = UMEntryThunk*
-
-    ldr x0, [x19, #Thread__m_pDomain]
-
-    // m_dwDomainId is 4 bytes so using 32-bit variant
-    ldr w1, [x12, #UMEntryThunk__m_dwDomainId]
-    ldr w0, [x0, #AppDomain__m_dwId]
-    cmp w0, w1
-    bne LOCAL_LABEL(UMThunkStub_WrongAppDomain)
-
     ldr x3, [x12, #UMEntryThunk__m_pUMThunkMarshInfo] // x3 = m_pUMThunkMarshInfo
 
     // m_cbActualArgSize is UINT32 and hence occupies 4 bytes
@@ -846,112 +837,8 @@ LOCAL_LABEL(UMThunkStub_DoTrapReturningThreads):
     add sp, sp, #SIZEOF__FloatArgumentRegisters
     b LOCAL_LABEL(UMThunkStub_InCooperativeMode)
 
-LOCAL_LABEL(UMThunkStub_WrongAppDomain):
-    // Saving FP Args as this is read by UM2MThunk_WrapperHelper
-    sub sp, sp, #SIZEOF__FloatArgumentRegisters
-    SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
-
-    // UMEntryThunk* pUMEntry
-    ldr x0, [fp, #UMThunkStub_HiddenArg]
-
-    // void * pArgs
-    add x2, fp, #16  
-
-    // remaining arguments are unused
-    bl C_FUNC(UM2MDoADCallBack)
-
-    // restore integral return value
-    ldp x0, x1, [fp, #16]
-
-    // restore FP or HFA return value
-    RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
-
-    b LOCAL_LABEL(UMThunkStub_PostCall)
-
 NESTED_END UMThunkStub, _TEXT
 
-
-// UM2MThunk_WrapperHelper(void *pThunkArgs, // x0
-//                         int cbStackArgs,  // x1 (unused)
-//                         void *pAddr,  // x2 (unused)
-//                         UMEntryThunk *pEntryThunk,// x3
-//                         Thread *pThread)  // x4
-
-// pThunkArgs points to the argument registers pushed on the stack by UMThunkStub
-
-NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT, NoHandler
-
-    PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32
-    PROLOG_SAVE_REG  x19, 16
-
-
-    // save pThunkArgs in non-volatile reg. It is required after return from call to ILStub
-    mov x19, x0  
-
-    // ARM64TODO - Is this required by ILStub
-    mov x12, x3  //// x12 = UMEntryThunk *
-
-    //
-    // Note that layout of the arguments is given by UMThunkStub frame
-    //
-    ldr x3, [x3, #UMEntryThunk__m_pUMThunkMarshInfo]
-
-    // m_cbActualArgSize is 4-byte field
-    ldr w2, [x3, #UMThunkMarshInfo__m_cbActualArgSize]
-    cbz w2, LOCAL_LABEL(UM2MThunk_WrapperHelper_RegArgumentsSetup)
-
-    // extend to 64- bits
-    uxtw x2, w2 
-
-    // Source pointer. Subtracting 16 bytes due to fp & lr
-    add x6, x0, #(UMThunkStub_StackArgs-16) 
-
-    // move source ptr to end of Stack Args
-    add x6, x6, x2 
-
-    // Count of stack slot pairs to copy (divide by 16)
-    lsr x1, x2, #4
-
-    // Is there an extra stack slot? (can happen when stack arg bytes not multiple of 16)
-    and x2, x2, #8
-
-    // If yes then start source pointer from 16 byte aligned stack slot
-    add x6, x6, x2
-
-    // increment stack slot pair count by 1 if x2 is not zero
-    add x1, x1, x2, LSR #3
-
-LOCAL_LABEL(UM2MThunk_WrapperHelper_StackLoop):
-    ldp x4, x5, [x6, #-16]!
-    stp x4, x5, [sp, #-16]!
-    subs x1, x1, #1
-    bne LOCAL_LABEL(UM2MThunk_WrapperHelper_StackLoop)
-
-LOCAL_LABEL(UM2MThunk_WrapperHelper_RegArgumentsSetup):
-    ldr x16, [x3, #(UMThunkMarshInfo__m_pILStub)]
-
-    // reload floating point registers
-    RESTORE_FLOAT_ARGUMENT_REGISTERS x0, -1 * (SIZEOF__FloatArgumentRegisters + 16)
-
-    // reload argument registers
-    RESTORE_ARGUMENT_REGISTERS x0, 0
-
-    blr x16
-
-    // save integral return value
-    stp x0, x1, [x19]
-
-    // save FP/HFA return values
-    SAVE_FLOAT_ARGUMENT_REGISTERS x19, -1 * (SIZEOF__FloatArgumentRegisters + 16)
-
-    EPILOG_STACK_RESTORE
-    EPILOG_RESTORE_REG  x19, 16
-    EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
-    EPILOG_RETURN
-
-NESTED_END UM2MThunk_WrapperHelper, _TEXT
-
-
 #ifdef FEATURE_HIJACK
 // ------------------------------------------------------------------
 // Hijack function for functions which return a scalar type or a struct (value type)
index 7346c46..e9edec1 100644 (file)
@@ -27,7 +27,6 @@
     IMPORT GetThread
     IMPORT CreateThreadBlockThrow
     IMPORT UMThunkStubRareDisableWorker
-    IMPORT UM2MDoADCallBack
     IMPORT GetCurrentSavedRedirectContext
     IMPORT LinkFrameAndThrow
     IMPORT FixContextHandler
@@ -754,15 +753,6 @@ UMThunkStub_HaveThread
 
 UMThunkStub_InCooperativeMode
     ldr                 x12, [fp, #UMThunkStub_HiddenArg] ; x12 = UMEntryThunk*
-
-    ldr                 x0, [x19, #Thread__m_pDomain]
-
-    ; m_dwDomainId is 4 bytes so using 32-bit variant
-    ldr                 w1, [x12, #UMEntryThunk__m_dwDomainId]
-    ldr                 w0, [x0, #AppDomain__m_dwId]
-    cmp                 w0, w1
-    bne                 UMThunkStub_WrongAppDomain
-
     ldr                 x3, [x12, #UMEntryThunk__m_pUMThunkMarshInfo] ; x3 = m_pUMThunkMarshInfo
 
     ; m_cbActualArgSize is UINT32 and hence occupies 4 bytes
@@ -833,109 +823,6 @@ UMThunkStub_DoTrapReturningThreads
     add                 sp, sp, #SIZEOF__FloatArgumentRegisters
     b                   UMThunkStub_InCooperativeMode
 
-UMThunkStub_WrongAppDomain
-    ; Saving FP Args as this is read by UM2MThunk_WrapperHelper
-    sub                 sp, sp, #SIZEOF__FloatArgumentRegisters
-    SAVE_FLOAT_ARGUMENT_REGISTERS  sp, 0
-
-    ; UMEntryThunk* pUMEntry
-    ldr                 x0, [fp, #UMThunkStub_HiddenArg]
-
-    ; void * pArgs
-    add                 x2, fp, #16              
-
-    ; remaining arguments are unused
-    bl                  UM2MDoADCallBack
-
-    ; restore any integral return value(s)
-    ldp                 x0, x1, [fp, #16]
-
-    ; restore any FP or HFA return value(s)
-    RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
-
-    b                   UMThunkStub_PostCall
-
-    NESTED_END
-
-
-; UM2MThunk_WrapperHelper(void *pThunkArgs,             // x0
-;                         int cbStackArgs,              // x1 (unused)
-;                         void *pAddr,                  // x2 (unused)
-;                         UMEntryThunk *pEntryThunk,    // x3
-;                         Thread *pThread)              // x4
-
-; pThunkArgs points to the argument registers pushed on the stack by UMThunkStub
-
-    NESTED_ENTRY UM2MThunk_WrapperHelper
-
-    PROLOG_SAVE_REG_PAIR fp, lr, #-32!
-    PROLOG_SAVE_REG      x19, #16
-
-
-    ; save pThunkArgs in non-volatile reg. It is required after return from call to ILStub
-    mov                 x19, x0  
-
-    ; ARM64TODO - Is this required by ILStub
-    mov                 x12, x3  ;                    // x12 = UMEntryThunk *
-
-    ;
-    ; Note that layout of the arguments is given by UMThunkStub frame
-    ;
-    ldr                 x3, [x3, #UMEntryThunk__m_pUMThunkMarshInfo]
-
-    ; m_cbActualArgSize is 4-byte field
-    ldr                 w2, [x3, #UMThunkMarshInfo__m_cbActualArgSize]
-    cbz                 w2, UM2MThunk_WrapperHelper_RegArgumentsSetup
-
-    ; extend to 64- bits
-    uxtw                x2, w2 
-
-    ; Source pointer. Subtracting 16 bytes due to fp & lr
-    add                 x6, x0, #(UMThunkStub_StackArgs-16) 
-
-    ; move source ptr to end of Stack Args
-    add                 x6, x6, x2 
-
-    ; Count of stack slot pairs to copy (divide by 16)
-    lsr                 x1, x2, #4
-
-    ; Is there an extra stack slot? (can happen when stack arg bytes not multiple of 16)
-    and                 x2, x2, #8
-
-    ; If yes then start source pointer from 16 byte aligned stack slot
-    add                 x6, x6, x2
-
-    ; increment stack slot pair count by 1 if x2 is not zero
-    add                 x1, x1, x2, LSR #3
-
-UM2MThunk_WrapperHelper_StackLoop
-    ldp                 x4, x5, [x6, #-16]!
-    stp                 x4, x5, [sp, #-16]!
-    subs                x1, x1, #1
-    bne                 UM2MThunk_WrapperHelper_StackLoop
-
-UM2MThunk_WrapperHelper_RegArgumentsSetup
-    ldr                 x16, [x3, #(UMThunkMarshInfo__m_pILStub)]
-
-    ; reload floating point registers
-    RESTORE_FLOAT_ARGUMENT_REGISTERS x0, -1 * (SIZEOF__FloatArgumentRegisters + 16)
-
-    ; reload argument registers
-    RESTORE_ARGUMENT_REGISTERS x0, 0
-
-    blr                 x16
-
-    ; save any integral return value(s)
-    stp                 x0, x1, [x19]
-
-    ; save any FP or HFA return value(s)
-    SAVE_FLOAT_ARGUMENT_REGISTERS x19, -1 * (SIZEOF__FloatArgumentRegisters + 16)
-
-    EPILOG_STACK_RESTORE
-    EPILOG_RESTORE_REG      x19, #16
-    EPILOG_RESTORE_REG_PAIR fp, lr, #32!
-    EPILOG_RETURN
-    
     NESTED_END
 
 #ifdef FEATURE_HIJACK
index d11c4e8..b11f9d7 100644 (file)
@@ -404,8 +404,6 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
         //
         ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
 
-        _ASSERTE(GetAppDomain()->ShouldHaveCode());
-
 #ifdef FEATURE_INTERPRETER
         _ASSERTE(isCallConv(m_methodSig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_DEFAULT)
                  || isCallConv(m_methodSig.GetCallingConvention(), CorCallingConvention(IMAGE_CEE_CS_CALLCONV_C))
index 9874d26..04b1226 100644 (file)
@@ -950,8 +950,6 @@ void EEStartupHelper(COINITIEE fFlags)
 
         StackwalkCache::Init();
 
-        AppDomain::CreateADUnloadStartEvent();
-
         // In coreclr, clrjit is compiled into it, but SO work in clrjit has not been done.
 #ifdef FEATURE_STACK_PROBE
         if (CLRHosted() && GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
@@ -996,19 +994,6 @@ void EEStartupHelper(COINITIEE fFlags)
         SystemDomain::NotifyProfilerStartup();
 #endif // PROFILING_SUPPORTED
 
-#ifndef CROSSGEN_COMPILE
-        if (CLRHosted()
-#ifdef _DEBUG
-            || ((fFlags & COINITEE_DLL) == 0 &&
-                g_pConfig->GetHostTestADUnload())
-#endif
-           ) {
-                // If we are hosted, a host may specify unloading AD when a managed allocation in
-                // critical region fails.  We need to precreate a thread to unload AD.
-                AppDomain::CreateADUnloadWorker();
-        }
-#endif // CROSSGEN_COMPILE
-
         g_fEEInit = false;
 
         SystemDomain::System()->DefaultDomain()->LoadSystemAssemblies();
index 5f7ef16..06451e9 100644 (file)
@@ -2383,10 +2383,6 @@ HRESULT CodeVersionManager::EnumerateClosedMethodDescs(
         while (appDomainIterator.Next())
         {
             AppDomain * pAppDomain = appDomainIterator.GetDomain();
-            if (pAppDomain->IsUnloading())
-            {
-                continue;
-            }
             hr = EnumerateDomainClosedMethodDescs(
                 pAppDomain,
                 pModule,
index 4d116c1..49802ff 100644 (file)
@@ -751,10 +751,7 @@ HRESULT WeakReferenceImpl::Cleanup()
         //
         GCX_COOP_THREAD_EXISTS(GET_THREAD());    
         
-        AppDomainFromIDHolder ad(m_adid, TRUE);
-        
-        if (!ad.IsUnloaded())
-            DestroyShortWeakHandle(m_ppObject);
+        DestroyShortWeakHandle(m_ppObject);
         
         m_ppObject = NULL;
     }
@@ -1103,18 +1100,7 @@ VOID SimpleComCallWrapper::Cleanup()
     // so we must release it if the AD wasn't unloaded
     if (IsAgile() && m_hOrigDomainHandle)
     {  
-        // the domain which the original handle belongs to might be already unloaded
-        if (GetRawDomainID()==::GetAppDomain()->GetId())
-            DestroyRefcountedHandle(m_hOrigDomainHandle);
-        else
-        {
-            GCX_COOP();
-            {
-                AppDomainFromIDHolder ad(GetRawDomainID(), TRUE);
-                if (!ad.IsUnloaded())
-                    DestroyRefcountedHandle(m_hOrigDomainHandle);
-            }
-        }
+        DestroyRefcountedHandle(m_hOrigDomainHandle);
         m_hOrigDomainHandle = NULL;
     }
 
@@ -2127,10 +2113,7 @@ void ComCallWrapper::MarkHandleWeak()
         MODE_ANY;
     }
     CONTRACTL_END;
-#ifdef _DEBUG
-    AppDomainFromIDHolder ad(GetSimpleWrapper()->GetDomainID(), TRUE);
-    _ASSERTE(!ad.IsUnloaded());
-#endif
+
     SyncBlock* pSyncBlock = GetSyncBlock();
     _ASSERTE(pSyncBlock);
 
@@ -2152,10 +2135,6 @@ void ComCallWrapper::ResetHandleStrength()
     }
     CONTRACTL_END;
     
-#ifdef _DEBUG
-    AppDomainFromIDHolder ad(GetSimpleWrapper()->GetDomainID(), TRUE);
-    _ASSERTE(!ad.IsUnloaded());
-#endif   
     SyncBlock* pSyncBlock = GetSyncBlock();
     _ASSERTE(pSyncBlock);
 
@@ -2511,27 +2490,10 @@ void ComCallWrapper::Cleanup()
         ClearSimpleWrapper(this);
     }
 
+    if (fOwnsHandle && m_ppThis)
     {
-        // Switch to cooperative mode for AppDomainFromIDHolder
-        // AppDomainFromIDHolder.Assign might forbid GC and AppDomainFromIDHolder.Release might re-enable GC. 
-        // The state is stored in ClrDebugState, which GCX_COOP() macros will push into stack & pop from stack 
-        // So use GCX_COOP() around all these statements for AppDomainFromIDHolder
-        GCX_COOP();
-        
-        // deregister the handle, in the first block. If no domain, then it's already done
-        AppDomainFromIDHolder pTgtDomain;
-        if (domainId != CURRENT_APPDOMAIN_ID)
-        {       
-            pTgtDomain.Assign(domainId, FALSE);        
-        }
-        
-        if (fOwnsHandle && m_ppThis && !pTgtDomain.IsUnloaded())
-        {            
-            LOG((LF_INTEROP, LL_INFO100, "ComCallWrapper::Cleanup on Object %8.8x\n", m_ppThis));
-            ClearHandle();
-        }
-        
-        pTgtDomain.Release();
+        LOG((LF_INTEROP, LL_INFO100, "ComCallWrapper::Cleanup on Object %8.8x\n", m_ppThis));
+        ClearHandle();
     }
     
     m_ppThis = NULL;
index 9b9d56a..4a74ddd 100644 (file)
@@ -341,21 +341,10 @@ OBJECTREF COMInterfaceMarshaler::GetCCWObject()
     if (m_dwServerSyncBlockIndex != 0)
     {
         AppDomain* pCurrDomain = m_pThread->GetDomain();
-        if (m_dwServerDomainId == pCurrDomain->GetId())
-        {
-            // if we are in the right AD, we know for sure that the object is still alive
-            // since we keep the CCW addref'ed and the AD could not have been unloaded
-            oref = ObjectToOBJECTREF(g_pSyncTable[m_dwServerSyncBlockIndex].m_Object);
-        }
-        else
-        {
-            // otherwise we have to make sure that the AD hasn't been unloaded
-            AppDomainFromIDHolder ad(m_dwServerDomainId, TRUE);
-            if (!ad.IsUnloaded())
-            {
-                oref = ObjectToOBJECTREF(g_pSyncTable[m_dwServerSyncBlockIndex].m_Object);
-            }
-        }
+
+        // if we are in the right AD, we know for sure that the object is still alive
+        // since we keep the CCW addref'ed
+        oref = ObjectToOBJECTREF(g_pSyncTable[m_dwServerSyncBlockIndex].m_Object);
     }
 
     return oref;
index 0a6447b..5f54bcd 100644 (file)
@@ -52,10 +52,9 @@ struct SharedState
             MODE_COOPERATIVE;
         }
         CONTRACTL_END;
-        AppDomainFromIDHolder ad(internal->GetKickOffDomainId(), TRUE);
-        if (ad.IsUnloaded())
-            COMPlusThrow(kAppDomainUnloadedException);
 
+        AppDomain *ad = SystemDomain::GetAppDomainFromId(internal->GetKickOffDomainId(), ADV_CURRENTAD);
+    
         m_Threadable = ad->CreateHandle(threadable);
         m_ThreadStartArg = ad->CreateHandle(threadStartArg);
 
@@ -72,17 +71,8 @@ struct SharedState
         }
         CONTRACTL_END;
 
-        // It's important to have no GC rendez-vous point between the checking and the clean-up below.
-        // The three handles below could be in an appdomain which is just starting to be unloaded, or an appdomain
-        // which has been unloaded already.  Thus, we need to check whether the appdomain is still valid before
-        // we do the clean-up.  Since we suspend all runtime threads when we try to do the unload, there will be no
-        // race condition between the checking and the clean-up as long as this thread cannot be suspended in between.
-        AppDomainFromIDHolder ad(m_Internal->GetKickOffDomainId(), TRUE);
-        if (!ad.IsUnloaded())
-        {
-            DestroyHandle(m_Threadable);
-            DestroyHandle(m_ThreadStartArg);
-        }
+        DestroyHandle(m_Threadable);
+        DestroyHandle(m_ThreadStartArg);
     }
 };
 
index 2a60f8c..df1ba64 100644 (file)
@@ -615,62 +615,13 @@ void COMToCLRWorkerBodyWithADTransition(
     BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, { *pRetValOut = COR_E_STACKOVERFLOW; return; } );
     EX_TRY
     {
-        bool fNeedToTranslateTAEtoADUE = false;
         ADID pTgtDomain = pWrap->GetDomainID();
         ENTER_DOMAIN_ID(pTgtDomain)
         {
             fEnteredDomain = TRUE;
             COMToCLRWorkerBody_SOIntolerant(pThread, pFrame, pWrap, pRetValOut);
-
-            //
-            // Below is some logic adapted from Thread::RaiseCrossContextExceptionHelper, which we now
-            // bypass because the IL stub is catching the ThreadAbortException instead of a proper domain 
-            // transition, where the logic typically resides.  This code applies some policy to transform 
-            // the ThreadAbortException into an AppDomainUnloadedException and sets up the HRESULT and 
-            // IErrorInfo accordingly.
-            //
-
-            // If the IL stub caught a TAE...
-            if (COR_E_THREADABORTED == ((HRESULT)*pRetValOut))
-            {
-                // ...first, make sure it was actually an HRESULT return value...
-                ComCallMethodDesc* pCMD = pFrame->GetComCallMethodDesc();
-                if (pCMD->IsNativeHResultRetVal()) 
-                {
-                    // There may be multiple AD transitions on the stack so the current unload boundary may
-                    // not be the transition frame that was set up to make our AD switch. Detect that by
-                    // comparing the unload boundary's Next with our ComMethodFrame and proceed to translate
-                    // the exception to ADUE only if they match. Otherwise the exception should stay as TAE.
-
-                    Frame* pUnloadBoundary = pThread->GetUnloadBoundaryFrame();
-                    // ...and we are at an unload boundary with a pending unload...
-                    if (    (    pUnloadBoundary != NULL
-                             && (pUnloadBoundary->Next() == pFrame
-                             &&  pThread->ShouldChangeAbortToUnload(pUnloadBoundary, pUnloadBoundary))
-                            )
-                        // ... or we don't have an unload boundary, but we're otherwise unloading 
-                        //     this domain from another thread (and we aren't the finalizer)...
-                        ||  (   (NULL == pUnloadBoundary)
-                             && (pThread->GetDomain() == SystemDomain::AppDomainBeingUnloaded())
-                             && (pThread != SystemDomain::System()->GetUnloadingThread())
-                             && (pThread != FinalizerThread::GetFinalizerThread())
-                            )
-                       )
-                    {
-                        // ... we take note and then create an ADUE in the domain we're returning to.
-                        fNeedToTranslateTAEtoADUE = true;
-                    }
-                }
-            }
         }
         END_DOMAIN_TRANSITION;
-
-        if (fNeedToTranslateTAEtoADUE)
-        {
-            EEResourceException ex(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
-            OBJECTREF oEx = CLRException::GetThrowableFromException(&ex);
-            *pRetValOut = SetupErrorInfo(oEx, pFrame->GetComCallMethodDesc());
-        }
     }
     EX_CATCH
     {
index ef99dec..f9785ab 100644 (file)
@@ -1180,48 +1180,7 @@ HRESULT CorRuntimeHostBase::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDo
     }
     CONTRACTL_END;
 
-    HRESULT hr = S_OK;
-
-    // No point going further if the runtime is not running...
-    {
-        // In IsRuntimeActive, we will call CanRunManagedCode that will
-        // check if the current thread has taken the loader lock or not,
-        // if MDA is supported. To do the check, MdaLoaderLock::ReportViolation
-        // will be invoked that will internally end up invoking
-        // MdaFactory<MdaXmlElement>::GetNext that will use the "new" operator
-        // that has the "FAULT" contract set, resulting in FAULT_VIOLATION since
-        // this method has the FORBID_FAULT contract set above.
-        //
-        // However, for a thread that holds the loader lock, unloading the appDomain is
-        // not a supported scenario. Thus, we should not be ending up in this code
-        // path for the FAULT violation.
-        //
-        // Hence, the CONTRACT_VIOLATION below for overriding the FORBID_FAULT
-        // for this scope only.
-        CONTRACT_VIOLATION(FaultViolation);
-        if (!IsRuntimeActive()
-            || !m_fStarted
-        )
-        {
-            return HOST_E_CLRNOTAVAILABLE;
-        }
-    }
-
-    BEGIN_ENTRYPOINT_NOTHROW;
-
-    // We do not use BEGIN_EXTERNAL_ENTRYPOINT here because
-    // we do not want to setup Thread.  Process may be OOM, and we want Unload
-    // to work.
-    hr =  AppDomain::UnloadById(ADID(dwDomainId), fWaitUntilDone);
-
-    END_ENTRYPOINT_NOTHROW;
-
-    if (pLatchedExitCode)
-    {
-        *pLatchedExitCode = GetLatchedExitCode();
-    }
-
-    return hr;
+    return COR_E_CANNOTUNLOADAPPDOMAIN;
 }
 
 //*****************************************************************************
@@ -1924,18 +1883,11 @@ public:
         BEGIN_ENTRYPOINT_NOTHROW;
 
         SystemDomain::LockHolder lh;
-        AppDomainFromIDHolder pAppDomain((ADID)dwAppDomainId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
 
-        if (!pAppDomain.IsUnloaded())
+        AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);        
+        if (pBytesAllocated)
         {
-            if (pBytesAllocated)
-            {
-                *pBytesAllocated = pAppDomain->GetAllocBytes();
-            }
-        }
-        else
-        {
-            hr = COR_E_APPDOMAINUNLOADED;
+            *pBytesAllocated = pAppDomain->GetAllocBytes();
         }
 
         END_ENTRYPOINT_NOTHROW;
@@ -1959,22 +1911,15 @@ public:
         BEGIN_ENTRYPOINT_NOTHROW;
 
         SystemDomain::LockHolder lh;
-        AppDomainFromIDHolder pAppDomain((ADID)dwAppDomainId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
 
-        if (pAppDomain.IsUnloaded())
+        AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
+        if (pAppDomainBytesSurvived)
         {
-            hr = COR_E_APPDOMAINUNLOADED;
+            *pAppDomainBytesSurvived = pAppDomain->GetSurvivedBytes();
         }
-        else
+        if (pTotalBytesSurvived)
         {
-            if (pAppDomainBytesSurvived)
-            {
-                *pAppDomainBytesSurvived = pAppDomain->GetSurvivedBytes();
-            }
-            if (pTotalBytesSurvived)
-            {
-                *pTotalBytesSurvived = SystemDomain::GetTotalSurvivedBytes();
-            }
+            *pTotalBytesSurvived = SystemDomain::GetTotalSurvivedBytes();
         }
 
         END_ENTRYPOINT_NOTHROW;
@@ -2000,20 +1945,10 @@ public:
         {
             SystemDomain::LockHolder lh;
     
+            AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
+            if (pMilliseconds)
             {
-                AppDomainFromIDHolder pAppDomain((ADID)dwAppDomainId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
-
-                if (!pAppDomain.IsUnloaded())
-                {
-                    if (pMilliseconds)
-                    {
-                        *pMilliseconds = pAppDomain->QueryProcessorUsage() / 10000;
-                    }
-                }
-                else
-                {
-                    hr = COR_E_APPDOMAINUNLOADED;
-                }
+                *pMilliseconds = pAppDomain->QueryProcessorUsage() / 10000;
             }
         }
 
index 80a69a6..8bc21b0 100644 (file)
@@ -43,17 +43,12 @@ struct DelegateInfo
         CONTRACTL_END;
 
 
-        AppDomainFromIDHolder ad(m_appDomainId, FALSE);
-        if (!ad.IsUnloaded())
-        {
-            if (m_stateHandle)
-                DestroyHandle(m_stateHandle);
-            if (m_eventHandle)
-                DestroyHandle(m_eventHandle);
-            if (m_registeredWaitHandle)
-               DestroyHandle(m_registeredWaitHandle);
-        }
-
+        if (m_stateHandle)
+            DestroyHandle(m_stateHandle);
+        if (m_eventHandle)
+                DestroyHandle(m_eventHandle);
+        if (m_registeredWaitHandle)
+            DestroyHandle(m_registeredWaitHandle);
     }
 #endif
 
index f7b3068..393c2aa 100644 (file)
@@ -3315,8 +3315,7 @@ DispatchMemberInfo* DispatchExInfo::CreateDispatchMemberInfoInstance(DISPID Disp
 
     DispatchMemberInfo* pInfo = new DispatchMemberInfo(this, DispID, strMemberName, MemberInfoObj);
 
-    AppDomainFromIDHolder pDomain(m_pSimpleWrapperOwner->GetDomainID(), FALSE);
-    pDomain.ThrowIfUnloaded();
+    AppDomain* pDomain = SystemDomain::GetAppDomainFromId(m_pSimpleWrapperOwner->GetDomainID(), ADV_CURRENTAD);
     
     pInfo->SetHandle(pDomain->CreateHandle(MemberInfoObj));
     
index 2becba5..c064872 100644 (file)
@@ -106,70 +106,6 @@ private:
 
 static UMEntryThunkFreeList s_thunkFreeList(DEFAULT_THUNK_FREE_LIST_THRESHOLD);
 
-EXTERN_C void STDCALL UM2MThunk_WrapperHelper(void *pThunkArgs,
-                                              int argLen,
-                                              void *pAddr,
-                                              UMEntryThunk *pEntryThunk,
-                                              Thread *pThread);
-
-// This is used as target of callback from DoADCallBack. It sets up the environment and effectively
-// calls back into the thunk that needed to switch ADs.
-void UM2MThunk_Wrapper(LPVOID ptr) // UM2MThunk_Args
-{
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_GC_TRIGGERS;
-    STATIC_CONTRACT_MODE_COOPERATIVE;
-    STATIC_CONTRACT_SO_INTOLERANT;
-
-    UM2MThunk_Args *pArgs = (UM2MThunk_Args *) ptr;
-    Thread* pThread = GetThread();
-
-    BEGIN_CALL_TO_MANAGED();
-
-    // return value is saved to pArgs->pThunkArgs
-    UM2MThunk_WrapperHelper(pArgs->pThunkArgs,
-                            pArgs->argLen,
-                            pArgs->pAddr,
-                            pArgs->pEntryThunk,
-                            pThread);
-
-    END_CALL_TO_MANAGED();
-}
-
-EXTERN_C void STDCALL UM2MDoADCallBack(UMEntryThunk *pEntryThunk,
-                                       void *pAddr,
-                                       void *pArgs,
-                                       int argLen)
-{
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-        ENTRY_POINT;
-        PRECONDITION(CheckPointer(pEntryThunk));
-        PRECONDITION(CheckPointer(pArgs));
-    }
-    CONTRACTL_END;
-
-    UM2MThunk_Args args = { pEntryThunk, pAddr, pArgs, argLen };
-
-
-    INSTALL_MANAGED_EXCEPTION_DISPATCHER;
-    INSTALL_UNWIND_AND_CONTINUE_HANDLER;
-    {
-        AppDomainFromIDHolder domain(pEntryThunk->GetDomainId(),FALSE);
-        domain.ThrowIfUnloaded();
-        if(!domain->CanReversePInvokeEnter())
-            COMPlusThrow(kNotSupportedException);
-    }
-
-    GetThread()->DoADCallBack(pEntryThunk->GetDomainId(), UM2MThunk_Wrapper, &args);
-
-    UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
-    UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
-}
-
 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
 
 EXTERN_C VOID __cdecl UMThunkStubRareDisable();
@@ -198,10 +134,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
     CodeLabel* pRejoinThreadLabel   = pcpusl->NewCodeLabel();
     CodeLabel* pDisableGCLabel      = pcpusl->NewCodeLabel();
     CodeLabel* pRejoinGCLabel       = pcpusl->NewCodeLabel();
-    CodeLabel* pDoADCallBackLabel   = pcpusl->NewCodeLabel();
-    CodeLabel* pDoneADCallBackLabel = pcpusl->NewCodeLabel();
-    CodeLabel* pADCallBackEpilog    = pcpusl->NewCodeLabel();
-    CodeLabel* pDoADCallBackStartLabel = pcpusl->NewAbsoluteCodeLabel();
 
     // We come into this code with UMEntryThunk in EAX
     const X86Reg kEAXentryThunk = kEAX;
@@ -318,22 +250,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
     // lea ebx, [ebp + 8]
     pcpusl->X86EmitIndexLea(kEBX, kEBP, 8);
 
-    // Load pThread->m_pDomain into edx
-    // mov edx,[ecx + offsetof(Thread, m_pAppDomain)]
-    pcpusl->X86EmitIndexRegLoad(kEDX, kECXthread, Thread::GetOffsetOfAppDomain());
-
-    // Load pThread->m_pAppDomain->m_dwId into edx
-    // mov edx,[edx + offsetof(AppDomain, m_dwId)]
-    pcpusl->X86EmitIndexRegLoad(kEDX, kEDX, AppDomain::GetOffsetOfId());
-
-    // check if the app domain of the thread matches that of delegate
-    // cmp edx,[eax + offsetof(UMEntryThunk, m_dwDomainId))]
-    pcpusl->X86EmitOffsetModRM(0x3b, kEDX, kEAXentryThunk, offsetof(UMEntryThunk, m_dwDomainId));
-
-    // jne pWrongAppDomain ; mismatch. This will call back into the stub with the
-    // correct AppDomain through DoADCallBack
-    pcpusl->X86EmitCondJump(pDoADCallBackLabel, X86CondCode::kJNE);
-
     //
     // ----------------------------------------------------------------------------------------------
     //
@@ -376,14 +292,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
     //            +-------------------------+
     //
 
-    // It's important that the "restart" after an AppDomain switch will skip
-    // the check for g_TrapReturningThreads.  That's because, during shutdown,
-    // we can only go through the UMThunkStubRareDisable pathway if we have
-    // not yet pushed a frame.  (Once pushed, the frame cannot be popped
-    // without coordinating with the GC.  During shutdown, such coordination
-    // would deadlock).
-    pcpusl->EmitLabel(pDoADCallBackStartLabel);
-
     // save the thread pointer
     pcpusl->X86EmitPushReg(kECXthread);
 
@@ -564,33 +472,13 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
     // restore the thread pointer
     pcpusl->X86EmitPopReg(kECXthread);
 
-
-    // Check whether we got here via the switch AD case. We can tell this by looking at whether the
-    // caller's arguments immediately precede our EBP frame (they will for the non-switch case but
-    // otherwise we will have pushed several frames in the interim). If we did switch now is the time
-    // to jump to our inner epilog which will clean up the inner stack frame and return to the runtime
-    // AD switching code.
-
-    // Does EBX (argument pointer) == EBP + 8?
-    // sub ebx, 8
-    pcpusl->X86EmitSubReg(kEBX, 8);
-
-    // cmp ebx, ebp
-    pcpusl->X86EmitR2ROp(0x3B, kEBX, kEBP);
-
-    // jne pADCallBackEpilog
-    pcpusl->X86EmitCondJump(pADCallBackEpilog, X86CondCode::kJNE);
-
     //
     // Once we reach this point in the code we're back to a single scenario: the outer frame of the
-    // reverse p/invoke. Either we never had to switch AppDomains or the AD switch code has already
-    // unwound and returned here to pop off the outer frame.
+    // reverse p/invoke.
     //
     // ----------------------------------------------------------------------------------------------
     //
 
-    pcpusl->EmitLabel(pDoneADCallBackLabel);
-
     // move byte ptr [ecx + Thread.m_fPreemptiveGCDisabled],0
     pcpusl->X86EmitOffsetModRM(0xc6, (X86Reg)0, kECXthread, Thread::GetOffsetOfGCFlag());
     pcpusl->Emit8(0);
@@ -693,47 +581,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
     pcpusl->X86EmitNearJump(pRejoinGCLabel);
 
     //-------------------------------------------------------------
-    // coming here if appdomain didn't match
-    //
-
-    pcpusl->EmitLabel(pDoADCallBackLabel);
-
-    // we will call DoADCallBack which calls into managed code to switch ADs and then calls us
-    // back. So when come in the second time the ADs will match and just keep processing.
-    // So we need to setup the parms to pass to DoADCallBack one of which is an address inside
-    // the stub that will branch back to the top of the stub to start again. Need to setup
-    // the parms etc so that when we return from the 2nd call we pop things properly.
-
-    // save thread pointer
-    pcpusl->X86EmitPushReg(kECXthread);
-
-    // push values for UM2MThunk_Args
-
-    // Move address of args (EBX) into EDX since some paths below use EBX.
-    pcpusl->X86EmitMovRegReg(kEDX, kEBX);
-
-    // size of args
-    pcpusl->X86EmitPushImm32(pInfo->m_cbSrcStack);
-
-    // address of args
-    pcpusl->X86EmitPushReg(kEDX);
-
-    // addr to call
-    pcpusl->X86EmitPushImm32(*pDoADCallBackStartLabel);
-
-    // UMEntryThunk
-    pcpusl->X86EmitPushReg(kEAXentryThunk);
-
-    // call UM2MDoADCallBack
-    pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID) UM2MDoADCallBack), 8);
-
-    // We need to clear the thread off the top of the stack and place it in ECX. Two birds with one stone.
-    pcpusl->X86EmitPopReg(kECX);
-
-    // Re-join the original stub to perform the last parts of the epilog.
-    pcpusl->X86EmitNearJump(pDoneADCallBackLabel);
-
-    //-------------------------------------------------------------
     // Coming here for rare case when enabling GC pre-emptive mode
     //
 
@@ -751,15 +598,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
 
     // return to mainline of function
     pcpusl->X86EmitNearJump(pEnableRejoin);
-
-    //-------------------------------------------------------------
-    // Coming here when we switched AppDomain and have successfully called the target. We must return
-    // into the runtime code (which will eventually unwind the AD transition and return us to the
-    // mainline stub in order to run the outer epilog).
-    //
-
-    pcpusl->EmitLabel(pADCallBackEpilog);
-    pcpusl->X86EmitReturn(0);
 }
 
 // Compiles an unmanaged to managed thunk for the given signature.
@@ -1105,15 +943,6 @@ void STDCALL UMEntryThunk::DoRunTimeInit(UMEntryThunk* pUMEntryThunk)
     // exceptions don't leak out into managed code.
     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
 
-    // The thread object is guaranteed to have been set up at this point.
-    Thread *pThread = GetThread();
-
-    if (pThread->GetDomain()->GetId() != pUMEntryThunk->GetDomainId())
-    {
-        // call ourselves again through DoCallBack with a domain transition
-        pThread->DoADCallBack(pUMEntryThunk->GetDomainId(), RunTimeInit_Wrapper, pUMEntryThunk);
-    }
-    else
     {
         GCX_PREEMP();
         pUMEntryThunk->RunTimeInit();
index ded1e57..2a1b5e5 100644 (file)
 #include "perfmap.h"
 #endif // FEATURE_PERFMAP
 
-BOOL DomainAssembly::IsUnloading()
-{
-    WRAPPER_NO_CONTRACT;
-    SUPPORTS_DAC;
-
-    BOOL fIsUnloading = FALSE;
-
-    fIsUnloading = this->GetAppDomain()->IsUnloading();
-
-    if (!fIsUnloading)
-    {
-        fIsUnloading = m_fDebuggerUnloadStarted;
-    }
-
-    return fIsUnloading;
-}
-
-
 #ifndef DACCESS_COMPILE
 DomainFile::DomainFile(AppDomain *pDomain, PEFile *pFile)
   : m_pDomain(pDomain),
@@ -1379,11 +1361,7 @@ BOOL DomainFile::PropagateNewActivation(Module *pModuleFrom, Module *pModuleTo)
         while (ai.Next())
         {
             STRESS_LOG3(LF_LOADER, LL_INFO100,"Attempting to propagate domain-neutral conditional module dependency %p -> %p to AppDomain %i\n",pModuleFrom,pModuleTo,ai.GetDomain()->GetId().m_dwId);
-            // This is to minimize the chances of trying to run code in an appdomain that's shutting down.
-            if (ai.GetDomain()->CanThreadEnter(pThread))
-            {
-                completed &= PropagateActivationInAppDomain(pModuleFrom,pModuleTo,ai.GetDomain());
-            }
+            completed &= PropagateActivationInAppDomain(pModuleFrom,pModuleTo,ai.GetDomain());
         }
     }
     else
index 070c616..5870651 100644 (file)
@@ -709,7 +709,6 @@ public:
     BOOL IsVisibleToDebugger();
     BOOL NotifyDebuggerLoad(int flags, BOOL attaching);
     void NotifyDebuggerUnload();
-    BOOL IsUnloading();
 
     inline BOOL IsCollectible();
     // 
index 37864f1..0b3e413 100644 (file)
@@ -345,7 +345,6 @@ HRESULT EEConfig::Init()
 #ifdef _DEBUG
     fShouldInjectFault = 0;
     testThreadAbort = 0;
-    testADUnload = 0;
 #endif
 
 #ifdef FEATURE_COMINTEROP
@@ -1175,7 +1174,6 @@ HRESULT EEConfig::sync()
     fShouldInjectFault = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InjectFault);
 
     testThreadAbort = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HostTestThreadAbort);
-    testADUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HostTestADUnload);
 
 #endif //_DEBUG
 
index 60d8b70..68f160e 100644 (file)
@@ -822,7 +822,6 @@ public:
     GCPollType GetGCPollType() { LIMITED_METHOD_CONTRACT; return iGCPollType; }
 
 #ifdef _DEBUG
-    DWORD GetHostTestADUnload() const {LIMITED_METHOD_CONTRACT; return testADUnload;}
 
     DWORD GetHostTestThreadAbort() const {LIMITED_METHOD_CONTRACT; return testThreadAbort;}
 
@@ -1100,7 +1099,6 @@ private: //----------------------------------------------------------------
 
 #ifdef _DEBUG
     DWORD fShouldInjectFault;
-    DWORD testADUnload;
     DWORD testThreadAbort;
 #endif
 
index efa5fc0..4cd4d0a 100644 (file)
@@ -682,47 +682,6 @@ EPolicyAction EEPolicy::DetermineResourceConstraintAction(Thread *pThread)
     return action;
 }
 
-
-void EEPolicy::PerformADUnloadAction(EPolicyAction action, BOOL haveStack, BOOL forStackOverflow)
-{
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_GC_TRIGGERS;
-    STATIC_CONTRACT_MODE_COOPERATIVE;
-    
-    STRESS_LOG0(LF_EH, LL_INFO100, "In EEPolicy::PerformADUnloadAction\n");       
-
-    Thread *pThread = GetThread();
-
-    AppDomain *pDomain = GetAppDomain();
-
-    if (!IsFinalizerThread())
-    {
-        int count = 0;
-        Frame *pFrame = pThread->GetFirstTransitionInto(GetAppDomain(), &count);
-        {
-            pThread->SetUnloadBoundaryFrame(pFrame);
-        }
-    }
-
-    pDomain->EnableADUnloadWorker(action==eUnloadAppDomain? ADU_Safe : ADU_Rude);
-    // Can't perform a join when we are handling a true SO.  We need to enable the unload woker but let the thread continue running
-    // through EH processing so that we can recover the stack and reset the guard page. 
-    if (haveStack)
-    {
-        pThread->SetAbortRequest(action==eUnloadAppDomain? EEPolicy::TA_V1Compatible : EEPolicy::TA_Rude);
-        if (forStackOverflow)
-        {
-            OBJECTREF exceptObj = CLRException::GetPreallocatedRudeThreadAbortException();
-            pThread->SetAbortInitiated();
-            RaiseTheExceptionInternalOnly(exceptObj, FALSE, TRUE);
-        }
-
-        OBJECTREF exceptObj = CLRException::GetPreallocatedThreadAbortException();
-        pThread->SetAbortInitiated();
-        RaiseTheExceptionInternalOnly(exceptObj, FALSE, FALSE);
-    }
-}
-
 void EEPolicy::PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack)
     {
     WRAPPER_NO_CONTRACT;
@@ -740,13 +699,6 @@ void EEPolicy::PerformResourceConstraintAction(Thread *pThread, EPolicyAction ac
     case eRudeAbortThread:
         pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
         break;
-    case eUnloadAppDomain:
-    case eRudeUnloadAppDomain:
-            {
-                GCX_ASSERT_COOP();
-        PerformADUnloadAction(action,haveStack);
-            }
-        break;
     case eExitProcess:
     case eFastExitProcess:
     case eRudeExitProcess:
@@ -985,12 +937,6 @@ void EEPolicy::HandleStackOverflow(StackOverflowDetector detector, void * pLimit
         // But here we know that if we have only one page, we will only update states of the Domain.
         CONTRACT_VIOLATION(SOToleranceViolation);
 
-        // Mark the current domain requested for rude unload
-        if (!fInDefaultDomain)
-        {
-        pCurrentDomain->EnableADUnloadWorker(ADU_Rude, FALSE);
-        }
-
         pThread->PrepareThreadForSOWork();
 
         pThread->MarkThreadForAbort(
@@ -1051,13 +997,6 @@ void EEPolicy::HandleSoftStackOverflow(BOOL fSkipDebugger)
     {
         Thread* pThread = GetThread();
         
-        if (pThread && pThread->PreemptiveGCDisabled())
-        {
-            // Mark the current domain requested for rude unload
-            GCX_ASSERT_COOP();
-            EEPolicy::PerformADUnloadAction(eRudeUnloadAppDomain, TRUE, TRUE);
-        }
-
         // We are leaving VM boundary, either entering managed code, or entering
         // non-VM unmanaged code.
         // We should not throw internal C++ exception.  Instead we throw an exception
@@ -1608,20 +1547,6 @@ void EEPolicy::HandleCodeContractFailure(LPCWSTR pMessage, LPCWSTR pCondition, L
     case eRudeAbortThread:
         pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
         break;
-    case eUnloadAppDomain:
-        // Register an appdomain unload, which starts on a separate thread.
-        IfFailThrow(AppDomain::UnloadById(pCurrentDomain->GetId(), FALSE));
-        // Don't continue execution on this thread.
-        pThread->UserAbort(Thread::TAR_Thread, TA_Safe, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
-        break;
-    case eRudeUnloadAppDomain:
-        pCurrentDomain->SetRudeUnload();
-        // Register an appdomain unload, which starts on a separate thread.
-        IfFailThrow(AppDomain::UnloadById(pCurrentDomain->GetId(), FALSE));
-        // Don't continue execution on this thread.
-        pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal);
-        break;
-
     case eExitProcess:  // Merged w/ default case
     default:
         _ASSERTE(action == eExitProcess);
index 44e0073..9ca09bb 100644 (file)
@@ -112,8 +112,6 @@ public:
 
     static void PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack);
 
-    static void PerformADUnloadAction(EPolicyAction action, BOOL haveStack, BOOL forStackOverflow = FALSE);
-
     static void HandleOutOfMemory();
 
     static void HandleStackOverflow(StackOverflowDetector detector, void * pLimitFrame);
index be83f1c..6179b6c 100644 (file)
@@ -4804,20 +4804,17 @@ VOID ETW::LoaderLog::DomainUnload(AppDomain *pDomain)
                                         TRACE_LEVEL_INFORMATION, 
                                         KEYWORDZERO))
         {
-            if(!pDomain->NoAccessToHandleTable())
-            {
-                DWORD enumerationOptions = ETW::EnumerationLog::GetEnumerationOptionsFromRuntimeKeywords();
-
-                // Domain unload also causes type unload events
-                if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
-                                                TRACE_LEVEL_INFORMATION, 
-                                                CLR_TYPE_KEYWORD))
-                {
-                    enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::TypeUnload;
-                }
+            DWORD enumerationOptions = ETW::EnumerationLog::GetEnumerationOptionsFromRuntimeKeywords();
 
-                ETW::EnumerationLog::EnumerationHelper(NULL, pDomain, enumerationOptions);
+            // Domain unload also causes type unload events
+            if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
+                                            TRACE_LEVEL_INFORMATION, 
+                                            CLR_TYPE_KEYWORD))
+            {
+                enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::TypeUnload;
             }
+
+            ETW::EnumerationLog::EnumerationHelper(NULL, pDomain, enumerationOptions);
         }
     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
 }
@@ -7006,21 +7003,8 @@ VOID ETW::EnumerationLog::IterateAppDomain(AppDomain * pAppDomain, DWORD enumera
     // ensure the App Domain does not get finalized until we're all done
     SystemDomain::LockHolder lh;
 
-    if (pAppDomain->IsFinalized())
-    {
-        return; 
-    }
-
-    // Since we're not FINALIZED yet, the handle table should remain intact,
-    // as should all type information in this AppDomain
-    _ASSERTE(!pAppDomain->NoAccessToHandleTable());
-
     // Now it's safe to do the iteration
     IterateDomain(pAppDomain, enumerationOptions);
-
-    // Since we're holding the system domain lock, the AD type info should be
-    // there throughout the entire iteration we just did
-    _ASSERTE(!pAppDomain->NoAccessToHandleTable());
 }
 
 /********************************************************************************/
index 62816eb..9e2e8d0 100644 (file)
@@ -29,8 +29,6 @@ ULONGLONG FinalizerThread::LastHeapDumpTime = 0;
 Volatile<BOOL> g_TriggerHeapDump = FALSE;
 #endif // __linux__
 
-AppDomain * FinalizerThread::UnloadingAppDomain;
-
 CLREvent * FinalizerThread::hEventFinalizer = NULL;
 CLREvent * FinalizerThread::hEventFinalizerDone = NULL;
 CLREvent * FinalizerThread::hEventShutDownToFinalizer = NULL;
@@ -143,7 +141,7 @@ Object * FinalizerThread::DoOneFinalization(Object* fobj, Thread* pThread,int bi
 
     AppDomain* targetAppDomain = fobj->GetAppDomain();
     AppDomain* currentDomain = pThread->GetDomain();
-    if (! targetAppDomain || ! targetAppDomain->CanThreadEnter(pThread))
+    if (! targetAppDomain)
     {
         // if can't get into domain to finalize it, then it must be agile so finalize in current domain
         targetAppDomain = currentDomain;
@@ -151,48 +149,39 @@ Object * FinalizerThread::DoOneFinalization(Object* fobj, Thread* pThread,int bi
 
     if (targetAppDomain == currentDomain)
     {
-        if (!targetAppDomain->IsRudeUnload() ||
-            fobj->GetMethodTable()->HasCriticalFinalizer())
+        class ResetFinalizerStartTime
         {
-            class ResetFinalizerStartTime
+        public:
+            ResetFinalizerStartTime()
             {
-            public:
-                ResetFinalizerStartTime()
+                if (CLRHosted())
                 {
-                    if (CLRHosted())
-                    {
-                        g_ObjFinalizeStartTime = CLRGetTickCount64();
-                    }                    
-                }
-                ~ResetFinalizerStartTime()
-                {
-                    if (g_ObjFinalizeStartTime)
-                    {
-                        g_ObjFinalizeStartTime = 0;
-                    }
-                }
-            };
+                    g_ObjFinalizeStartTime = CLRGetTickCount64();
+                }                    
+            }
+            ~ResetFinalizerStartTime()
             {
-                ThreadLocaleHolder localeHolder;
-
+                if (g_ObjFinalizeStartTime)
                 {
-                    ResetFinalizerStartTime resetTime;
-                    CallFinalizer(fobj);
+                    g_ObjFinalizeStartTime = 0;
                 }
             }
-            pThread->InternalReset(FALSE);
+        };
+        {
+            ThreadLocaleHolder localeHolder;
+
+            {
+                ResetFinalizerStartTime resetTime;
+                CallFinalizer(fobj);
+            }
         }
+        pThread->InternalReset(FALSE);
     } 
     else 
     {
-        if (! targetAppDomain->GetDefaultContext())
-        {
-            // Can no longer enter domain becuase the handle containing the context has been
-            // destroyed so just bail. Should only get this if are at the stage of nuking the
-            // handles in the domain if it's still open.
-            _ASSERTE(targetAppDomain->IsUnloading() && targetAppDomain->ShouldHaveFinalization());
-        }
-        else if (!currentDomain->IsDefaultDomain())
+        _ASSERTE(targetAppDomain->GetDefaultContext());
+
+        if (!currentDomain->IsDefaultDomain())
         {
             // this means we are in some other domain, so need to return back out through the DoADCallback
             // and handle the object from there in another domain.
@@ -239,10 +228,6 @@ Object * FinalizerThread::FinalizeAllObjects(Object* fobj, int bitToCheck)
 
     if (fobj == NULL)
     {
-        if (AppDomain::HasWorkForFinalizerThread())
-        {
-            return NULL;
-        }
         fobj = GCHeapUtilities::GetGCHeap()->GetNextFinalizable();
     }
 
@@ -264,10 +249,6 @@ Object * FinalizerThread::FinalizeAllObjects(Object* fobj, int bitToCheck)
 
         if (fobj->GetHeader()->GetBits() & bitToCheck)
         {
-            if (AppDomain::HasWorkForFinalizerThread())
-            {
-                return NULL;
-            }
             fobj = GCHeapUtilities::GetGCHeap()->GetNextFinalizable();
         }
         else
@@ -281,10 +262,6 @@ Object * FinalizerThread::FinalizeAllObjects(Object* fobj, int bitToCheck)
 
             if (fobj == NULL)
             {
-                if (AppDomain::HasWorkForFinalizerThread())
-                {
-                    return NULL;
-                }
                 fobj = GCHeapUtilities::GetGCHeap()->GetNextFinalizable();
             }
         }
@@ -621,44 +598,9 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args)
             GetFinalizerThread()->EEResetAbort(Thread::TAR_ALL);
         }
         FastInterlockExchange ((LONG*)&g_FinalizerIsRunning, TRUE);
-        AppDomain::EnableADUnloadWorkerForFinalizer();
-
-        do
-        {
-            FinalizeAllObjects(NULL, 0);
-            _ASSERTE(GetFinalizerThread()->GetDomain()->IsDefaultDomain());
 
-            if (AppDomain::HasWorkForFinalizerThread())
-            {
-                AppDomain::ProcessUnloadDomainEventOnFinalizeThread();                
-            }
-            else if (UnloadingAppDomain == NULL)
-                break;
-            else if (!GCHeapUtilities::GetGCHeap()->FinalizeAppDomain(UnloadingAppDomain, !!fRunFinalizersOnUnload))
-            {
-                break;
-            }
-            // Now schedule any objects from an unloading app domain for finalization 
-            // on the next pass (even if they are reachable.)
-            // Note that it may take several passes to complete the unload, if new objects are created during
-            // finalization.
-        }
-        while(TRUE);
-
-        if (UnloadingAppDomain != NULL)
-        {
-            SyncBlockCache::GetSyncBlockCache()->CleanupSyncBlocksInAppDomain(UnloadingAppDomain);
-            {
-                // Before we continue with AD unloading, mark the stage as
-                // FINALIZED under the SystemDomain lock so that this portion
-                // of unloading may be serialized with other parts of the CLR
-                // that require the AD stage to be < FINALIZED, in particular
-                // ETW's AD enumeration code used during its rundown events.
-                SystemDomain::LockHolder lh;
-                UnloadingAppDomain->SetFinalized(); // All finalizers have run except for FinalizableAndAgile objects
-            }
-            UnloadingAppDomain = NULL;
-        }
+        FinalizeAllObjects(NULL, 0);
+        _ASSERTE(GetFinalizerThread()->GetDomain()->IsDefaultDomain());
 
         FastInterlockExchange ((LONG*)&g_FinalizerIsRunning, FALSE);
         // We may still have the finalizer thread for abort.  If so the abort request is for previous finalizer method, not for next one.
@@ -1006,7 +948,7 @@ void FinalizerThread::FinalizerThreadWait(DWORD timeout)
                 if (status == WAIT_TIMEOUT)
                 {
                     ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
-                    if (finalizeStartTime || AppDomain::HasWorkForFinalizerThread())
+                    if (finalizeStartTime)
                     {
                         if (CLRGetTickCount64() >= finalizeStartTime+timeout)
                         {
index be68451..bb1cfe4 100644 (file)
@@ -10,7 +10,6 @@ class FinalizerThread
 {
     static BOOL fRunFinalizersOnUnload;
     static BOOL fQuitFinalizer;
-    static AppDomain *UnloadingAppDomain;
     
 #if defined(__linux__) && defined(FEATURE_EVENT_TRACE)
     static ULONGLONG LastHeapDumpTime;
@@ -60,20 +59,6 @@ public:
         return g_pFinalizerThread;
     }
 
-    // Start unloading app domain
-    static void UnloadAppDomain(AppDomain *pDomain, BOOL fRunFinalizers)
-    {
-        LIMITED_METHOD_CONTRACT;
-        UnloadingAppDomain = pDomain; 
-        fRunFinalizersOnUnload = fRunFinalizers;
-    }
-
-    static AppDomain*  GetUnloadingAppDomain()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return UnloadingAppDomain;
-    }
-
     static BOOL IsCurrentThreadFinalizer();
 
     static void EnableFinalization();
index 3dd22da..34645b3 100644 (file)
@@ -193,9 +193,6 @@ void GCToEEInterface::GcStartWork (int condemned, int max_gen)
     }
     CONTRACTL_END;
 
-    // Update AppDomain stage here.
-    SystemDomain::System()->ProcessClearingDomains();
-
 #ifdef VERIFY_HEAP
     // Validate byrefs pinned by IL stubs since the last GC.
     StubHelpers::ProcessByrefValidationList();
@@ -1450,14 +1447,14 @@ bool GCToEEInterface::AppDomainCanAccessHandleTable(uint32_t appDomainID)
 
     ADIndex index(appDomainID);
     AppDomain *pDomain = SystemDomain::GetAppDomainAtIndex(index);
-    return (pDomain != NULL) && !pDomain->NoAccessToHandleTable();
+    return (pDomain != NULL);
 }
 
 uint32_t GCToEEInterface::GetIndexOfAppDomainBeingUnloaded()
 {
     LIMITED_METHOD_CONTRACT;
 
-    return SystemDomain::IndexOfAppDomainBeingUnloaded().m_dwIndex;
+    return 0xFFFFFFFF;
 }
 
 uint32_t GCToEEInterface::GetTotalNumSizedRefHandles()
@@ -1472,8 +1469,7 @@ bool GCToEEInterface::AppDomainIsRudeUnload(void *appDomain)
 {
     LIMITED_METHOD_CONTRACT;
 
-    AppDomain *realPtr = static_cast<AppDomain *>(appDomain);
-    return realPtr->IsRudeUnload() != FALSE;
+    return false;
 }
 
 bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration)
index 4361778..220445a 100644 (file)
@@ -18,7 +18,6 @@ void ValidateObjectAndAppDomain(OBJECTREF objRef, ADIndex appDomainIndex)
 
     // Access to a handle in an unloaded domain is not allowed
     assert(domain != nullptr);
-    assert(!domain->NoAccessToHandleTable());
 
 #endif // _DEBUG_IMPL
 }
@@ -36,12 +35,6 @@ void ValidateHandleAssignment(OBJECTHANDLE handle, OBJECTREF objRef)
     IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
     ADIndex appDomainIndex = ADIndex(reinterpret_cast<DWORD>(mgr->GetHandleContext(handle)));
 
-    AppDomain *unloadingDomain = SystemDomain::AppDomainBeingUnloaded();
-    if (unloadingDomain && unloadingDomain->GetIndex() == appDomainIndex && unloadingDomain->NoAccessToHandleTable())
-    {
-        _ASSERTE (!"Access to a handle in unloaded domain is not allowed");
-    }
-
     ValidateObjectAndAppDomain(objRef, appDomainIndex);
 #endif // _DEBUG_IMPL
 }
index 70f6e30..e17cec7 100644 (file)
@@ -175,7 +175,7 @@ ASMCONSTANTS_C_ASSERT(CORINFO_ArgumentException_ASM == CORINFO_ArgumentException
 #ifndef CROSSGEN_COMPILE
 
 // from clr/src/vm/threads.h
-#define Thread_m_Context    0x38
+#define Thread_m_Context    0x34
 ASMCONSTANTS_C_ASSERT(Thread_m_Context == offsetof(Thread, m_Context))
 
 #define Thread_m_State      0x04
@@ -193,10 +193,10 @@ ASMCONSTANTS_C_ASSERT(Thread_m_pFrame == offsetof(Thread, m_pFrame))
 #endif // CROSSGEN_COMPILE
 
 #ifndef CROSSGEN_COMPILE
-#define Thread_m_dwLockCount 0x18
+#define Thread_m_dwLockCount 0x14
 ASMCONSTANTS_C_ASSERT(Thread_m_dwLockCount == offsetof(Thread, m_dwLockCount))
 
-#define Thread_m_ThreadId 0x1C
+#define Thread_m_ThreadId 0x18
 ASMCONSTANTS_C_ASSERT(Thread_m_ThreadId == offsetof(Thread, m_ThreadId))
 
 #ifdef FEATURE_HIJACK
@@ -338,7 +338,7 @@ ASMCONSTANTS_C_ASSERT(UMThunkMarshInfo__m_cbRetPop == offsetof(UMThunkMarshInfo,
 #endif //FEATURE_STUBS_AS_IL
 
 #ifndef CROSSGEN_COMPILE
-#define               Thread__m_pDomain                     0x14
+#define               Thread__m_pDomain                     0x10
 ASMCONSTANTS_C_ASSERT(Thread__m_pDomain == offsetof(Thread, m_pDomain));
 
 #endif
index 2052088..09fb502 100644 (file)
@@ -555,28 +555,6 @@ LEAF_ENTRY PrecodeFixupThunk, _TEXT
     jmp     C_FUNC(ThePreStub)
 LEAF_END PrecodeFixupThunk, _TEXT
 
-// void __stdcall UM2MThunk_WrapperHelper(void *pThunkArgs,
-//                                        int argLen,
-//                                        void *pAddr,
-//                                        UMEntryThunk *pEntryThunk,
-//                                        Thread *pThread)
-NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT, NoHandler
-    push    ebx
-
-    mov     eax, [esp + 20] // pEntryThunk
-    mov     ecx, [esp + 24] // pThread
-    mov     ebx, [esp + 8]  // pThunkArgs
-
-    sub     esp, 8
-    CHECK_STACK_ALIGNMENT
-    call    [esp + 16 + 8]      // pAddr
-    add     esp, 8
-
-    pop     ebx
-
-    ret     20
-NESTED_END UM2MThunk_WrapperHelper, _TEXT
-
 NESTED_ENTRY UMThunkStubRareDisable, _TEXT, NoHandler
     push    eax
     push    ecx
index 17d521f..18b5c6e 100644 (file)
@@ -926,31 +926,6 @@ getFPReturn4:
    retn    8
 _getFPReturn@8 endp
 
-; void __stdcall UM2MThunk_WrapperHelper(void *pThunkArgs,
-;                                        int argLen,
-;                                        void *pAddr,
-;                                        UMEntryThunk *pEntryThunk,
-;                                        Thread *pThread)
-UM2MThunk_WrapperHelper proc stdcall public,
-                        pThunkArgs : DWORD,
-                        argLen : DWORD,
-                        pAddr : DWORD,
-                        pEntryThunk : DWORD,
-                        pThread : DWORD
-    UNREFERENCED argLen
-
-    push    ebx
-
-    mov     eax, pEntryThunk
-    mov     ecx, pThread
-    mov     ebx, pThunkArgs
-    call    pAddr
-
-    pop     ebx
-
-    ret
-UM2MThunk_WrapperHelper endp
-
 ; VOID __cdecl UMThunkStubRareDisable()
 ;<TODO>
 ; @todo: this is very similar to StubRareDisable
index 77f0c9e..cb5f817 100644 (file)
@@ -1550,7 +1550,7 @@ BOOL AppDomainLoaderAllocator::CanUnload()
         SO_TOLERANT;
     } CONTRACTL_END;
 
-    return m_Id.GetAppDomain()->CanUnload();
+    return FALSE;
 }
 
 BOOL AssemblyLoaderAllocator::CanUnload()
@@ -1750,7 +1750,6 @@ void AssemblyLoaderAllocator::CleanupHandles()
     CONTRACTL_END;
 
     _ASSERTE(GetDomain()->IsAppDomain());
-    _ASSERTE(!GetDomain()->AsAppDomain()->NoAccessToHandleTable());
 
     // This method doesn't take a lock around RemoveHead because it's supposed to
     // be called only from Terminate
index 133cbf9..2ce0bda 100644 (file)
@@ -2256,13 +2256,10 @@ FCIMPL2(void, MarshalNative::ChangeWrapperHandleStrength, Object* orefUNSAFE, CL
         
         if (pWrap == NULL)
             COMPlusThrowOM();
-        AppDomainFromIDHolder pDomain(pWrap->GetDomainID(), FALSE);
-        pDomain.ThrowIfUnloaded();
         if (fIsWeak != 0)
             pWrap->MarkHandleWeak();
         else
             pWrap->ResetHandleStrength();
-        pDomain.Release();
     }        
 
     HELPER_METHOD_FRAME_END();
index a768ded..53a0be7 100644 (file)
@@ -10075,7 +10075,7 @@ BOOL MethodTable::Validate()
 NOINLINE BYTE *MethodTable::GetLoaderAllocatorObjectForGC()
 {
     WRAPPER_NO_CONTRACT;
-    if (!Collectible() || ((PTR_AppDomain)GetLoaderModule()->GetDomain())->NoAccessToHandleTable())
+    if (!Collectible())
     {
         return NULL;
     }
index 94e61c6..f808496 100644 (file)
@@ -107,7 +107,7 @@ FCIMPL1(LPOVERLAPPED, AllocateNativeOverlapped, OverlappedDataObject* overlapped
         g_pOverlappedDataClass = MscorlibBinder::GetClass(CLASS__OVERLAPPEDDATA);
         // We have optimization to avoid creating event if IO is in default domain.  This depends on default domain 
         // can not be unloaded.
-        _ASSERTE(IsSingleAppDomain() || !SystemDomain::System()->DefaultDomain()->CanUnload());
+        _ASSERTE(IsSingleAppDomain());
         _ASSERTE(SystemDomain::System()->DefaultDomain()->GetId().m_dwId == DefaultADID);
     }
 
index a0427cd..ca54ba2 100644 (file)
@@ -244,12 +244,6 @@ TypeHandle Object::GetGCSafeTypeHandleIfPossible() const
     Module * pLoaderModule = pMTToCheck->GetLoaderModule();
 
     BaseDomain * pBaseDomain = pLoaderModule->GetDomain();
-    if ((pBaseDomain != NULL) && 
-        (pBaseDomain->IsAppDomain()) && 
-        (pBaseDomain->AsAppDomain()->IsUnloading()))
-    {
-        return NULL;
-    }
 
     // Don't look up types that are unloading due to Collectible Assemblies. Haven't been
     // able to find a case where we actually encounter objects like this that can cause
index a6b0a64..b5c1e57 100644 (file)
@@ -177,33 +177,16 @@ HRESULT IterateAppDomains(CallbackObject * callbackObj,
     // AD available in catch-up enumeration
     //     < AppDomainCreationFinished issued
     //     < AD NOT available from catch-up enumeration
-    //     < AppDomainShutdownStarted issued
     //     
     // The AppDomainIterator constructor parameter m_bActive is set to be TRUE below,
-    // meaning only AppDomains in the range [STAGE_ACTIVE;STAGE_CLOSED) will be included
+    // meaning only AppDomains in stage STAGE_ACTIVE or higher will be included
     // in the iteration.
     //     * AppDomainCreationFinished (with S_OK hrStatus) is issued once the AppDomain
     //         reaches STAGE_ACTIVE.
-    //     * AppDomainShutdownStarted is issued while the AppDomain is in STAGE_EXITED,
-    //         just before it hits STAGE_FINALIZING. (STAGE_EXITED < STAGE_CLOSED)
-    //     * To prevent AppDomains from appearing in the enumeration after we would have
-    //         sent the AppDomainShutdownStarted event for them, we must add an
-    //         additional check in the enumeration loop to exclude ADs such that
-    //         pAppDomain->IsUnloading() (i.e., > STAGE_UNLOAD_REQUESTED). Thus, for an
-    //         AD for which AppDomainShutdownStarted callback is issued, we have AD >=
-    //         STAGE_EXITED > STAGE_UNLOAD_REQUESTED, and thus, that AD will be excluded
-    //         by the pAppDomain->IsUnloading() check.
     AppDomainIterator appDomainIterator(TRUE);
     while (appDomainIterator.Next())
     {
         AppDomain * pAppDomain = appDomainIterator.GetDomain();
-        if (pAppDomain->IsUnloading())
-        {
-            // Must skip app domains that are in the process of unloading, to ensure
-            // the rules around which entities the profiler should find in the
-            // enumeration. See code:#ProfilerEnumAppDomains for details.
-            continue;
-        }
 
         // Of course, the AD could start unloading here, but if it does we're guaranteed
         // the profiler has had a chance to see the Unload callback for the AD, and thus
@@ -271,9 +254,6 @@ HRESULT IterateUnsharedModules(AppDomain * pAppDomain,
     //     * AssemblyLoadFinished is issued once the Assembly reaches
     //         code:FILE_LOAD_LOADLIBRARY
     //     * AssemblyUnloadStarted is issued as a result of either:
-    //         * AppDomain unloading. In this case such assemblies / modules would be
-    //             excluded by the AD iterator above, because it excludes ADs if
-    //             pAppDomain->IsUnloading()
     //         * Collectible assemblies unloading. Such assemblies will no longer be
     //             enumerable.
     //
index fd0488c..6663300 100644 (file)
@@ -93,14 +93,6 @@ void SOTolerantCode_RecoverStack(DWORD dwFlags)
         {
             pThread->DisablePreemptiveGC();
         }
-        // PerformADUnloadAction is SO_INTOLERANT, but we might be
-        // calling BEGIN_SO_TOLERANT_CODE from an entry point method
-        BEGIN_CONTRACT_VIOLATION(SOToleranceViolation);
-        BEGIN_GCX_ASSERT_COOP;
-        // We have enough stack now.  Start unload 
-        EEPolicy::PerformADUnloadAction(eRudeUnloadAppDomain, TRUE, TRUE);
-        END_GCX_ASSERT_COOP;
-        END_CONTRACT_VIOLATION;
     }
     COMPlusThrowSO();
 }
index d95adb1..51e4b9d 100644 (file)
@@ -195,11 +195,7 @@ ADID StackSampler::GetDomainId(MethodDesc* pMD, const ADID& defaultId)
     }
     if (bPresent != FALSE)
     {
-        AppDomainFromIDHolder pDomain(adId, FALSE);
-        if (!pDomain.IsUnloaded())
-        {
-            return adId;
-        }
+        return adId;
     }
     return defaultId;
 }
index c33c330..6265751 100644 (file)
@@ -475,11 +475,6 @@ HRESULT __stdcall Unknown_QueryInterface_ICCW(IUnknown *pUnk, REFIID riid, void
         
         SimpleComCallWrapper *pSimpleWrap = pWrap->GetSimpleWrapper();
 
-        AppDomainFromIDHolder ad((ADID)pSimpleWrap->GetRawDomainID(), TRUE);
-
-        if (ad.IsUnloaded() || ad->IsUnloading())
-            return COR_E_APPDOMAINUNLOADED;
-        
         //
         // For CCWs that have outstanding Jupiter-reference, they could be either:
         // 1. Neutered - in this case it is unsafe to touch m_ppThis
index 991b6c6..f72f69d 100644 (file)
@@ -603,22 +603,7 @@ HRESULT CLRTestHookManager::CheckConfig()
 
 HRESULT CLRTestHookManager::UnloadAppDomain(DWORD adid,DWORD flags)
 {
-    HRESULT hr = S_OK;
-    BEGIN_ENTRYPOINT_NOTHROW;
-    // We do not use BEGIN_EXTERNAL_ENTRYPOINT here because
-    // we do not want to setup Thread.  Process may be OOM, and we want Unload
-    // to work.
-    if (flags==ADUF_FORCEFULLGC)
-    {
-        SystemDomain::LockHolder ulh;
-        ADID id(adid);
-        AppDomainFromIDHolder pApp(id,TRUE,AppDomainFromIDHolder::SyncType_ADLock);//, AppDomainFromIDHolder::SyncType_ADLock); 
-        if(!pApp.IsUnloaded())
-            pApp->SetForceGCOnUnload(TRUE);
-    }
-    hr =  AppDomain::UnloadById(ADID(adid), flags!=ADUF_ASYNCHRONOUS,TRUE);
-    END_ENTRYPOINT_NOTHROW;
-    return hr;
+    return COR_E_CANNOTUNLOADAPPDOMAIN;
 }
 
 VOID CLRTestHookManager::DoAppropriateWait( int cObjs, HANDLE *pObjs, INT32 iTimeout, BOOL bWaitAll, int* res)
index ddf31f4..9a0ebdc 100644 (file)
@@ -1350,9 +1350,6 @@ void CheckADValidity(AppDomain* pDomain, DWORD ADValidityKind)
     if ((ADValidityKind &  ADV_FINALIZER) &&
         IsFinalizerThread())
        return;
-    if ((ADValidityKind &  ADV_ADUTHREAD) &&
-        IsADUnloadHelperThread())
-       return;
     if ((ADValidityKind &  ADV_RUNNINGIN) &&
         pDomain->IsRunningIn(GetThread()))
        return;
@@ -1377,7 +1374,6 @@ Thread::Thread()
     CONTRACTL_END;
 
     m_pFrame                = FRAME_TOP;
-    m_pUnloadBoundaryFrame  = NULL;
 
     m_fPreemptiveGCDisabled = 0;
 
@@ -7438,7 +7434,6 @@ VOID Thread::RestoreGuardPage()
     }
 
     FinishSOWork();
-    //GetAppDomain()->EnableADUnloadWorker(EEPolicy::ADU_Rude);
 
     INDEBUG(DebugLogStackMBIs());
 
@@ -7680,8 +7675,7 @@ void MakeCallWithAppDomainTransition(
 
     Thread*     _ctx_trans_pThread          = GetThread();
     TESTHOOKCALL(EnteringAppDomain((TargetDomain.m_dwId)));     
-    AppDomainFromIDHolder pTargetDomain(TargetDomain, TRUE);
-    pTargetDomain.ThrowIfUnloaded();
+    AppDomain* pTargetDomain = SystemDomain::GetAppDomainFromId(TargetDomain, ADV_CURRENTAD);
     _ASSERTE(_ctx_trans_pThread != NULL);
     _ASSERTE(_ctx_trans_pThread->GetDomain()->GetId()!= TargetDomain);
 
@@ -7695,7 +7689,6 @@ void MakeCallWithAppDomainTransition(
         pTargetDomain->GetDefaultContext(),
         _ctx_trans_pFrame);
 
-    pTargetDomain.Release();
     args->pCtxFrame = _ctx_trans_pFrame;
     TESTHOOKCALL(EnteredAppDomain((TargetDomain.m_dwId))); 
     /* work around unreachable code warning */
@@ -7809,11 +7802,8 @@ void Thread::DoContextCallBack(ADID appDomain, Context *pContext, Context::ADCal
     Context*    pCurrDefCtx     = pCurrDomain->GetDefaultContext();
     BOOL  bDefaultTargetCtx=FALSE;
 
-    {
-        AppDomainFromIDHolder ad(appDomain, TRUE);
-        ad.ThrowIfUnloaded();
-        bDefaultTargetCtx=(ad->GetDefaultContext()==pContext);
-    }
+    AppDomain* ad = SystemDomain::GetAppDomainFromId(appDomain, ADV_CURRENTAD);
+    bDefaultTargetCtx=(ad->GetDefaultContext()==pContext);
 
     if (pCurrDefCtx == pThread->GetContext() && bDefaultTargetCtx)
     {
@@ -7828,156 +7818,6 @@ void Thread::DoContextCallBack(ADID appDomain, Context *pContext, Context::ADCal
     LOG((LF_APPDOMAIN, LL_INFO100, "Thread::DoADCallBack Done at esp %p\n", espVal));
 }
 
-
-void Thread::DoADCallBack(AppDomain* pDomain , Context::ADCallBackFcnType pTarget, LPVOID args, DWORD dwADV,
-                          BOOL fSetupEHAtTransition /* = TRUE */)
-{
-
-
-#ifdef _DEBUG
-    TADDR espVal = (TADDR)GetCurrentSP();
-
-    LOG((LF_APPDOMAIN, LL_INFO100, "Thread::DoADCallBack Calling %p at esp %p in [%d]\n",
-            pTarget, espVal, pDomain->GetId().m_dwId));
-#endif
-    Thread* pThread  = GetThread();
-
-    // Get the default context for the current domain as well as for the
-    // destination domain.
-    AppDomain*  pCurrDomain     = pThread->GetContext()->GetDomain();
-
-    if (pCurrDomain!=pDomain)
-    {
-        // use the target domain's default context as the target context
-        // so that the actual call to a transparent proxy would enter the object into the correct context.
-
-        BOOL fThrow = FALSE;
-
-#ifdef FEATURE_PAL
-        // FEATURE_PAL must setup EH at AD transition - the option to omit the setup
-        // is only for regular Windows builds. 
-        _ASSERTE(fSetupEHAtTransition);
-#endif // FEATURE_PAL
-        
-        LOG((LF_APPDOMAIN, LL_INFO10, "Thread::DoADCallBack - performing AD transition with%s EH at transition boundary.\n",
-            (fSetupEHAtTransition == FALSE)?"out":""));
-
-        if (fSetupEHAtTransition)
-        {
-            ENTER_DOMAIN_PTR(pDomain,dwADV)
-            {
-                (pTarget)(args);
-
-                // unloadBoundary is cleared by ReturnToContext, so get it now.
-                Frame* unloadBoundaryFrame = pThread->GetUnloadBoundaryFrame();
-                fThrow = pThread->ShouldChangeAbortToUnload(GET_CTX_TRANSITION_FRAME(), unloadBoundaryFrame);
-            }
-            END_DOMAIN_TRANSITION;
-        }
-#ifndef FEATURE_PAL
-        else
-        {
-            ENTER_DOMAIN_PTR_NO_EH_AT_TRANSITION(pDomain,dwADV)
-            {
-                (pTarget)(args);
-
-                // unloadBoundary is cleared by ReturnToContext, so get it now.
-                Frame* unloadBoundaryFrame = pThread->GetUnloadBoundaryFrame();
-                fThrow = pThread->ShouldChangeAbortToUnload(GET_CTX_TRANSITION_FRAME(), unloadBoundaryFrame);
-            }
-            END_DOMAIN_TRANSITION_NO_EH_AT_TRANSITION;
-        }
-#endif // !FEATURE_PAL
-
-        // if someone caught the abort before it got back out to the AD transition (like DispatchEx_xxx does)
-        // then need to turn the abort into an unload, as they're gonna keep seeing it anyway
-        if (fThrow)
-        {
-            LOG((LF_APPDOMAIN, LL_INFO10, "Thread::DoADCallBack turning abort into unload\n"));
-            COMPlusThrow(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
-        }
-    }
-    else
-    {
-        UNREACHABLE();
-    }
-    LOG((LF_APPDOMAIN, LL_INFO100, "Thread::DoADCallBack Done at esp %p\n", espVal));
-}
-
-void Thread::DoADCallBack(ADID appDomainID , Context::ADCallBackFcnType pTarget, LPVOID args, BOOL fSetupEHAtTransition /* = TRUE */)
-{
-
-
-#ifdef _DEBUG
-    TADDR espVal = (TADDR)GetCurrentSP();
-
-    LOG((LF_APPDOMAIN, LL_INFO100, "Thread::DoADCallBack Calling %p at esp %p in [%d]\n",
-            pTarget, espVal, appDomainID.m_dwId));
-#endif
-    Thread* pThread  = GetThread();
-
-    // Get the default context for the current domain as well as for the
-    // destination domain.
-    AppDomain*  pCurrDomain     = pThread->GetContext()->GetDomain();
-
-    if (pCurrDomain->GetId()!=appDomainID)
-    {
-        // use the target domain's default context as the target context
-        // so that the actual call to a transparent proxy would enter the object into the correct context.
-
-        BOOL fThrow = FALSE;
-
-#ifdef FEATURE_PAL
-        // FEATURE_PAL must setup EH at AD transition - the option to omit the setup
-        // is only for regular Windows builds. 
-        _ASSERTE(fSetupEHAtTransition);
-#endif // FEATURE_PAL
-
-        LOG((LF_APPDOMAIN, LL_INFO10, "Thread::DoADCallBack - performing AD transition with%s EH at transition boundary.\n",
-            (fSetupEHAtTransition == FALSE)?"out":""));
-
-        if (fSetupEHAtTransition)
-        {
-            ENTER_DOMAIN_ID(appDomainID)
-            {
-                (pTarget)(args);
-
-                // unloadBoundary is cleared by ReturnToContext, so get it now.
-                Frame* unloadBoundaryFrame = pThread->GetUnloadBoundaryFrame();
-                fThrow = pThread->ShouldChangeAbortToUnload(GET_CTX_TRANSITION_FRAME(), unloadBoundaryFrame);
-            }
-            END_DOMAIN_TRANSITION;
-        }
-#ifndef FEATURE_PAL
-        else
-        {
-            ENTER_DOMAIN_ID_NO_EH_AT_TRANSITION(appDomainID)
-            {
-                (pTarget)(args);
-
-                // unloadBoundary is cleared by ReturnToContext, so get it now.
-                Frame* unloadBoundaryFrame = pThread->GetUnloadBoundaryFrame();
-                fThrow = pThread->ShouldChangeAbortToUnload(GET_CTX_TRANSITION_FRAME(), unloadBoundaryFrame);
-            }
-            END_DOMAIN_TRANSITION_NO_EH_AT_TRANSITION;
-        }
-#endif // !FEATURE_PAL
-
-        // if someone caught the abort before it got back out to the AD transition (like DispatchEx_xxx does)
-        // then need to turn the abort into an unload, as they're gonna keep seeing it anyway
-        if (fThrow)
-        {
-            LOG((LF_APPDOMAIN, LL_INFO10, "Thread::DoADCallBack turning abort into unload\n"));
-            COMPlusThrow(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
-        }
-    }
-    else
-    {
-        UNREACHABLE();
-    }
-    LOG((LF_APPDOMAIN, LL_INFO100, "Thread::DoADCallBack Done at esp %p\n", espVal));
-}
-
 void Thread::EnterContextRestricted(Context *pContext, ContextTransitionFrame *pFrame)
 {
     CONTRACTL {
@@ -7996,12 +7836,6 @@ void Thread::EnterContextRestricted(Context *pContext, ContextTransitionFrame *p
     // and it should always have an AD set
     _ASSERTE(pDomain);
 
-    if (m_pDomain != pDomain && !pDomain->CanThreadEnter(this))
-    {
-        pFrame->SetReturnContext(NULL);
-        COMPlusThrow(kAppDomainUnloadedException);
-    }
-
     pFrame->SetReturnContext(m_Context);
     pFrame->SetReturnExecutionContext(NULL);
 
@@ -8147,18 +7981,6 @@ void Thread::ReturnToContext(ContextTransitionFrame *pFrame)
             EPolicyAction action = GetEEPolicy()->GetActionOnFailure(FAIL_OrphanedLock);
             switch (action)
             {
-            case eUnloadAppDomain:
-                if (!pFromDomain->IsDefaultDomain())
-                {
-                    pFromDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                }
-                break;
-            case eRudeUnloadAppDomain:
-                if (!pFromDomain->IsDefaultDomain())
-                {
-                    pFromDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-                break;
             case eExitProcess:
             case eFastExitProcess:
             case eRudeExitProcess:
@@ -8222,16 +8044,6 @@ void Thread::ReturnToContext(ContextTransitionFrame *pFrame)
         m_pDomain = pReturnDomain;
         SetAppDomain(pReturnDomain);
 
-        if (pFrame == m_pUnloadBoundaryFrame)
-        {
-                m_pUnloadBoundaryFrame = NULL;      
-            if (IsAbortRequested())
-            {
-                EEResetAbort(TAR_ADUnload);
-            }
-            ResetBeginAbortedForADUnload();
-        }
-
         // Restore the last thrown object to what it was before the AD transition. Note that if
         // an exception was thrown out of the AD we transitionned into, it will be raised in
         // RaiseCrossContextException and the EH system will store it as the last thrown 
@@ -8265,18 +8077,6 @@ void Thread::ReturnToContext(ContextTransitionFrame *pFrame)
         // _ASSERTE (action == eThrowException || !pReturnDomain->IsDefaultDomain());
         switch (action)
         {
-        case eUnloadAppDomain:
-            if (!pReturnDomain->IsDefaultDomain())
-            {
-                pReturnDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-            }
-            break;
-        case eRudeUnloadAppDomain:
-            if (!pReturnDomain->IsDefaultDomain())
-            {
-                pReturnDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-            }
-            break;
         case eExitProcess:
         case eFastExitProcess:
         case eRudeExitProcess:
@@ -8483,64 +8283,6 @@ AppDomain *Thread::GetInitialDomain()
     return pDomain;
 }
 
-#ifndef DACCESS_COMPILE
-void  Thread::SetUnloadBoundaryFrame(Frame *pFrame)
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE((this == GetThread() && PreemptiveGCDisabled()) ||
-             ThreadStore::HoldingThreadStore());
-    if ((ULONG_PTR)m_pUnloadBoundaryFrame < (ULONG_PTR)pFrame)
-    {
-        m_pUnloadBoundaryFrame = pFrame;
-    }
-    if (pFrame == NULL)
-    {
-        ResetBeginAbortedForADUnload();
-    }
-}
-
-void  Thread::ResetUnloadBoundaryFrame()
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE(this == GetThread() && PreemptiveGCDisabled());
-    m_pUnloadBoundaryFrame=NULL;
-    ResetBeginAbortedForADUnload();
-}
-
-#endif
-
-BOOL Thread::ShouldChangeAbortToUnload(Frame *pFrame, Frame *pUnloadBoundaryFrame)
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-    }
-    CONTRACTL_END;
-
-    if (! pUnloadBoundaryFrame)
-        pUnloadBoundaryFrame = GetUnloadBoundaryFrame();
-
-    // turn the abort request into an AD unloaded exception when go past the boundary.
-    if (pFrame != pUnloadBoundaryFrame)
-        return FALSE;
-
-    // Only time have an unloadboundaryframe is when have specifically marked that thread for aborting
-    // during unload processing, so this won't trigger UnloadedException if have simply thrown a ThreadAbort
-    // past an AD transition frame
-    _ASSERTE (IsAbortRequested());
-
-    EEResetAbort(TAR_ADUnload);
-
-    if (m_AbortType == EEPolicy::TA_None)
-    {
-        return TRUE;
-    }
-    else
-    {
-        return FALSE;
-    }
-}
-
 BOOL Thread::HaveExtraWorkForFinalizer()
 {
     LIMITED_METHOD_CONTRACT;
@@ -8550,7 +8292,6 @@ BOOL Thread::HaveExtraWorkForFinalizer()
         || ExecutionManager::IsCacheCleanupRequired()
         || Thread::CleanupNeededForFinalizedThread()
         || (m_DetachCount > 0)
-        || AppDomain::HasWorkForFinalizerThread()
         || SystemDomain::System()->RequireAppDomainCleanup()
         || ThreadStore::s_pThreadStore->ShouldTriggerGCForDeadThreads();
 }
@@ -8573,11 +8314,6 @@ void Thread::DoExtraWorkForFinalizer()
     }
 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
 
-    if (AppDomain::HasWorkForFinalizerThread())
-    {
-        AppDomain::ProcessUnloadDomainEventOnFinalizeThread();
-    }
-
     if (RequireSyncBlockCleanup())
     {
 #ifndef FEATURE_PAL
@@ -8592,7 +8328,7 @@ void Thread::DoExtraWorkForFinalizer()
     }
     if (SystemDomain::System()->RequireAppDomainCleanup())
     {
-        SystemDomain::System()->ProcessDelayedUnloadDomains();
+        SystemDomain::System()->ProcessDelayedUnloadLoaderAllocators();
     }
 
     if(m_DetachCount > 0 || Thread::CleanupNeededForFinalizedThread())
@@ -8766,46 +8502,6 @@ protected:
 
 static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState);
 
-
-// Here's the tricky part.  *IF and only IF* we took an AppDomain transition at the base, then we
-// now want to push another complete set of handlers above us.  The reason is that we want the
-// Watson report and the unhandled exception event to occur in the target AppDomain.  If we don't
-// do this apparently redundant push of handlers, then we will marshal back the exception to the
-// handlers on the Default AppDomain side.  This will erase all the important exception state by
-// unwinding (catch and rethrow) in DoADCallBack.  And it will cause all unhandled exceptions to
-// be reported from the Default AppDomain, which is annoying to any AppDomain.UnhandledException
-// event listeners.
-//
-// So why not skip the handlers that are in the Default AppDomain and just push the ones after the
-// transition?  Well, transitioning out of the Default AppDomain into the target AppDomain could
-// fail.  We need handlers pushed for that case.  And in that case it's perfectly reasonable to
-// report the problem as occurring in the Default AppDomain, which is what the base handlers will
-// do.
-
-static void ManagedThreadBase_DispatchInCorrectAD(LPVOID args)
-{
-    CONTRACTL
-    {
-        GC_TRIGGERS;
-        THROWS;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-
-    ManagedThreadCallState *pCallState = (ManagedThreadCallState *) args;
-
-    // Ensure we aren't going to infinitely recurse.
-    _ASSERTE(pCallState->IsAppDomainEqual(GetThread()->GetDomain()));
-
-    // And then go round one more time.  But this time we want to ensure that the filter contains
-    // any exceptions that aren't swallowed.  These must be treated as unhandled, rather than
-    // propagated through the AppDomain boundary in search of an outer handler.  Otherwise we
-    // will not get correct Watson behavior.
-    pCallState->flags = MTCSF_ContainToAppDomain;
-    ManagedThreadBase_DispatchOuter(pCallState);
-    pCallState->flags = MTCSF_NormalBase;
-}
-
 static void ManagedThreadBase_DispatchInner(ManagedThreadCallState *pCallState)
 {
     CONTRACTL
@@ -8816,41 +8512,8 @@ static void ManagedThreadBase_DispatchInner(ManagedThreadCallState *pCallState)
     }
     CONTRACTL_END;
 
-
-    Thread *pThread = GetThread();
-
-    if (!pCallState->IsAppDomainEqual(pThread->GetDomain()))
-    {
-        // On Win7 and later, AppDomain transitions at the threadbase will *not* have EH setup at transition boundary.
-        // This implies that an unhandled exception from the base domain (i.e. AD in which the thread starts) will
-        // not return to DefDomain but will continue to go up the stack with the thread still being in base domain.
-        // We have a holder in ENTER_DOMAIN_*_NO_EH_AT_TRANSITION macro (ReturnToPreviousAppDomainHolder) that will
-        // revert AD context at threadbase if an unwind is triggered after the exception has gone unhandled.
-        //
-        // This also implies that there will be no exception object marshalling (and it may not be required after all) 
-        // as well and once the holder reverts the AD context, the LastThrownObject in Thread will be set to NULL.
-#ifndef FEATURE_PAL
-        BOOL fSetupEHAtTransition = FALSE;
-#else // !FEATURE_PAL
-        BOOL fSetupEHAtTransition = TRUE;
-#endif // !FEATURE_PAL
-
-        if (pCallState->bDomainIsAsID)
-            pThread->DoADCallBack(pCallState->pAppDomainId,
-                              ManagedThreadBase_DispatchInCorrectAD,
-                              pCallState, fSetupEHAtTransition);
-        else
-            pThread->DoADCallBack(pCallState->pUnsafeAppDomain,
-                              ManagedThreadBase_DispatchInCorrectAD,
-                               pCallState, ADV_FINALIZER, fSetupEHAtTransition);
-    }
-    else
-    {
-        // Since no AppDomain transition is necessary, we need no additional handlers pushed
-        // *AFTER* the transition.  We now have adequate handlers below us.  Go ahead and
-        // dispatch the call.
-        (*pCallState->pTarget) (pCallState->args);
-    }
+    // Go ahead and dispatch the call.
+    (*pCallState->pTarget) (pCallState->args);
 }
 
 static void ManagedThreadBase_DispatchMiddle(ManagedThreadCallState *pCallState)
@@ -10758,10 +10421,6 @@ ETaskType GetCurrentTaskType()
     {
         TaskType = TT_THREADPOOL_WAIT;
     }
-    else if (type & ThreadType_ADUnloadHelper)
-    {
-        TaskType = TT_ADUNLOAD;
-    }
     else if (type & ThreadType_Threadpool_IOCompletion)
     {
         TaskType = TT_THREADPOOL_IOCOMPLETION;
index e4b6487..dc46863 100644 (file)
@@ -448,8 +448,6 @@ inline void CommonTripThread() { }
 #define ADV_COMPILATION  0x10
 // finalizer thread - synchronized with ADU
 #define ADV_FINALIZER     0x40
-// adu thread - cannot race with itself
-#define ADV_ADUTHREAD   0x80
 // held by AppDomainRefTaker
 #define ADV_REFTAKER    0x100
 
@@ -1586,7 +1584,6 @@ public:
     Volatile<ULONG>      m_fPreemptiveGCDisabled;
 
     PTR_Frame            m_pFrame;  // The Current Frame
-    PTR_Frame            m_pUnloadBoundaryFrame;
 
     //-----------------------------------------------------------
     // If the thread has wandered in from the outside this is
@@ -2012,17 +2009,6 @@ public:
 
     bool DetectHandleILStubsForDebugger();
 
-#ifndef DACCESS_COMPILE
-    void  SetUnloadBoundaryFrame(Frame *pFrame);
-    void  ResetUnloadBoundaryFrame();
-#endif
-
-    PTR_Frame GetUnloadBoundaryFrame()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return m_pUnloadBoundaryFrame;
-    }
-
     void SetWin32FaultAddress(DWORD eip)
     {
         LIMITED_METHOD_CONTRACT;
@@ -2441,14 +2427,6 @@ public:
         return m_Context;
     }
 
-
-    // This callback is used when we are executing in the EE and discover that we need
-    // to switch appdomains.
-    //
-    // Set the last parameter to FALSE if you want to perform the AD transition *without*
-    // EH (this can affect marshalling of exceptions).
-    void DoADCallBack(ADID appDomain , Context::ADCallBackFcnType pTarget, LPVOID args, BOOL fSetupEHAtTransition = TRUE);
-    void DoADCallBack(AppDomain* pDomain , Context::ADCallBackFcnType pTarget, LPVOID args, DWORD dwADV, BOOL fSetupEHAtTransition = TRUE);
     void DoContextCallBack(ADID appDomain, Context* c , Context::ADCallBackFcnType pTarget, LPVOID args);
 
     // Except for security and the call in from the remoting code in mscorlib, you should never do an
@@ -2544,8 +2522,6 @@ public:
     Frame *IsRunningIn(AppDomain* pDomain, int *count);
     Frame *GetFirstTransitionInto(AppDomain *pDomain, int *count);
 
-    BOOL ShouldChangeAbortToUnload(Frame *pFrame, Frame *pUnloadBoundaryFrame=NULL);
-
     // Get outermost (oldest) AppDomain for this thread.
     AppDomain *GetInitialDomain();
 
@@ -2806,7 +2782,6 @@ public:
     enum ThreadAbortRequester
     {
         TAR_Thread =      0x00000001,   // Request by Thread
-        TAR_ADUnload =    0x00000002,   // Request by AD unload
         TAR_FuncEval =    0x00000004,   // Request by Func-Eval
         TAR_StackOverflow = 0x00000008,   // Request by StackOverflow.  TAR_THREAD should be set at the same time.
         TAR_ALL = 0xFFFFFFFF,
@@ -2828,7 +2803,6 @@ private:
         TAI_FuncEvalAbort     = 0x00000040,
         TAI_FuncEvalV1Abort   = 0x00000080,
         TAI_FuncEvalRudeAbort = 0x00000100,
-        TAI_ForADUnloadThread = 0x10000000,     // AD unload thread is working on the thread
     };
 
     static const DWORD TAI_AnySafeAbort = (TAI_ThreadAbort   |
@@ -2887,14 +2861,6 @@ private:
 
     typedef Holder<Thread*, Thread::AcquireAbortControl, Thread::ReleaseAbortControl> AbortControlHolder;
 
-    BOOL IsBeingAbortedForADUnload()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return (m_AbortInfo & TAI_ForADUnloadThread) != 0;
-    }
-
-    void ResetBeginAbortedForADUnload();
-
 public:
 #ifdef _DEBUG
     BOOL           m_fRudeAborted;
@@ -2965,8 +2931,6 @@ public:
     }
 
     BOOL           IsRudeAbort();
-    BOOL           IsRudeAbortOnlyForADUnload();
-    BOOL           IsRudeUnload();
     BOOL           IsFuncEvalAbort();
 
 #if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
@@ -6974,19 +6938,16 @@ private:
 #define ENTER_DOMAIN_SWITCH_CTX_BY_ADID(_pCurrDomainPtr,_pDestDomainId,_bUnsafePoint)           \
     AppDomain* _ctx_trans_pCurrDomain=_pCurrDomainPtr;                                          \
     _ctx_trans_pDestDomainId=(ADID)_pDestDomainId;                                               \
-    BOOL _ctx_trans_bUnsafePoint=_bUnsafePoint;                                                 \
     if (_ctx_trans_fPredicate &&                                                                \
         (_ctx_trans_pCurrDomain==NULL ||                                                        \
             (_ctx_trans_pCurrDomain->GetId() != _ctx_trans_pDestDomainId)))                     \
     {                                                                                           \
-        AppDomainFromIDHolder _ctx_trans_ad(_ctx_trans_pDestDomainId,_ctx_trans_bUnsafePoint);  \
-        _ctx_trans_ad.ThrowIfUnloaded();                                                        \
+        AppDomain* _ctx_trans_ad = SystemDomain::GetAppDomainFromId(_ctx_trans_pDestDomainId, ADV_CURRENTAD); \
                                                                                                 \
         _ctx_trans_ad->EnterContext(_ctx_trans_pThread,                                         \
             _ctx_trans_ad->GetDefaultContext(),                                                 \
             _ctx_trans_pFrame);                                                                 \
                                                                                                 \
-        _ctx_trans_ad.Release();                                                                \
         _ctx_trans_fTransitioned = true;                                                        \
     }
 
@@ -6999,8 +6960,6 @@ private:
     {                                                                                           \
         TESTHOOKCALL(AppDomainCanBeUnloaded(_ctx_trans_pDestDomain->GetId().m_dwId,FALSE));        \
         GCX_FORBID();                                                                           \
-        if (!_ctx_trans_pDestDomain->CanThreadEnter(_ctx_trans_pThread))                        \
-            COMPlusThrow(kAppDomainUnloadedException);                                          \
                                                                                                 \
         _ctx_trans_pThread->EnterContextRestricted(                                             \
             _ctx_trans_pDestDomain->GetDefaultContext(),                                                                 \
@@ -7089,8 +7048,6 @@ private:
 #define ADV_COMPILATION  0x10
 // finalizer thread - synchronized with ADU
 #define ADV_FINALIZER     0x40
-// adu thread - cannot race with itself
-#define ADV_ADUTHREAD   0x80
 // held by AppDomainRefTaker
 #define ADV_REFTAKER    0x100
 
index f5a439c..1c07070 100644 (file)
@@ -46,14 +46,14 @@ inline void Thread::IncLockCount()
     LIMITED_METHOD_CONTRACT;
     _ASSERTE(GetThread() == this);
     m_dwLockCount++;
-    _ASSERTE(m_dwLockCount != 0 || HasThreadStateNC(TSNC_UnbalancedLocks) || GetDomain()->OkToIgnoreOrphanedLocks());
+    _ASSERTE(m_dwLockCount != 0 || HasThreadStateNC(TSNC_UnbalancedLocks));
 }
 
 inline void Thread::DecLockCount()
 {
     LIMITED_METHOD_CONTRACT;
     _ASSERTE(GetThread() == this);
-    _ASSERTE(m_dwLockCount > 0 || HasThreadStateNC(TSNC_UnbalancedLocks) || GetDomain()->OkToIgnoreOrphanedLocks());
+    _ASSERTE(m_dwLockCount > 0 || HasThreadStateNC(TSNC_UnbalancedLocks));
     m_dwLockCount--;
 }
 
@@ -167,8 +167,6 @@ inline void Thread::FinishSOWork()
     if (HasThreadStateNC(TSNC_SOWorkNeeded))
     {
         ResetThreadStateNC(TSNC_SOWorkNeeded);
-        // Wake up AD unload thread to finish SO work that is delayed due to limit stack
-        AppDomain::EnableADUnloadWorkerForThreadAbort();
     }
 #else
     _ASSERTE(!HasThreadStateNC(TSNC_SOWorkNeeded));
index 6c761f3..abf9597 100644 (file)
@@ -639,13 +639,7 @@ void Thread::ClearAbortReason(BOOL pNoLock)
 
     // If there is an OBJECTHANDLE, try to clear it.
     if (oh != 0 && adid.m_dwId != 0)
-    {   // See if the domain is still valid; if so, destroy the ObjectHandle
-        AppDomainFromIDHolder ad(adid, TRUE);
-        if (!ad.IsUnloaded())
-        {   // Still a valid domain, so destroy the handle.
-            DestroyHandle(oh);
-        }
-    }
+        DestroyHandle(oh);
 }
 
 
@@ -1272,31 +1266,6 @@ BOOL Thread::IsRudeAbort()
     return (IsAbortRequested() && (m_AbortType == EEPolicy::TA_Rude));
 }
 
-BOOL Thread::IsRudeAbortOnlyForADUnload()
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-    }
-    CONTRACTL_END;
-
-    return (IsAbortRequested() &&
-            (m_AbortInfo & TAI_ADUnloadRudeAbort) &&
-            !(m_AbortInfo & (TAI_ThreadRudeAbort | TAI_FuncEvalRudeAbort))
-           );
-}
-
-BOOL Thread::IsRudeUnload()
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-    }
-    CONTRACTL_END;
-
-    return (IsAbortRequested() && (m_AbortInfo & TAI_ADUnloadRudeAbort));
-}
-
 BOOL Thread::IsFuncEvalAbort()
 {
     CONTRACTL {
@@ -1451,33 +1420,7 @@ Thread::UserAbort(ThreadAbortRequester requester,
             GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
             break;
         case eUnloadAppDomain:
-            {
-                AppDomain *pDomain = GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                }
-            }
-            // AD unload does not abort finalizer thread.
-            if (this != FinalizerThread::GetFinalizerThread())
-            {
-                if (this == GetThread())
-                {
-                    Join(INFINITE,TRUE);
-                }
-                return S_OK;
-            }
-            break;
         case eRudeUnloadAppDomain:
-            {
-                AppDomain *pDomain = GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-            }
             // AD unload does not abort finalizer thread.
             if (this != FinalizerThread::GetFinalizerThread())
             {
@@ -1545,13 +1488,6 @@ Thread::UserAbort(ThreadAbortRequester requester,
         m_dwAbortPoint = 1;
 #endif
 
-        if (CLRHosted() && GetAbortEndTime() != MAXULONGLONG)
-        {
-            // ToDo: Skip debugger funcval
-            // Use our helper thread to watch abort.
-            AppDomain::EnableADUnloadWorkerForThreadAbort();
-        }
-
         GCX_COOP();
 
         OBJECTREF exceptObj;
@@ -1583,7 +1519,6 @@ Thread::UserAbort(ThreadAbortRequester requester,
     {
         // A host may call ICLRTask::Abort on a critical thread.  We don't want to
         // block this thread.
-        AppDomain::EnableADUnloadWorkerForThreadAbort();
         return S_OK;
     }
 
@@ -2120,14 +2055,6 @@ LPrepareRetry:
                 SetRudeAbortEndTimeFromEEPolicy();
                 goto LRetry;
             case eUnloadAppDomain:
-                {
-                    AppDomain *pDomain = GetDomain();
-                    if (!pDomain->IsDefaultDomain())
-                    {
-                        GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
-                        pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                    }
-                }
                 // AD unload does not abort finalizer thread.
                 if (this == FinalizerThread::GetFinalizerThread())
                 {
@@ -2146,14 +2073,6 @@ LPrepareRetry:
                 }
                 break;
             case eRudeUnloadAppDomain:
-                {
-                    AppDomain *pDomain = GetDomain();
-                    if (!pDomain->IsDefaultDomain())
-                    {
-                        GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
-                        pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                    }
-                }
                 // AD unload does not abort finalizer thread.
                 if (this == FinalizerThread::GetFinalizerThread())
                 {
@@ -2285,26 +2204,6 @@ void Thread::ThreadAbortWatchDogEscalate(Thread *pThread)
             GetEEPolicy()->NotifyHostOnTimeout(operation,action);
             pThread->UserAbort(Thread::TAR_Thread, EEPolicy::TA_Rude, INFINITE, Thread::UAC_WatchDog);
             break;
-        case eUnloadAppDomain:
-            {
-                AppDomain *pDomain = pThread->GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                }
-            }
-            break;
-        case eRudeUnloadAppDomain:
-            {
-                AppDomain *pDomain = pThread->GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-            }
-            break;
         case eExitProcess:
         case eFastExitProcess:
         case eRudeExitProcess:
@@ -2463,26 +2362,6 @@ void Thread::MarkThreadForAbort(ThreadAbortRequester requester, EEPolicy::Thread
         }
     }
 
-    if (requester & TAR_ADUnload)
-    {
-        if (abortType == EEPolicy::TA_Safe)
-        {
-            abortInfo |= TAI_ADUnloadAbort;
-        }
-        else if (abortType == EEPolicy::TA_Rude)
-        {
-            abortInfo |= TAI_ADUnloadRudeAbort;
-        }
-        else if (abortType == EEPolicy::TA_V1Compatible)
-        {
-            abortInfo |= TAI_ADUnloadV1Abort;
-        }
-        if (IsADUnloadHelperThread())
-        {
-            abortInfo |= TAI_ForADUnloadThread;
-        }
-    }
-
     if (requester & TAR_FuncEval)
     {
         if (abortType == EEPolicy::TA_Safe)
@@ -2534,14 +2413,8 @@ void Thread::MarkThreadForAbort(ThreadAbortRequester requester, EEPolicy::Thread
             {
                 m_RudeAbortEndTime = endTime;
             }
-            // We can not call into host if we are in the middle of stack overflow.
-            // And we don't need to wake up our watchdog if there is no timeout.
-            if (GetThread() == this && (requester & TAR_StackOverflow) == 0)
-        {
-            AppDomain::EnableADUnloadWorkerForThreadAbort();
         }
     }
-    }
 
     if (abortInfo == (m_AbortInfo & abortInfo))
     {
@@ -2658,13 +2531,6 @@ void Thread::UnmarkThreadForAbort(ThreadAbortRequester requester, BOOL fForce)
         }
     }
 
-    if (requester & TAR_ADUnload)
-    {
-        m_AbortInfo &= ~(TAI_ADUnloadAbort   |
-                         TAI_ADUnloadV1Abort |
-                         TAI_ADUnloadRudeAbort);
-    }
-
     if (requester & TAR_FuncEval)
     {
         m_AbortInfo &= ~(TAI_FuncEvalAbort   |
@@ -2718,21 +2584,6 @@ void Thread::UnmarkThreadForAbort(ThreadAbortRequester requester, BOOL fForce)
     STRESS_LOG3(LF_APPDOMAIN, LL_ALWAYS, "Unmark Thread %p Thread Id = %x for abort from requester %d\n", this, GetThreadId(), requester);
 }
 
-// Make sure that when AbortRequest bit is cleared, we also dec TrapReturningThreads count.
-void Thread::ResetBeginAbortedForADUnload()
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_NOTRIGGER;
-    }
-    CONTRACTL_END;
-
-    AbortRequestLockHolder lh(this);
-
-    m_AbortInfo &= ~TAI_ForADUnloadThread;
-}
-
 void Thread::InternalResetAbort(ThreadAbortRequester requester, BOOL fResetRudeAbort)
 {
     CONTRACTL {
@@ -2762,7 +2613,7 @@ void Thread::SetAbortRequest(EEPolicy::ThreadAbortTypes abortType)
     }
     CONTRACTL_END;
 
-    MarkThreadForAbort(TAR_ADUnload, abortType);
+    MarkThreadForAbort(TAR_Thread, abortType);
 
     if (m_State & TS_Interruptible)
     {
@@ -3212,26 +3063,6 @@ void Thread::HandleThreadAbortTimeout()
             GetEEPolicy()->NotifyHostOnTimeout(operation,action);
             MarkThreadForAbort(TAR_Thread, EEPolicy::TA_Rude);
             break;
-        case eUnloadAppDomain:
-            {
-                AppDomain *pDomain = GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
-                }
-            }
-            break;
-        case eRudeUnloadAppDomain:
-            {
-                AppDomain *pDomain = GetDomain();
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnTimeout(operation,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-            }
-            break;
         case eExitProcess:
         case eFastExitProcess:
         case eRudeExitProcess:
@@ -3345,13 +3176,6 @@ void Thread::PreWorkForThreadAbort()
             EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ThreadRudeAbortInCriticalRegion, this);
             switch (action)
             {
-            case eRudeUnloadAppDomain:
-                if (!pDomain->IsDefaultDomain())
-                {
-                    GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ThreadRudeAbortInCriticalRegion,action);
-                    pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
-                }
-                break;
             case eExitProcess:
             case eFastExitProcess:
             case eRudeExitProcess:
index 2a3a3bb..ddbd34a 100644 (file)
@@ -476,10 +476,7 @@ private:
 
                 {
                     GCX_COOP();
-                    AppDomainFromIDHolder ad(pDelegate->m_appDomainId, TRUE);
-                    if (!ad.IsUnloaded())
-                        // if no domain then handle already gone or about to go.
-                        StoreObjectInHandle(pDelegate->m_registeredWaitHandle, NULL);
+                    StoreObjectInHandle(pDelegate->m_registeredWaitHandle, NULL);
                 }
             }