Architectural stuff

New fields in the TSO:

Speculation frames

The info table for a speculation frame points to the static spec-depth configuration for that speculation point. (Points to, because the config is mutable, and the info table has to be adjacent to the (immutable) code.)

Abortion

Abortion is modelled by a special asynchronous exception ThreadAbort. When tearing frames off the stack, we start a new chunk at every speculation frame, as well as every update frame. We proceed down to the deepest speculation frame.

The AP_STACK closure built for a speculation frame must be careful not to enter the next AP_STACK closure up, because that would re-enter a possible loop.

Delivering an asynch exception to a thread that is speculating. Invariant: there can be no catch frames inside speculation (we abort in catch# when speculating. So the asynch exception just tears off frames in the standard way until it gets to a catch frame, just as it would usually do.

Abortion can punish one or more of the speculation frames by decrementing their static config variables.

Synchronous exceptions

Synchronous exceptions are treated similarly as before. The stack is discarded up to an update frame; the thunk to be updated is overwritten with "raise x", and the process continues. Until a catch frame.

When we find a spec frame, we allocate a "raise x" object, and resume execution with the return address in the spec frame. In that way the spec frame is like a catch frame; it stops the unwinding process.

It's essential that every hard failure is caught, else speculation is unsafe. In particular, divide by zero is hard to catch using OS support, so we test explicitly in library code. You can shoot yourself in the foot by writing x `div#` 0, side-stepping the test.

Online profiling

Sampling can be more frequent than minor GC (by jiggling the end-of-block code) but cannot be less frequent, because GC doesn't expect to see profiling frames.