Scratchspaces
This is the mechanism behind the lifetime split in the quick start: buffers a pass needs only while it runs are allocated inside the frame and die with the block, while buffers the caller must outlive are allocated from the unframed space before the block opens.
Both forms bind their frame as the ambient space for the block, so the ambient space is always the innermost open frame.
Pol.scratchspace — Function
scratchspace(f, space)An allocation frame on space: calls f with a Frame, which is also the ambient space for the block —
scratchspace(space) do frame
softmax!(y, x; scratch(frame, softmax!, x)...)
endOn an Arena the frame carries a mark, retracted when the block closes, also on a throw — everything carved inside is reclaimed. On any other space the frame records each buffer it materializes and release!s them all at close — a no-op for GC-owned arrays, eager reclamation where an overload provides it. Frames nest: opening a frame on a frame stacks a new one on the same space.
Inside the block the ambient space (ambientspace) is the frame: once a frame is open, nothing should allocate from outside it implicitly, so every frame-opening rebinds. The frame argument is therefore redundant for lifetime — but it is the concretely-typed spelling: ambient reads are dynamically dispatched, alloc(frame, ...) infers.
Buffers allocated from the frame are only valid inside the block. Allocating from the unframed space — outputs before the block opens — is what gives a buffer the caller's lifetime.
scratchspace(f)The ambient form: a frame on ambientspace, rebound as ambient for the block — f is called with no arguments, and everything inside allocates from the frame by default:
scratchspace() do
tmp = alloc(Float32, n) # carved from this block's frame
y = softmax(x) # an Allocating verb: outputs too
end # frame retractsThe invariant both forms maintain: the ambient space is always the innermost open frame. The closure receives no frame because it needs no frame — an allocation that must outlive the block is the case that deserves the explicit space-first spelling.
Pol.Frame — Type
FrameThe abstract supertype of allocation frames — the framed space a scratchspace block passes. A frame is a Space whose buffers are reclaimed when its block closes, and proof of being inside one: the one-step scratch form materializes against a Frame only.
Pol.release! — Function
release!(buffer)Release one frame buffer back to its space when a scratchspace block closes. The default is a no-op — GC-owned buffers just become garbage. Array families that benefit from eager reclamation overload it on the buffer type; a package extension already provides release!(x::AbstractGPUArray) = GPUArrays.unsafe_free!(x), freeing the device memory immediately instead of when the GC finalizes the array.