diff options
59 files changed, 139 insertions, 4326 deletions
diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp index a28adace88..942ac3db0c 100644 --- a/src/classlibnative/bcltype/system.cpp +++ b/src/classlibnative/bcltype/system.cpp @@ -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 diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp index bed03ad6c9..57f9f6be39 100644 --- a/src/debug/daccess/dacdbiimpl.cpp +++ b/src/debug/daccess/dacdbiimpl.cpp @@ -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); diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 839ed794b6..a2148b7cc7 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -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); diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h index cf31bc575f..58c3113cd3 100644 --- a/src/inc/clrconfigvalues.h +++ b/src/inc/clrconfigvalues.h @@ -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.") diff --git a/src/inc/utilcode.h b/src/inc/utilcode.h index 2356316368..3c5a686a04 100644 --- a/src/inc/utilcode.h +++ b/src/inc/utilcode.h @@ -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; diff --git a/src/vm/amd64/UMThunkStub.asm b/src/vm/amd64/UMThunkStub.asm index 123a630880..b7701d8e18 100644 --- a/src/vm/amd64/UMThunkStub.asm +++ b/src/vm/amd64/UMThunkStub.asm @@ -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 diff --git a/src/vm/amd64/asmconstants.h b/src/vm/amd64/asmconstants.h index cadc10ac56..1af07860ce 100644 --- a/src/vm/amd64/asmconstants.h +++ b/src/vm/amd64/asmconstants.h @@ -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 diff --git a/src/vm/amd64/umthunkstub.S b/src/vm/amd64/umthunkstub.S index 3e60bedb3f..834f0ca0f8 100644 --- a/src/vm/amd64/umthunkstub.S +++ b/src/vm/amd64/umthunkstub.S @@ -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 diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 18478eb0d4..8f8efcf0fc 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -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,708 +7693,6 @@ 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) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - 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 - - pApp->SetStage(STAGE_OPEN); -} - -void AppDomain::RestrictThreadEntrance(AppDomain * pApp) -{ - CONTRACTL - { - DISABLED(NOTHROW); - DISABLED(GC_TRIGGERS); - MODE_ANY; - DISABLED(FORBID_FAULT); - PRECONDITION(CheckPointer(pApp)); - } - 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 - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n", - GetId().m_dwId, this, GetFriendlyNameForLogging())); - - RestrictEnterHolder RestrictEnter(this); - - { - 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 - } - - // Raise the event indicating the domain is being unloaded. - if (GetDefaultContext()) - { - 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) - { - 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; - } - - 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); - } - } - } - } - - // 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. - - PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex()); - - - if (!NingenEnabled()) - { - UnwindThreads(); - } - - TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ; - ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId); - - 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++); - - LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n", - GetId().m_dwId, this, GetFriendlyNameForLogging())); - - // 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); - - CodeVersionManager::OnAppDomainExit(this); - - // - // 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> - // - - SetStage(STAGE_FINALIZING); - - // Flush finalizers now. - FinalizerThread::UnloadAppDomain(this, fRunFinalizers); - - DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload); - ULONGLONG startTime = CLRGetTickCount64(); - ULONGLONG elapsedTime = 0; - DWORD finalizerWait = 0; - - while (FinalizerThread::GetUnloadingAppDomain() != NULL) - { - - if (timeout != INFINITE) - { - elapsedTime = CLRGetTickCount64() - startTime; - } - if (timeout > elapsedTime) - { - finalizerWait = timeout - static_cast<DWORD>(elapsedTime); - } - FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized - if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL) - { - elapsedTime = CLRGetTickCount64() - startTime; - if (timeout <= elapsedTime) - { - SetRudeUnload(); - // TODO: Consider escalation from RudeAppDomain - timeout = INFINITE; - } - } - } - - 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()) - { - } - - ClearGCRoots(); - ClearGCHandles(); - - LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n", - GetId().m_dwId, this, GetFriendlyNameForLogging())); - - if (fAsyncExit && fRunFinalizers) - { - GCX_PREEMP(); - m_AssemblyCache.Clear(); - ClearFusionContext(); - ReleaseFiles(); - if (!NingenEnabled()) - { - AddMemoryPressure(); - } - } - 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. - { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - -} - -void AppDomain::Close() -{ - CONTRACTL - { - GC_TRIGGERS; - NOTHROW; - } - CONTRACTL_END; - - LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n", - GetId().m_dwId, this, GetFriendlyNameForLogging())); - - { - GCX_PREEMP(); - RemoveMemoryPressure(); - } - _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash - { - SystemDomain::LockHolder lh; // Avoid races with AppDomainIterator - SetStage(STAGE_CLOSED); - } - - // CONSIDER: move releasing remoting cache from managed code to here. -} - - -void AppDomain::ResetUnloadRequestThread(ADID Id) -{ - CONTRACTL - { - NOTHROW; - MODE_ANY; - PRECONDITION(!IsADUnloadHelperThread()); - } - CONTRACTL_END; - - GCX_COOP(); - AppDomainFromIDHolder ad(Id, TRUE); - if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED) - { - Thread *pThread = ad->GetUnloadRequestThread(); - if(pThread==GetThread()) - { - 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); - } - } -} - - -int g_fADUnloadWorkerOK = -1; - -HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough) -{ - CONTRACTL - { - if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;} - MODE_ANY; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);} - FORBID_FAULT; - } - 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; - - { - 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) - { - pApp->EnableADUnloadWorker(); - return S_OK; - } - - pSink = pApp->PrepareForWaitUnloadCompletion(); - - pApp->EnableADUnloadWorker(); - - // release the holders - we don't care anymore if the appdomain is gone - } - -#ifdef FEATURE_TESTHOOKS - if (fExceptionsPassThrough) - { - CONTRACT_VIOLATION(FaultViolation); - return UnloadWaitNoCatch(dwId,pSink); - } -#endif - - return UnloadWait(dwId,pSink); -} - -HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink) -{ - CONTRACTL - { - NOTHROW; - MODE_ANY; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);} - } - 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); - - if (SUCCEEDED(hr)) - hr=pSink->GetUnloadResult(); - - if (FAILED(hr)) - { - ResetUnloadRequestThread(Id); - } - return hr; -} - -#ifdef FEATURE_TESTHOOKS -HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink) -{ - 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(); - - HRESULT hr = pSink->GetUnloadResult(); - - if (SUCCEEDED(hr)) - resetUnloadHolder.SuppressRelease(); - - return hr; -} -#endif - -void AppDomain::Unload(BOOL fForceUnload) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_TRIGGERS; - 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(); - - - if (! fForceUnload && !g_pConfig->AppDomainUnload()) - return; - - EPolicyAction action; - EClrOperation operation; - if (!IsRudeUnload()) - { - operation = OPR_AppDomainUnload; - } - else - { - operation = OPR_AppDomainRudeUnload; - } - action = GetEEPolicy()->GetDefaultAction(operation,NULL); - GetEEPolicy()->NotifyHostOnDefaultAction(operation,action); - - 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; - } - -#if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT)) - static int unloadCount = 0; -#endif - -#ifdef AD_LOG_MEMORY - { - 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); - } - } - } - } -#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()) - { - _ASSERTE(!pThread->IsRunningIn(this, NULL)); - } - - -#ifdef APPDOMAIN_STATE - _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain()); -#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(); - } -#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 - -#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(); - - // Do the actual unloading - { - // We do not want other threads to abort the current one. - ThreadPreventAsyncHolder preventAsync; - Exit(TRUE, !bForceGC); - } - if(bForceGC) - { - GCHeapUtilities::GetGCHeap()->GarbageCollect(); - FinalizerThread::FinalizerThreadWait(); - SetStage(STAGE_COLLECTED); - Close(); //NOTHROW! - } - -#ifdef AD_LOG_MEMORY - if (pLogIt) - { - GCX_PREEMP(); - pLogIt(unloadCount); - } -#endif // AD_LOG_MEMORY - -#ifdef AD_SNAPSHOT - if (takeSnapShot) - { - 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 - -#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(); - } -#endif // _DEBUG -} - void AppDomain::ExceptionUnwind(Frame *pFrame) { CONTRACTL @@ -8681,24 +7710,7 @@ void AppDomain::ExceptionUnwind(Frame *pFrame) Thread *pThread = GetThread(); _ASSERTE(pThread); - if (! pThread->ShouldChangeAbortToUnload(pFrame)) - { - LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n")); - return; - } - - LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n")); - - GCX_COOP(); - OBJECTREF throwable = NULL; - EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound")); - throwable = e.GetThrowable(); - - // reset the exception to an AppDomainUnloadedException - if (throwable != NULL) - { - GetThread()->SafeSetThrowables(throwable); - } + LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n")); } BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread) @@ -8720,78 +7732,6 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo 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; } @@ -8830,10 +7770,6 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo Frame *pFrame = pThread->GetFirstTransitionInto(this, &count); if (! pFrame) { _ASSERTE(count == 0); - if (pThread->IsBeingAbortedForADUnload()) - { - pThread->ResetBeginAbortedForADUnload(); - } continue; } @@ -8841,7 +7777,6 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo { totalADCount += count; nThreadsNeedMoreWork++; - pThread->SetUnloadBoundaryFrame(pFrame); } else { @@ -8849,8 +7784,7 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo } // 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())) + 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); @@ -8869,13 +7803,7 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo // 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 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()) - ) - ) + if (pThread != FinalizerThread::GetFinalizerThread()) { STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count); @@ -8883,12 +7811,7 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo #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); + pThread->SetAbortRequest(EEPolicy::TA_V1Compatible); } TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ; } @@ -8903,18 +7826,6 @@ BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnlo // exit the domain gracefully. // m_dwThreadEnterCount = totalADCount; - if (reKind != kLastException) - { - pThread = NULL; - while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) - { - if (pThread->IsBeingAbortedForADUnload()) - { - pThread->ResetBeginAbortedForADUnload(); - } - } - } - // CommonTripThread will handle the abort for any threads that we've marked ThreadSuspend::RestartEE(FALSE, TRUE); if (reKind != kLastException) @@ -8946,25 +7857,17 @@ void AppDomain::UnwindThreads() m_dwThreadsStillInAppDomain=(ULONG)-1; ULONGLONG startTime = CLRGetTickCount64(); - if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain && - !IsRudeUnload()) - { - GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain); - SetRudeUnload(); - } - // Force threads to go through slow path during AD unload. TSSuspendHolder shTrap; - BOOL fCurrentUnloadMode = IsRudeUnload(); BOOL fMarkUnloadRequestThread = TRUE; // 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) { + 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; @@ -8973,16 +7876,11 @@ void AppDomain::UnwindThreads() // 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); + GetEEPolicy()->NotifyHostOnTimeout(OPR_AppDomainUnload, action); EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT); _ASSERTE (!"Should not reach here"); break; @@ -8995,14 +7893,6 @@ void AppDomain::UnwindThreads() 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) @@ -9034,24 +7924,6 @@ void AppDomain::UnwindThreads() while (TRUE) ; } -void AppDomain::ClearGCHandles() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - NOTHROW; - } - CONTRACTL_END; - - SetStage(STAGE_HANDLETABLE_NOACCESS); - - GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete(); - - // Remove our handle store as a source of GC roots - m_handleStore->Uproot(); -} - void AppDomain::ClearGCRoots() { CONTRACTL @@ -10060,151 +8932,6 @@ void AppDomain::InitializeDefaultDomainManager() 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 - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - DWORD i = 1; - while (TRUE) { - - AppDomain *pDomainToUnload = NULL; - - { - // 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; - } - } - } - - 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; - - EX_TRY { - AppDomain::DoADUnloadWork(); - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); -} - ULONGLONG g_ObjFinalizeStartTime = 0; Volatile<BOOL> g_FinalizerIsRunning = FALSE; Volatile<ULONG> g_FinalizerLoopCount = 0; @@ -10255,11 +8982,6 @@ void FinalizerThreadAbortOnTimeout() EEPolicy::TA_Safe, INFINITE, Thread::UAC_FinalizerTimeout); - if (!pDomain->IsDefaultDomain()) - { - GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action); - pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe); - } } break; case eRudeUnloadAppDomain: @@ -10269,11 +8991,6 @@ void FinalizerThreadAbortOnTimeout() EEPolicy::TA_Rude, INFINITE, Thread::UAC_FinalizerTimeout); - if (!pDomain->IsDefaultDomain()) - { - GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action); - pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude); - } } break; case eExitProcess: @@ -10298,321 +9015,12 @@ enum WorkType { WT_UnloadDomain = 0x1, WT_ThreadAbort = 0x2, - WT_FinalizerThread = 0x4, - WT_ClearCollectedDomains=0x8 + WT_FinalizerThread = 0x4 }; static Volatile<DWORD> s_WorkType = 0; - -DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args) -{ - CONTRACTL - { - NOTHROW; - DISABLED(GC_TRIGGERS); - - // 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; - - BEGIN_ENTRYPOINT_NOTHROW; - - ClrFlsSetThreadType (ThreadType_ADUnloadHelper); - - Thread *pThread = (Thread*)args; - bool fOK = (pThread->HasStarted() != 0); - - { - GCX_MAYBE_PREEMP(fOK); - - _ASSERTE (g_fADUnloadWorkerOK == -2); - - FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1); - - if (!fOK) - { - 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(); - } - - if ((s_WorkType & WT_ClearCollectedDomains) != 0) - { - STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n"); - FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains); - GCX_COOP(); - SystemDomain::System()->ClearCollectedDomains(); - } - - } -Exit:; - } - - END_ENTRYPOINT_NOTHROW; - - return 0; -} - -void AppDomain::EnableADUnloadWorker() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; // Called during a SO - } - CONTRACTL_END; - - EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe; - -#ifdef _DEBUG - DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload(); - if (hostTestADUnload == 2) { - type = EEPolicy::ADU_Rude; - } -#endif // _DEBUG - - EnableADUnloadWorker(type); -} - -void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; // Called during a SO - } - 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); - } - - if (!fHasStack) - { - // Can not call Set due to limited stack. - return; - } - LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n")); - g_pUnloadStartEvent->Set(); -} - -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(); -} - - -void AppDomain::EnableADUnloadWorkerForFinalizer() -{ - 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(); - } -} - -void AppDomain::EnableADUnloadWorkerForCollectedADCleanup() -{ - LIMITED_METHOD_CONTRACT; - LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n")); - FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains); - g_pUnloadStartEvent->Set(); -} - - -void SystemDomain::ClearCollectedDomains() -{ - CONTRACTL - { - GC_TRIGGERS; - NOTHROW; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - AppDomain* pDomainsToClear=NULL; - { - CrstHolder lh(&m_DelayedUnloadCrst); - for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; ) - { - if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED) - { - AppDomain* pAppDomain=*ppDomain; - *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList; - pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear; - pDomainsToClear=pAppDomain; - } - else - ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList); - } - } - - for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;) - { - AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList; - pDomain->Close(); //NOTHROW! - pDomain->Release(); - pDomain=pNext; - } -} - -void SystemDomain::ProcessClearingDomains() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CrstHolder lh(&m_DelayedUnloadCrst); - - 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; - } -} - -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 diff --git a/src/vm/appdomain.hpp b/src/vm/appdomain.hpp index eb28f3ae11..5ffc1b2045 100644 --- a/src/vm/appdomain.hpp +++ b/src/vm/appdomain.hpp @@ -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: diff --git a/src/vm/appdomain.inl b/src/vm/appdomain.inl index 7fb4a9593d..37fb501361 100644 --- a/src/vm/appdomain.inl +++ b/src/vm/appdomain.inl @@ -19,20 +19,6 @@ #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 diff --git a/src/vm/appdomainnative.cpp b/src/vm/appdomainnative.cpp index 713856f1d8..3b2a53846e 100644 --- a/src/vm/appdomainnative.cpp +++ b/src/vm/appdomainnative.cpp @@ -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; diff --git a/src/vm/appdomainnative.hpp b/src/vm/appdomainnative.hpp index 9728ef8ec0..dc1b133d2d 100644 --- a/src/vm/appdomainnative.hpp +++ b/src/vm/appdomainnative.hpp @@ -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); diff --git a/src/vm/arm/asmconstants.h b/src/vm/arm/asmconstants.h index 5af778ba36..c57c92a95b 100644 --- a/src/vm/arm/asmconstants.h +++ b/src/vm/arm/asmconstants.h @@ -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 diff --git a/src/vm/arm/asmhelpers.S b/src/vm/arm/asmhelpers.S index 22ec7c1171..feadaa87ba 100644 --- a/src/vm/arm/asmhelpers.S +++ b/src/vm/arm/asmhelpers.S @@ -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 diff --git a/src/vm/arm/asmhelpers.asm b/src/vm/arm/asmhelpers.asm index 60def084e7..c0fef0c705 100644 --- a/src/vm/arm/asmhelpers.asm +++ b/src/vm/arm/asmhelpers.asm @@ -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 diff --git a/src/vm/arm64/asmconstants.h b/src/vm/arm64/asmconstants.h index 262e481b53..7d0a9f734b 100644 --- a/src/vm/arm64/asmconstants.h +++ b/src/vm/arm64/asmconstants.h @@ -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 diff --git a/src/vm/arm64/asmhelpers.S b/src/vm/arm64/asmhelpers.S index e138feb402..aa79b4d477 100644 --- a/src/vm/arm64/asmhelpers.S +++ b/src/vm/arm64/asmhelpers.S @@ -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) diff --git a/src/vm/arm64/asmhelpers.asm b/src/vm/arm64/asmhelpers.asm index 7346c468a0..e9edec17e5 100644 --- a/src/vm/arm64/asmhelpers.asm +++ b/src/vm/arm64/asmhelpers.asm @@ -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 diff --git a/src/vm/callhelpers.cpp b/src/vm/callhelpers.cpp index d11c4e83d4..b11f9d73e9 100644 --- a/src/vm/callhelpers.cpp +++ b/src/vm/callhelpers.cpp @@ -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)) diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp index 9874d26f4d..04b12264a8 100644 --- a/src/vm/ceemain.cpp +++ b/src/vm/ceemain.cpp @@ -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(); diff --git a/src/vm/codeversion.cpp b/src/vm/codeversion.cpp index 5f7ef16f7b..06451e9e94 100644 --- a/src/vm/codeversion.cpp +++ b/src/vm/codeversion.cpp @@ -2383,10 +2383,6 @@ HRESULT CodeVersionManager::EnumerateClosedMethodDescs( while (appDomainIterator.Next()) { AppDomain * pAppDomain = appDomainIterator.GetDomain(); - if (pAppDomain->IsUnloading()) - { - continue; - } hr = EnumerateDomainClosedMethodDescs( pAppDomain, pModule, diff --git a/src/vm/comcallablewrapper.cpp b/src/vm/comcallablewrapper.cpp index 4d116c157f..49802ff9d0 100644 --- a/src/vm/comcallablewrapper.cpp +++ b/src/vm/comcallablewrapper.cpp @@ -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; diff --git a/src/vm/cominterfacemarshaler.cpp b/src/vm/cominterfacemarshaler.cpp index 9b9d56a6ff..4a74ddd4d4 100644 --- a/src/vm/cominterfacemarshaler.cpp +++ b/src/vm/cominterfacemarshaler.cpp @@ -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; diff --git a/src/vm/comsynchronizable.cpp b/src/vm/comsynchronizable.cpp index 0a6447bd9b..5f54bcda93 100644 --- a/src/vm/comsynchronizable.cpp +++ b/src/vm/comsynchronizable.cpp @@ -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); } }; diff --git a/src/vm/comtoclrcall.cpp b/src/vm/comtoclrcall.cpp index 2a60f8c2df..df1ba64a8e 100644 --- a/src/vm/comtoclrcall.cpp +++ b/src/vm/comtoclrcall.cpp @@ -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 { diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp index ef99dec970..f9785ab19f 100644 --- a/src/vm/corhost.cpp +++ b/src/vm/corhost.cpp @@ -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; } } diff --git a/src/vm/delegateinfo.h b/src/vm/delegateinfo.h index 80a69a63c3..8bc21b0155 100644 --- a/src/vm/delegateinfo.h +++ b/src/vm/delegateinfo.h @@ -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 diff --git a/src/vm/dispatchinfo.cpp b/src/vm/dispatchinfo.cpp index f7b3068428..393c2aaf95 100644 --- a/src/vm/dispatchinfo.cpp +++ b/src/vm/dispatchinfo.cpp @@ -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)); diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp index 2becba5bfe..c064872981 100644 --- a/src/vm/dllimportcallback.cpp +++ b/src/vm/dllimportcallback.cpp @@ -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(); diff --git a/src/vm/domainfile.cpp b/src/vm/domainfile.cpp index ded1e5715b..2a1b5e5fea 100644 --- a/src/vm/domainfile.cpp +++ b/src/vm/domainfile.cpp @@ -37,24 +37,6 @@ #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 diff --git a/src/vm/domainfile.h b/src/vm/domainfile.h index 070c616ecb..58706518c7 100644 --- a/src/vm/domainfile.h +++ b/src/vm/domainfile.h @@ -709,7 +709,6 @@ public: BOOL IsVisibleToDebugger(); BOOL NotifyDebuggerLoad(int flags, BOOL attaching); void NotifyDebuggerUnload(); - BOOL IsUnloading(); inline BOOL IsCollectible(); // diff --git a/src/vm/eeconfig.cpp b/src/vm/eeconfig.cpp index 37864f1f83..0b3e413a0e 100644 --- a/src/vm/eeconfig.cpp +++ b/src/vm/eeconfig.cpp @@ -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 diff --git a/src/vm/eeconfig.h b/src/vm/eeconfig.h index 60d8b70157..68f160edea 100644 --- a/src/vm/eeconfig.h +++ b/src/vm/eeconfig.h @@ -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 diff --git a/src/vm/eepolicy.cpp b/src/vm/eepolicy.cpp index efa5fc0667..4cd4d0a03c 100644 --- a/src/vm/eepolicy.cpp +++ b/src/vm/eepolicy.cpp @@ -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); diff --git a/src/vm/eepolicy.h b/src/vm/eepolicy.h index 44e0073754..9ca09bb67b 100644 --- a/src/vm/eepolicy.h +++ b/src/vm/eepolicy.h @@ -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); diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp index be83f1c7a4..6179b6c561 100644 --- a/src/vm/eventtrace.cpp +++ b/src/vm/eventtrace.cpp @@ -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()); } /********************************************************************************/ diff --git a/src/vm/finalizerthread.cpp b/src/vm/finalizerthread.cpp index 62816ebacb..9e2e8d06e2 100644 --- a/src/vm/finalizerthread.cpp +++ b/src/vm/finalizerthread.cpp @@ -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) { diff --git a/src/vm/finalizerthread.h b/src/vm/finalizerthread.h index be684514b5..bb1cfe4a74 100644 --- a/src/vm/finalizerthread.h +++ b/src/vm/finalizerthread.h @@ -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(); diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index 3dd22dafdf..34645b302c 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -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) diff --git a/src/vm/gchandleutilities.cpp b/src/vm/gchandleutilities.cpp index 4361778fb9..220445a1cc 100644 --- a/src/vm/gchandleutilities.cpp +++ b/src/vm/gchandleutilities.cpp @@ -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 } diff --git a/src/vm/i386/asmconstants.h b/src/vm/i386/asmconstants.h index 70f6e30c4a..e17cec7227 100644 --- a/src/vm/i386/asmconstants.h +++ b/src/vm/i386/asmconstants.h @@ -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 diff --git a/src/vm/i386/asmhelpers.S b/src/vm/i386/asmhelpers.S index 2052088f51..09fb50266f 100644 --- a/src/vm/i386/asmhelpers.S +++ b/src/vm/i386/asmhelpers.S @@ -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 diff --git a/src/vm/i386/asmhelpers.asm b/src/vm/i386/asmhelpers.asm index 17d521fb92..18b5c6eb98 100644 --- a/src/vm/i386/asmhelpers.asm +++ b/src/vm/i386/asmhelpers.asm @@ -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 diff --git a/src/vm/loaderallocator.cpp b/src/vm/loaderallocator.cpp index 77f0c9e3c1..cb5f81752d 100644 --- a/src/vm/loaderallocator.cpp +++ b/src/vm/loaderallocator.cpp @@ -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 diff --git a/src/vm/marshalnative.cpp b/src/vm/marshalnative.cpp index 133cbf9069..2ce0bdaa4c 100644 --- a/src/vm/marshalnative.cpp +++ b/src/vm/marshalnative.cpp @@ -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(); diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp index a768ded29b..53a0be79a5 100644 --- a/src/vm/methodtable.cpp +++ b/src/vm/methodtable.cpp @@ -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; } diff --git a/src/vm/nativeoverlapped.cpp b/src/vm/nativeoverlapped.cpp index 94e61c63fd..f808496657 100644 --- a/src/vm/nativeoverlapped.cpp +++ b/src/vm/nativeoverlapped.cpp @@ -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); } diff --git a/src/vm/object.cpp b/src/vm/object.cpp index a0427cdcb9..ca54ba2848 100644 --- a/src/vm/object.cpp +++ b/src/vm/object.cpp @@ -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 diff --git a/src/vm/profilingenumerators.cpp b/src/vm/profilingenumerators.cpp index a6b0a640f1..b5c1e57b60 100644 --- a/src/vm/profilingenumerators.cpp +++ b/src/vm/profilingenumerators.cpp @@ -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. // diff --git a/src/vm/stackprobe.cpp b/src/vm/stackprobe.cpp index fd0488c222..6663300e90 100644 --- a/src/vm/stackprobe.cpp +++ b/src/vm/stackprobe.cpp @@ -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(); } diff --git a/src/vm/stacksampler.cpp b/src/vm/stacksampler.cpp index d95adb1f63..51e4b9df5d 100644 --- a/src/vm/stacksampler.cpp +++ b/src/vm/stacksampler.cpp @@ -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; } diff --git a/src/vm/stdinterfaces_wrapper.cpp b/src/vm/stdinterfaces_wrapper.cpp index c33c330798..62657519da 100644 --- a/src/vm/stdinterfaces_wrapper.cpp +++ b/src/vm/stdinterfaces_wrapper.cpp @@ -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 diff --git a/src/vm/testhookmgr.cpp b/src/vm/testhookmgr.cpp index 991b6c64cd..f72f69de43 100644 --- a/src/vm/testhookmgr.cpp +++ b/src/vm/testhookmgr.cpp @@ -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) diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index ddf31f4f5b..9a0ebdc7ca 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -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; diff --git a/src/vm/threads.h b/src/vm/threads.h index e4b6487f55..dc468630f5 100644 --- a/src/vm/threads.h +++ b/src/vm/threads.h @@ -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 diff --git a/src/vm/threads.inl b/src/vm/threads.inl index f5a439c350..1c07070068 100644 --- a/src/vm/threads.inl +++ b/src/vm/threads.inl @@ -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)); diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp index 6c761f3da1..abf9597074 100644 --- a/src/vm/threadsuspend.cpp +++ b/src/vm/threadsuspend.cpp @@ -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: diff --git a/src/vm/win32threadpool.h b/src/vm/win32threadpool.h index 2a3a3bbb24..ddbd34a3c3 100644 --- a/src/vm/win32threadpool.h +++ b/src/vm/win32threadpool.h @@ -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); } } |