Support IoContext and DurableObjectState unload event
Adds support for a new ctx.addEventListener("unload", () => { }); for both DurableObjectState and ExecutionContext. These now both inherit EventTarget and this is updated in the types as well.
The motivation for this is being able to provide better memory management for Wasm applications, where memory can be pre-emptively disposed without waiting for the GC. Because Wasm pages once allocated are never deallocated, avoiding unnecessary page allocations with eager freeing to begin with can be a big memory improvement.
It's implemented as an event target, after initially implementing an individual handler. The motivation being to use standard JS semantics instead of inventing our how handler system.
For ExecutionContext, the IoContext disposal will trigger the listeners while disabling further IO. And the same for DurableObejctState shutdown. Added support for a new configuration option to be able to more easily test this shutdown as well.
During shutdown, we asynchronously take a lock, then run a task with supressed IO to call the handlers, clear microtasks and terminate. Weak references are used in these to not run handlers if any of the context state was already disposed. In addition, the task is never even created if there are no unload handlers.
For performance, to avoid taking an async lock when there are no unload handlers, we use the setEventListenerCallback feature to note if handlers are registered, only taking the async lock when this indicates we need to.