Skip to content
This repository has been archived by the owner on Mar 15, 2022. It is now read-only.

EH RI #897

Merged
merged 70 commits into from
Oct 22, 2015
Merged

EH RI #897

merged 70 commits into from
Oct 22, 2015

Conversation

JosephTremoulet
Copy link
Contributor

Merge the EH branch back into master.

At a high level, the EH status is still "code with EH constructs compiles cleanly, but attempts to catch exceptions may not work correctly at run-time". The differences are:

  • Code "compiling cleanly" now includes generating IR for all handlers, pushing it through the entire compiler pipeline, generating EH tables and passing them to the runtime. Previously it meant stripping the handler code in the reader.
  • Failfast calls are now inserted into handler entries, so diagnosing failures due to lack of EH support becomes easier.
  • Things are stable enough now that it makes sense to do the rest of the EH bring-up with incremental changes off master, rather than in a separate long-lived branch.

JosephTremoulet and others added 30 commits April 22, 2015 23:27
This flag allows compiling in a bring-up mode where EH clauses aren't
reported to the runtime.
This is a temporary measure during EH bring-up; methods with landing pads
will have their IR shown (if IR dumps are enabled), but then will be
discarded so we'll fall back to the other jit rather than choking on the
landing pads downstream.
Expand the FlowGraphInfoMap to record the innermost containing EHRegion
for each BasicBlock.

Remove the explicit Region parameter to makeFlowGraphNode since it is now
assumed to be the CurrentRegion.

Remove the overload of fgNodeGetRegion that takes a Function (and rewrite
its only callsite to get the tree directly).
Allow recording catch class tokens on region objects.  Use a union to
overlay data used only for finally regions from data used only for catch
regions.
Group pointers for better packing.
In preparation for making their logic a little more complex.
This will facilitate consulting the FlowGraphNodeInfoMap to identify
handlers for nominal edges.
Add a hook, fgEnterRegion, used during first-pass flow-graph construction
to perform any necessary client actions for setting up regions.

Implement fgEnterRegion in GenIR to create a landing pad for each
protected region.  Clauses are added for catch handlers in the landing
pad; other handler types are stubbed out.

Update FlowGraphSuccessorEdgeList to report a nominal edge from any
handler-protected block to its handler block (even if no throwing
instructions have been inserted into the source block yet); this
conservative model is what the base Reader class is expecting in terms of
EH flow (and in particular, this ensures that handlers are visited when
determining reachable blocks to decide which blocks to run pass 2 over).

Remove setupBlockForEH now that its functionality has been incorporated
into fgEnterRegion.

Update leave processing to generate a call to llvm.eh.endcatch whenever a
catch handler is exited.

Closes #66
Calls in protected regions that may throw must use invoke instructions
annotated with the appropriate unwind label.
Invoke is a terminator, so it splits its block; update some code in
genConditionalPointBlock to allow that there may be multiple point blocks
once the invoke has been inserted.
Implement reader support for catch handlers and may-throw calls
Conflicts:
	lib/Jit/LLILCJit.cpp
Conflicts:
	lib/Reader/reader.cpp
The argument is the entire struct defined by the LandingPad, not the
extracted exception pointer field of it.
As currently written, the exception dispatch from the inner landingpad
would jump straight to the outer landingpad if the exception type doesn't
match.  This is incorrect; that path out of the inner dispatch should jump
to a common point that the outer landingpad also jumps to (only one
`landingpad` instruction [the inner one] should be executed in these
cases).
Just punt on these cases since the dispatch code will need to look very
different once the new representation lands.
 - Change the name of the personality function to the correct one for
   CoreCLR.
 - Pass the catch class token value directly as the clause argument on the
   landingpad instruction.
Add a jit layer before the ObjectLinkingLayer to inspect the object and:
 - Call reserveUnwindInfo for each funclet (before calling allocMem)
 - Call allocUnwindInfo separately for each funclet

Also, add code to:
 - Call setEHcount and setEHinfo to report protected regions and their
   handlers

The individual functions' contributes in .xdata are determined by parsing
the unwind info headers in the .xdata and markers placed between the
functions' contributions by the CoreCLR EH table generation in LLVM.
The handler types supported in the reader are now also supported in
lowering/emission.
Conflicts:
	include/Jit/LLILCJit.h
	lib/Jit/EEMemoryManager.cpp
	lib/Jit/LLILCJit.cpp
This layer just needs to call the memory manager's reserveUnwindSpace
method on each object as it passes through; use the
orc::ObjectTransformLayer utility rather than a custom object layer.
Use ObjectTransformLayer to reserve unwind space
Conflicts:
	lib/Jit/LLILCJit.cpp
This will be necessary when we outline filter functions.
Filters are outlined during initial IR generation (which includes
explicitly escaping any locals referenced in filters), to simplify
modeling their effects in the IR (invoking the outlined function must be
included as a possible side-effect of any invoke that may throw an
exception, since this must bottom out in a call to the throw helper [which
is external code] and the filter function has external linkage).

