How does C++ exception handling translate to machine code
Asked Answered
R

3

47

Mentally, I've always wondered how try/throw/catch looks behind the scenes, when the C++ compiles translates it to assembler. But since I never use it, I never got around to checking it out (some people would say lazy).

Is the normal stack used for keeping track of trys, or is a separate per-thread stack kept for this purpose alone? Is the implementation between MSVC and g++ big or small? Please show me some pseudo asm (IA-32 is ok too) so I never have to check it out myself! :)

Edit: Now I get the basics of MSVC's implementation on IA-32 handling. Anybody know for g++ on IA-32, or any other CPU for that matter?

Edit 2 (11 years later): Here are some data on performance. They've also made source code freely available.

Rijeka answered 25/8, 2009 at 21:48 Comment(0)
S
26

Poor implementations of exception handlers push some kind of exception handler block for each try clause on the runtime stack as the try clause is entered, and pop it off as the try clause is exited. A location holding the address of the most recently pushed exception handler block is also maintained. Typically these exception handlers are chained together so they can be found by following links from the most recent to older versions. When an exception occurs, a pointer to the last-pushed EH handler block is found, and processing of that "try" clause's EH cases is checked. A hit on an EH case causes stack cleanup to occur back to the point of pushed EH, and control transfers to the EH case. No hits on the EH causes the next EH to be found, and the process repeats. The Windows 32-bit SEH scheme is a version of this.

This is a poor implementation because the program pays a runtime price for each try clause (push then pop) even when no exception occurs.

Good implementations simply record a table of ranges where try clauses occur. This means there's zero overhead to enter/exit a try clause. (My PARLANSE parallell programming langauge uses this technique). An exception looks up the PC of the exception point in the table, and passes control to the EH selected by the table. The EH code resets the stack as appropriate. Fast and pretty. I think the Windows 64 bit EH is of this type, but I haven't looked carefully.

[EDIT April 2020: Just measured the cost of PARLANSE exceptions recently. 0nS (by design) if no exception; 25ns on an 3Ghz i7 from "throw" to "catch" to "acknowledge" (end empty catch). OP added a link measuring C++ exception handling at roughly 1000ns for the simplest kind, and a literally nonStandard handling scheme that clocks in at 57ns for exception or no exception; CPU clock rates for the C++ versions are a bit slower so these numbers are only for rough comparison.]

Sartin answered 25/8, 2009 at 22:5 Comment(6)
The link is dead.Eighth
@Kowalski: thanks for pointing that out. Link fixed.Sartin
@IraBaxter The PARLANSE link is not working for me (connection timed out). I googled it and same issue occurring there.Papaw
@Sourav: We're in Austin TX, just recieved 6 inches of snow (century record) and power is off all over the city -> our servers are down. Hold your breath for 1/2 day and try again.Sartin
@IraBaxter Suppose a hypothetical language provides concise and cleaner syntax to write error-code base handling style, then which one would you prefer? error-code or exceptions?Papaw
Exceptions, especially those that have zero cost when they don't happen. a) you don't have write an error code test that checks for every error at every point where one might occur, and b) it keeps the cost of the error checking way down. PARLANSE has had this nice property for the last 20 years.Sartin
G
5

The C++ standard committee published a technical report on "C++ performance" to debunk many myths about how C++ features supposedly slow you down. This also includes details about how exception handling could be implemented. The draft of this technical report is available for free. Check section 5.4.1. "Exception Handling Implementation Issues and Techniques".

Graiae answered 3/10, 2009 at 6:37 Comment(0)
D
2

Asm from the Godbolt compiler explorer, for the x86-64 System V calling convention with g++8.2's C++ABI, for a function that catches, and one that throws.

x86-64 System V uses the .eh_frame section for stack-unwind metadata, so the exception-helper library functions know how to walk the stack and restore registers. That's what .cfi directives do.

Disciplinarian answered 3/8, 2018 at 8:57 Comment(1)
I couldn't decide whether to post this barely-an-answer as a comment or not. I went with answer, even though I didn't take the time to get into details or show and comment the code.Disciplinarian

© 2022 - 2024 — McMap. All rights reserved.