The new API allows managing JS closures converted from Swift closures
from Swift side. It allows us to get the underlying `JSObject` and
manage its lifetime manually from Swift.
```swift
@js func makeIntToInt() throws(JSException) -> JSTypedClosure<(Int) -> Int> {
return JSTypedClosure { x in
return x + 1
}
}
@JSFunction func takeIntToInt(_ transform: JSTypedClosure<(Int) -> Int>) throws(JSException)
let closure = JSTypedClosure<(Int) -> Int> { x in
return x * 2
}
defer { closure.release() }
try takeIntToInt(closure)
```
Likewise to `JSClosure`, API users are responsible for "manually" releasing the
closure when it's no longer needed by calling `release()`. After releasing,
the closure becomes unusable and calling it will throw a JS exception
(note that we will not segfault even if the closure is called after releasing).
```swift
let closure = JSTypedClosure<(Int) -> Int> { x in
return x * 2
}
closure.release()
try closure(10) // "JSException: Attempted to call a released JSTypedClosure created at <file>:<line>"
```
As a belt-and-suspenders measure, the underlying JS closure is also
registered with a `FinalizationRegistry` to ensure that the Swift closure box
is released when the JS closure is garbage collected, in case the API user
forgets to call `release()`. However, relying on this mechanism is **not recommended**
because the timing of garbage collection is non-deterministic and it's
not guaranteed that it will happen in a timely manner.
----
On the top of the new API, this commit also fixes memory leak issues of
closures exported to JS.