Thursday, August 31, 2017

Swift’s Error Handling Implementation

Mike Ash:

Swift 3 works by essentially automating Objective-C’s NSError convention. The compiler inserts an extra, hidden parameter which is essentially Error *, or NSError **. Throwing an error consists of writing the error object to the pointer passed in that parameter. The caller allocates some stack space and passes its address in that parameter. On return, it checks to see if that space now contains an error. If it does, it jumps to the catch block.

Swift 4 gets a little fancier. The basic idea is the same, but instead of a normal extra parameter, a special register is reserved for the error return.

Joe Groff:

Some more fun trivia: r12 and x21 were specifically chosen because they’re normally callee-saved registers, so a non-throwing function can be “toll-free bridged” as a throwing one, since the non-throwing ABI will always preserve null in the error register.


One of the arguments against manual propagation of errors has long been the code size and performance cost at each call, but Swift’s ABI does a pretty good job of minimizing the cost without getting too avant-garde—it’s one instruction to zero out the error register at the boundary where you enter a “throws” context, and one instruction (on ARM64 at least, though still one fused uop on Intel) to jump-if-not-zero into the catch block after each call that might throw.

2 Comments RSS · Twitter

[…] Swift.Codable, Swift 4: Key-Value Observation, Swift’s Error Handling Implementation, Swift 4: Bridging Peephole for “as” Casts, Swift 4: Synthesizing Equatable and […]

[…] Swift’s Error Handling Implementation […]

Leave a Comment