Swift’s Error Handling Implementation
Swift 3 works by essentially automating Objective-C’s
NSError
convention. The compiler inserts an extra, hidden parameter which is essentiallyError *
, orNSError **
. 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 thecatch
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.
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 […]