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
JIT: Do not report duplicate EH clauses to VM (#114895)
* JIT: Do not report duplicate EH clauses to VM
* Remove the flags and their usage too
* Remove doc for Duplicated Clauses
* Update JIT-EE GUID
* Update doc for cloned finallys
* Delete COR_ILEXCEPTION_CLAUSE_OFFSETLEN and COR_ILEXCEPTION_CLAUSE_DEPRECATED
* Replace magic value with COR_ILEXCEPTION_CLAUSE_SAMETRY
---------
Co-authored-by: Jan Kotas <[email protected]>
Copy file name to clipboardExpand all lines: docs/design/coreclr/botr/clr-abi.md
+1-84Lines changed: 1 addition & 84 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -200,11 +200,7 @@ For Windows/x86 on NativeAOT and Linux/x86, funclets are used just like on other
200
200
201
201
## Cloned finallys
202
202
203
-
JIT64 attempts to speed the normal control flow by 'inlining' a called finally along the 'normal' control flow (i.e., leaving a try body in a non-exceptional manner via C# fall-through). Because the VM semantics for non-rude Thread.Abort dictate that handlers will not be aborted, the JIT must mark these 'inlined' finally bodies. These show up as special entries at the end of the EH tables and are marked with `COR_ILEXCEPTION_CLAUSE_FINALLY | COR_ILEXCEPTION_CLAUSE_DUPLICATED`, and the try_start, try_end, and handler_start are all the same: the start of the cloned finally.
204
-
205
-
RyuJit also implements finally cloning, for all supported architectures. However, the implementation does not yet handle the thread abort case; cloned finally bodies are not guaranteed to remain intact and are not reported to the runtime. Because of this, finally cloning is disabled for VMs that support thread abort (desktop clr).
206
-
207
-
JIT32 does not implement finally cloning.
203
+
RyuJIT attempts to speed the normal control flow by 'inlining' a called finally along the 'normal' control flow (i.e., leaving a try body in a non-exceptional manner via C# fall-through). This optimization is supported on all architectures.
208
204
209
205
## Invoking Finallys/Non-local exits
210
206
@@ -499,85 +495,6 @@ When the inner "throw new UserException4" is executed, the exception handling fi
499
495
500
496
Filters are invoked in the 1st pass of EH processing and as such execution might resume back at the faulting address, or in the filter-handler, or someplace else. Because the VM must allow GC's to occur during and after a filter invocation, but before the EH subsystem knows where it will resume, we need to keep everything alive at both the faulting address **and** within the filter. This is accomplished by 3 means: (1) the VM's stackwalker and GCInfoDecoder report as live both the filter frame and its corresponding parent frame, (2) the JIT encodes all stack slots that are live within the filter as being pinned, and (3) the JIT reports as live (and possible zero-initializes) anything live-out of the filter. Because of (1) it is likely that a stack variable that is live within the filter and the try body will be double reported. During the mark phase of the GC double reporting is not a problem. The problem only arises if the object is relocated: if the same location is reported twice, the GC will try to relocate the address stored at that location twice. Thus we prevent the object from being relocated by pinning it, which leads us to why we must do (2). (3) is done so that after the filter returns, we can still safely incur a GC before executing the filter-handler or any outer handler within the same frame. For the same reason, control must exit a filter region via its final block (in other words, a filter region must terminate with the instruction that leaves the filter region, and the program may not exit the filter region via other paths).
501
497
502
-
## Duplicated Clauses
503
-
504
-
Duplicated clauses are a special set of entries in the EH tables to assist the VM. Specifically, if handler 'A' is also protected by an outer EH clause 'B', then the JIT must emit a duplicated clause, a duplicate of 'B', that marks the whole handler 'A' (which is now lexically disjoint for the range of code for the corresponding try body 'A') as being protected by the handler for 'B'.
505
-
506
-
Duplicated clauses are not needed for x86 and for NativeAOT ABI.
507
-
508
-
During exception dispatch the VM uses these duplicated clauses to know when to skip any frames between the handler and its parent function. After skipping to the parent function, due to a duplicated clause, the VM searches for a regular/non-duplicate clause in the parent function. The order of duplicated clauses is important. They should appear after all of the main function clauses. They should still follow the normal sorting rules (inner-to-outer, top-to-bottom), but because the try-start/try-end will all be the same for a given handler, they should maintain the ordering, regarding inner-to-outer, as the corresponding original clause.
509
-
510
-
Example:
511
-
512
-
```
513
-
A: try {
514
-
B: ...
515
-
C: try {
516
-
D: ...
517
-
E: try {
518
-
F: ...
519
-
G: }
520
-
H: catch {
521
-
I: ...
522
-
J: }
523
-
K: ...
524
-
L: }
525
-
M: finally {
526
-
N: ...
527
-
O: }
528
-
P: ...
529
-
Q: }
530
-
R: catch {
531
-
S: ...
532
-
T: }
533
-
```
534
-
535
-
In MSIL this would generate 3 EH clauses:
536
-
537
-
```
538
-
.try E-G catch H-J
539
-
.try C-L finally M-O
540
-
.try A-Q catch R-T
541
-
```
542
-
543
-
The native code would be laid out as follows (the order of the handlers is irrelevant except they are after the main method body) with their corresponding (fake) native offsets:
2. .try 3-9 finally 15-17 (top-most & next inner-most)
573
-
3. .try 1-11 catch 18-20 (top-most & outer-most)
574
-
4. .try 12-14 finally 15-17 duplicated (inner-most because clause 2 is inside clause 3, top-most because handler H-J is first)
575
-
5. .try 12-14 catch 18-20 duplicated
576
-
6. .try 15-17 catch 18-20
577
-
```
578
-
579
-
If the handlers were in a different order, then clause 6 might appear before clauses 4 and 5, but never in between.
580
-
581
498
## Clauses covering the same try region
582
499
583
500
Several consecutive clauses may cover the same `try` block. A clause covering the same region as the previous one is marked by the `COR_ILEXCEPTION_CLAUSE_SAMETRY` flag. When exception ex1 is thrown while running handler for another exception ex2 and the exception ex2 escapes the ex1's handler frame, this enables the runtime to skip clauses that cover the same `try` block as the clause that handled the ex1.
0 commit comments