The performance overhead comes from grabbing a stack trace and constructing an object that lives on the heap, and then unwinding the stack. (Some assembly experts can probably explain this overhead better than I can.). When your code handles an error condition that it anticipates, that overhead is wasted CPU cycles.
(This is why Exceptions aren't for flow control.)
What we really need are languages that differentiate better among success / error / exception. Go has panic / resume, and Java has compiler-enforced exception handling, unless it's a runtime exception.
What I want instead is something where I have optional and convenient syntax to handle lightweight errors; or the ability to automatically convert errors to exceptions if I don't handle them.
TLDR:
Think of the query to lookup a record by ID case. If the record isn't found, it's an error that doesn't have a stacktrace or an object on the heap. But, if my code doesn't handle the error, then it's a full exception with a stacktrace.