Bob Congdon’s blog points out that in the dark days before exception handling you could always use setjmp
and longjmp
to do non-local gotos.
In fact, the script engines are compiled in C++ with exception handling turned off (for performance reasons), and the mainline loop of the bytecode interpreter uses setjmp
–longjmp
exception handling to implement error handling. When you have a script that calls an object that returns an error, we longjmp
back to the start of the interpreter loop and then figure out what to do next.
In VBScript of course it depends on whether On Error Resume Next
is on or not, and in JScript we construct an exception object and start propagating it back up the stack until we find an interpreter frame that has a catch block. (If there are multiple script engines on the stack then things get extremely complicated, so I won’t even go there.)
Since a long jump does not call any destructors, it was very important that we design our interpreter loop to not put anything on the system stack that required destructing. Fortunately, since we were designing the interpreter to be an interpreter for a garbage-collected language, it was pretty easy. Everything that the interpreter does that requires memory either takes the memory out of the area reserved for the script’s stack (which will be cleaned up when the frame goes away) or heap-allocates it and adds the memory to the garbage collector.
Not everyone has the luxury of having a longjmp-safe garbage collector already implemented, so kids, don’t try this at home! If you must use exception handling in C++, take my advice and use real C++ exception handling.
Reflections from 2019:
As I noted in my previous article on this subject, it’s important to think about what kind of costs exception handling imposes; why did we turn off exception handling in the C++ compiler to get a performance win?
The overall cost, not the per-exception cost, killed our performance on the server. Exception handling adds additional code to every function, and that additional code has a nonzero run time. Since the purpose of the code — handling exceptions — was never going to be fulfilled because we never threw an exception, we turned it off.
A reader asked me for the numbers justifying that decision, which I had measured on a Pentium 1 seven years prior to writing this article in 2003, so I declined to speculate. But it was significant.
Some people consider the “X considered harmful” trope to be overplayed or, irony, harmful. Obviously I don’t feel the same way, as I’ve used it many times. It’s playful, it points to history, and it takes a stand. Like anything, it can be overused.
Pingback: Porting old posts, part 4 | Fabulous adventures in coding