You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Remove DomainAssembly and other multi-appdomain dead code (#126881)
Closes#104590
* Deletes DomainAssembly, simplifying DacDbi APIs in the process
* Updates comments and docs mentioning domain-neutral assemblies or
multiple AppDomains
* Removes dead code in dbi & DacDbi related to multiple AppDomains
* Remove IsAssemblyFullyTrusted
* Tested on diagnosticstests
Copy file name to clipboardExpand all lines: docs/design/coreclr/botr/dac-notes.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -62,7 +62,7 @@ An example may be helpful in understanding how marshaling works. The common debu
62
62
63
63
The debugger in this figure could be Visual Studio, MDbg, WinDbg, etc. The debugger interfaces with the CLR debugger interface (DBI) APIs to get the information it needs. Information that must come from the target goes through the DAC. The debugger implements the data target, which is responsible for implementing a `ReadVirtual` function to read memory in the target. The dotted line in the diagram represents the process boundary.
64
64
65
-
Suppose the debugger needs to display the starting address of an ngen'ed method in the managed application that it has gotten from the managed stack. We will assume that the debugger has already gotten an instance of `ICorDebugFunction` back from the DBI. It will begin by calling the DBI API `ICorDebugFunction::GetNativeCode`. This calls into the DAC through the DAC/DBI interface function `GetNativeCodeInfo`, passing in the domain file and metadata token for the function. The following code fragment is a simplification of the actual function, but it illustrates marshaling without introducing extraneous details.
65
+
Suppose the debugger needs to display the starting address of an ngen'ed method in the managed application that it has gotten from the managed stack. We will assume that the debugger has already gotten an instance of `ICorDebugFunction` back from the DBI. It will begin by calling the DBI API `ICorDebugFunction::GetNativeCode`. This calls into the DAC through the DAC/DBI interface function `GetNativeCodeInfo`, passing in the assembly and metadata token for the function. The following code fragment is a simplification of the actual function, but it illustrates marshaling without introducing extraneous details.
Copy file name to clipboardExpand all lines: docs/design/coreclr/botr/profiling.md
+3-9Lines changed: 3 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -118,7 +118,7 @@ A ProcessID is unique system-wide for the lifetime of the process. All other IDs
118
118
119
119
### Hierarchy & Containment
120
120
121
-
ID's are arranged in a hierarchy, mirroring the hierarchy in the process. Processes contain AppDomains contain Assemblies contain Modules contain Classes contain Functions. Threads are contained within Processes, and may move from AppDomain to AppDomain. Objects are mostly contained within AppDomains (a very few objects may be members of more than one AppDomain at a time). Contexts are contained within Processes.
121
+
ID's are arranged in a hierarchy, mirroring the hierarchy in the process. Processes contain the global AppDomain which contains Assemblies which contain Modules which contain Classes which contain Functions. Threads are contained within Processes. Objects are contained within the AppDomain. Contexts are contained within Processes.
122
122
123
123
### Lifetime & Stability
124
124
@@ -140,12 +140,6 @@ GCHandleID – Alive from the call to HandleCreated until the return from Handle
140
140
141
141
In addition, any ID returned from a profiling API function will be alive at the time it is returned.
142
142
143
-
### App-Domain Affinity
144
-
145
-
There is an AppDomainID for each user-created app-domain in the process, plus the "default" domain, plus a special pseudo-domain used for holding domain-neutral assemblies.
146
-
147
-
Assembly, Module, Class, Function, and GCHandleIDs have app-domain affinity, meaning that if an assembly is loaded into multiple app domains, it (and all of the modules, classes, and functions contained within it) will have a different ID in each, and operations upon each ID will take effect only in the associated app domain. Domain-neutral assemblies will appear in the special pseudo-domain mentioned above.
148
-
149
143
### Special Notes
150
144
151
145
All IDs except ObjectID should be treated as opaque values. Most IDs are fairly self-explanatory. A few are worth explaining in more detail:
@@ -386,8 +380,8 @@ There are four types of statics. The following table describes what they are and
386
380
387
381
|**Static Type**|**Definition**|**Identifying in Metadata**|
Copy file name to clipboardExpand all lines: docs/design/coreclr/botr/threading.md
+1-14Lines changed: 1 addition & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,7 @@ The public Thread interface available to managed code intentionally hides the de
18
18
19
19
The CLR provides equivalent abstractions for managed threads, implemented by the CLR itself. For example, it does not expose the operating system's thread-local storage (TLS) mechanism, but instead provides managed "thread-static" variables. Similarly, it does not expose the native thread's "thread ID," but instead provides a "managed thread ID" which is generated independently of the OS. However, for diagnostic purposes, some details of the underlying native thread may be obtained via types in the System.Diagnostics namespace.
20
20
21
-
Managed threads require additional functionality typically not needed by native threads. First, managed threads hold GC references on their stacks, so the CLR must be able to enumerate (and possibly modify) these references every time a GC occurs. To do this, the CLR must "suspend" each managed thread (stop it at a point where all of its GC references can be found). Second, when an AppDomain is unloaded, the CLR must ensure that no thread is executing code in that AppDomain. This requires the ability to force a thread to unwind out of that AppDomain. The CLR does this by injecting a ThreadAbortException into such threads.
21
+
Managed threads require additional functionality typically not needed by native threads. First, managed threads hold GC references on their stacks, so the CLR must be able to enumerate (and possibly modify) these references every time a GC occurs. To do this, the CLR must "suspend" each managed thread (stop it at a point where all of its GC references can be found). Second, when the AppDomain is unloaded, the CLR must ensure that no thread is executing code in the AppDomain. This requires the ability to force a thread to unwind out of the AppDomain. The CLR does this by injecting a ThreadAbortException into such threads.
22
22
23
23
Data Structures
24
24
===============
@@ -107,19 +107,6 @@ Hijacking for GC suspension is done by Thread::SysSuspendForGC. This method atte
107
107
* If fully interruptible, it is safe to perform a GC at any point, since the thread is, by definition, at a safe point. It is reasonable to leave the thread suspended at this point (because it's safe) but various historical OS bugs prevent this from working, because the CONTEXT retrieved earlier may be corrupt. Instead, the thread's instruction pointer is overwritten, redirecting it to a stub that will capture a more complete CONTEXT, leave cooperative mode, wait for the GC to complete, reenter cooperative mode, and restore the thread to its previous state.
108
108
* If partially-interruptible, the thread is, by definition, not at a safe point. However, the caller will be at a safe point (method transition). Using that knowledge, the CLR "hijacks" the top-most stack frame's return address (physically overwrite that location on the stack) with a stub similar to the one used for fully-interruptible code. When the method returns, it will no longer return to its actual caller, but rather to the stub (the method may also perform a GC poll, inserted by the JIT, before that point, which will cause it to leave cooperative mode and undo the hijack).
109
109
110
-
ThreadAbort / AppDomain-Unload
111
-
==============================
112
-
113
-
In order to unload an AppDomain, the CLR must ensure that no thread is running in that AppDomain. To accomplish this, all managed threads are enumerated, and "abort" any threads which have stack frames belonging to the AppDomain being unloaded. A ThreadAbortException is "injected" into the running thread, which causes the thread to unwind (executing backout code along the way) until it is no longer executing in the AppDomain, at which point the ThreadAbortException is translated into an AppDomainUnloaded exception.
114
-
115
-
ThreadAbortException is a special type of exception. It can be caught by user code, but the CLR ensures that the exception will be rethrown after the user's exception handler is executed. Thus ThreadAbortException is sometimes referred to as "uncatchable," though this is not strictly true.
116
-
117
-
A ThreadAbortException is typically 'thrown' by simply setting a bit on the managed thread marking it as "aborting." This bit is checked by various parts of the CLR (most notably, every return from a p/invoke) and often times setting this bit is all that is needed to get the thread aborted in a timely manner.
118
-
119
-
However, if the thread is, for example, executing a long-running managed loop, it may never check this bit. To get such a thread to abort faster, the thread is "hijacked" and forced to raise a ThreadAbortException. This hijacking is done in the same way as GC suspension, except that the stubs that the thread is redirected to will cause a ThreadAbortException to be raised, rather than waiting for a GC to complete.
120
-
121
-
This hijacking means that a ThreadAbortException can be raised at essentially any arbitrary point in managed code. This makes it extremely difficult for managed code to deal successfully with a ThreadAbortException. It is therefore unwise to use this mechanism for any purpose other than AppDomain-Unload, which ensures that any state corrupted by the ThreadAbort will be cleaned up along with the AppDomain.
Copy file name to clipboardExpand all lines: docs/design/features/code-versioning.md
+1-26Lines changed: 1 addition & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -286,31 +286,6 @@ Another interesting consideration is that in the future I anticipate having some
286
286
287
287
Thus if the current implementation doesn't appear ideal partly this may be because I wasn't sufficiently clever, but the other part is that I was optimizing for future conditions.
288
288
289
-
### Domains ###
290
-
There is one CodeVersionManager per AppDomain, and one for the SharedDomain. Versioning for a given method always looks up the appropriate CodeVersionManager by traversing from MethodDef token -> Module that defines that token -> Domain that loaded that module -> CodeVersionManager. In code this is either:
Some shortcut accessors are defined to make these lookups simpler:
300
-
301
-
```
302
-
pModule->GetCodeVersionManager()
303
-
pMethod->GetCodeVersionManager()
304
-
```
305
-
306
-
Generics can cause methods in domain-neutral modules to refer to types in domain-specific modules. The rules above dictate that these code versions still reside in the domain-neutral CodeVersionManager. The AppDomain specific CodeVersionManagers will never contain code versions with a domain-neutral type in their instantiation.
307
-
308
-
CoreCLR is largely moving away from multiple AppDomains but I left the domain distinctions in place for a few reasons:
309
-
310
-
1. Pragmatically the feature is a partial refactoring of ReJitManager and this is what ReJitManager did. Diverging from ReJitManager's design incurs extra time and risk of new issues.
311
-
2. Maybe someday we will want to migrate similar functionality back to the desktop .NET SKU. Desktop supports multiple AppDomains so per-AppDomain handling would be required in that context.
312
-
313
-
AppDomain unloading however has not been handled. If CoreCLR supports proper AppDomain unload at some point or the code moves back to desktop runtime we will need to handle this gap.
314
289
315
290
### Code activation and publishing ###
316
291
@@ -332,7 +307,7 @@ In order to do step 3 the `CodeVersionManager` relies on one of three different
332
307
### Thread-safety ###
333
308
CodeVersionManager is designed for use in a free-threaded environment, in many cases by requiring the caller to acquire a lock before calling. This lock can be acquired by constructing an instance of `CodeVersionManager::LockHolder`.
334
309
335
-
in some scope for the CodeVersionManager being operated on. CodeVersionManagers from different domains should not have their locks taken by the same thread with one exception, it is OK to take the shared domain manager lock and one AppDomain manager lock in that order. The lock is required to change the shape of the tree or traverse it but not to read/write configuration properties from each node. A few special cases:
310
+
in some scope for the CodeVersionManager being operated on. The lock is required to change the shape of the tree or traverse it but not to read/write configuration properties from each node. A few special cases:
336
311
337
312
- CodeVersionManager::SetActiveILCodeVersions needs to operate partially inside and partially outside the lock. The caller should not acquire the lock beforehand.
338
313
- NativeCodeVersion::GetILCodeVersion() does not require the lock if the caller first guarantees it is operating on the default code version.
0 commit comments