6.3 Non-Local Exits

The Catch and Unwind-Protect special forms are implemented using catch frames. Unwind-Protect builds a catch frame whose tag is the Catch-All object. The Catch miscop creates a catch frame for a given tag and PC to branch to in the current instruction. The Throw miscop looks up the stack by following the chain of catch frames until it finds a frame with a matching tag or a frame with the Catch-All object as its tag. If it finds a frame with a matching tag, that frame is “returned from,” and that function is resumed. If it finds a frame with the Catch-All object as its tag, that frame is “returned from,” and in addition, %SP-Internal-Throw-Tag is set to the tag being searched for. So that interrupted cleanup forms behave correctly, %SP-Internal-Throw-Tag should be bound to the Catch-All object before the Catch-All frame is built. The protected forms are then executed, and if %SP-Internal-Throw-Tag is not the Catch-All object, its value is thrown to. Exactly what we do is this:

  1. Put the contents of the Active-Catch register into a register, A. Put NIL into another register, B.
  2. If A is NIL, the tag we seek isn’t on the stack. Signal an Unseen-Throw-Tag error.
  3. Look at the tag for the catch frame in register A. If it’s the tag we’re looking for, go to step 4. If it’s the Catch-All object and B is NIL, copy A to B. Set A to the previous catch frame and go back to step 2.
  4. If B is non-NIL, we need to execute some cleanup forms. Return into B’s frame and bind %SP-Internal-Throw-Tag to the tag we’re searching for. When the cleanup forms are finished executing, they’ll throw to this tag again.
  5. If B is NIL, return into this frame, pushing the return value (or BLTing the multiple values if this frame accepts multiple values and there are multiple values).

If no form inside of a Catch results in a Throw, the catch frame needs to be removed from the stack before execution of the function containing the throw is resumed. For now, the value produced by the forms inside the Catch form are thrown to the tag. Some sort of specialized miscop could be used for this, but right now we’ll just go with the throw. The branch PC specified by a Catch miscop is part of the constants area of the function object, much like the function’s entry points.