The ReaderBase class is unaware of the outlining.  GenIR generates the
filter code inline in the main function (except for an initial point
block) during its main passes, and then moves filter blocks to the correct
function in the readerPostVisit pass that this change adds between reading
MSIL and removing unreachable code.

The CurrentRegion tracked by the reader is used by GenIR to check whether
code currently being generated is destined for an outlined filter or not,
in the places where that is needed.  References to parameters and locals
check if the use is in a filter and insert escape code in the parent
function and recover code in the filter as necessary.

Any invoke in a filter-protected region needs a nominal edge to the filter
as well as to its landingpad (the landingpad doesn't have explicit flow to
the filter); this is achieved by having FlowGraphSuccessorEdgeList track
down and iterate through the entry blocks of any filters referenced in the
landingpad.

There's also some juggling in fgNodeGetNext to ensure that the point
blocks for filter entries are visited in their correct place in MSIL
order.

This change renames GenIR's Function field to RootFunction as reminder
that some methods will have multiple functions.  A few places are updated
to iterate through all functions in the module where previously they were
just operating on the one Function, including marking functions with
unmanaged call frames and removing unreachable code.
JosephTremoulet and others added 13 commits October 2, 2015 23:41
Skip relocation for personality routine in xdata
The object gets a function symbol for each funclet, so we need to sum
their sizes rather than trying to report each in turn.
Update debug info emission to handle funclets
When insertConditionalPointBlock inserts a point block that has been
split, it needs to find the ultimate tail point block, not keep checking
the head point block's terminator repeatedly.
The helper call may be an invoke, so the predecessor of the PHI block may
not be the block holding the call, but rather it's invoke's normal
successor.
Make sure that CurrentInstrOffset and CurrentRegion have reasonable values
when inserting prolog code after parsing all instructions (previously they
were inadvertently getting the end-of-function values).
Conflicts:
	lib/Reader/readerir.cpp
Conflicts:
	lib/GcInfo/GcInfo.cpp
This will make it easier to triage failures due to unsupported EH
behavior.

Also add a setting that overrides this behavior to facilitate EH testing.
Insert failfast calls at exception handler entries
@JosephTremoulet
Copy link
Contributor Author

The individual changes were all PRed when they went into the EH branch.

@AndyAyersMS PTAL.

@JosephTremoulet
Copy link
Contributor Author

Forgot to mention:

  • NGEN and InsertStatepoints tests still pass, except that JIT\Regression\VS-ia64-JIT\V1.2-M02\b28158\b28158 with its 16,732 catch clauses starts timing out.
  • Precise GC tests have some additional failures, but @swaroop-sridhar and I have looked at them and believe them to be due to issues already existing in the mainline.

@swaroop-sridhar
Copy link
Contributor

Can you please add an exclusion for b28158 under the $(COMPLUS_INSERTSTATEPOINTS) condition in exclusion.targets? to keep the InsertStatepoints job green.

This test times out; opened #898 to investigate.
@JosephTremoulet
Copy link
Contributor Author

Can you please add an exclusion for b28158 under the $(COMPLUS_INSERTSTATEPOINTS) condition in exclusion.targets? to keep the InsertStatepoints job green.

Sure; updated.

@AndyAyersMS
Copy link
Member

I'm quite happy to see this merge.

Looked through the code a bit but not in detail. Am willing to trust that suitable rigor was applied along the way.

Do you think there is value in preserving branch history here, or should you rebase and squash?

@JosephTremoulet
Copy link
Contributor Author

I'd prefer to have the history as-is;

  • I think it will make any future history searches more likely to find the relevant details
  • I believe we'll never find ourselves trying to bisect through these changes
  • even if we would do that, reconstructing a bisectable rebased history would be an effort that doesn't seem worth the opportunity cost
  • neither squashing into a single monolithic commit not parceling out a non-bisectable rebased history by splitting out certain functions at a time gives you any information that isn't just as easily found in the diff against previous master, the header comments, and/or the non-rebased commits that git blame will find this way.

For Microsoft:LLVM, on the other hand, while the EH and MS branches now have identical sources, I considered doing a merge there just to keep the history from the EH branch, but after looking at the specific commits that would preserve, decided there wasn't anything in there worth preserving.

@AndyAyersMS
Copy link
Member

I don't feel strongly either way, just wanted your perspective.

LGTM.

JosephTremoulet added a commit that referenced this pull request Oct 22, 2015
@JosephTremoulet JosephTremoulet merged commit 97fa13f into master Oct 22, 2015
@@ -103,6 +104,7 @@ def main(argv):
parser.add_argument('-n', '--ngen', help='use ngened mscorlib', default=False, action="store_true")
parser.add_argument('-p', '--precise-gc', help='test with precise gc', default=False, action="store_true")
parser.add_argument('-v', '--verbose', help='echo commands', default=False, action="store_true")
parser.add_argument('-e', '--eh', help='enable exception handlers to run (as opposed to failfast)', default=False, action="store_true")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the llilc_runtest.py have the --eh option as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. Yeah, good catch, thanks. Will PR an update.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants