-
-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor JSClosure to leverage FinalizationRegistry
#128
Conversation
I wonder if there's a good way to feature-flag it? It would be great to dynamically detect if This is another nudge towards enabling browser feature detection/versioning in |
I don’t think so — it would require substantially different API usage on the Swift side if it was unavailable unless we just wanted to leak memory on the Swift side. I’m not too concerned about compatibility because recent versions of most evergreen browsers support it, and Safari 14.1 is available on Mojave (10.14) and above, so most people should be OK with this, especially given the rate at which people are using SwiftWasm right now 😉 |
I understand, my concern is with economic accessibility here. There are enough old devices that will never get Safari 14.1 installed on them, and I would love Tokamak to support them. We also know some people researching Tokamak for use in production environment right now, that puts some constraints on browsers and devices compatibility too. |
I guess I’m not sure what the target audience would be. Mixpanel’s iOS adoption report shows that 90% of devices run iOS 14, and only 5% of devices run a version below iOS 13. Chrome seems to run on Android 5 and above (although I’m not 100% positive they will actually give you the latest version). Two other things to consider: First, SwiftWasm’s current build output is fairly large, making it difficult to use on mobile data plans or with cheaper phones. Second, I doubt the pool of devices that support SwiftWasm but not FinalizationRegistry is growing. |
After asking around, I was surprised to hear that requiring latest iOS is not such a problem for some devs. I'm happy to defer to Yuta on this after all. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall +1 👍 I want to merge change with feature flag like -D JAVASCRIPTKIT_WITHOUT_WEAKREF
as an escape hatch. What do you think about this?
@@ -10,40 +11,9 @@ public protocol JSClosureProtocol: JSValueCompatible { | |||
func release() | |||
} | |||
|
|||
/// `JSOneshotClosure` is a JavaScript function that can be called only once. | |||
public class JSOneshotClosure: JSObject, JSClosureProtocol { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you measure runtime performance between JSOneshotClosure
and JSClosure
for deallocation overhead?
I think deallocation that depends on GC cycle will increase memory usage while waiting until event loop frame.
(But I'm not sure how this overhead affects users experience 😅 )
sharedClosures[hostFuncRef] = nil | ||
} | ||
@available(*, deprecated, message: "JSClosure.release() is no longer necessary") | ||
public func release() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So JSClosure
in browsers without FinalizationRegistry
support won't be deallocated, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If FinalizationRegistry
is not supported, the JS side will crash on startup when it attempts to call new FinalizationRegistry()
.
I‘d be happy to merge with a feature flag, but I’m not sure how to implement it on the JS side. I guess I could conditionally construct the |
@j-f1 I think we can expose an API to get feature bit-flags from Swift side like: |
Just chiming in: Instead of a flag, there should a separate API for Further, I don't think this is really a concern at all. In a few short months Safari 15 will be out Safari 14.1 will be the "old" version. It should be considered very safe to assume minimum Safari 14.1 |
Think I'm fine proceeding with this approach after all without supporting older browsers. @kateinoigakukun do you think switching to |
521e855
to
43a33ee
Compare
Time Change: +1,909.75ms (18%) Total Time: 10,482ms
|
My recent updates to the JS side cause the |
@j-f1 what do you think would be the best way to benchmark how |
I don’t think benchmarks are the right way to evaluate this change. The primary result is to improve safety/ease of use by tying the lifetime of the Swift closure to that of the JS function. Since the benchmarks run above show no major performance changes, I’m not personally super concerned. |
Right, I was only interested if it was worth dropping manually-managed version altogether in favor of the garbage-collected one. @kateinoigakukun WDYT? |
|
closure.release()
andJSOneshotClosure
are no longer neededFinalizationRegistry
callsswjs_free_host_function
to remove the corresponding Swift closure from the global dictionary.JSClosure
removes the JS function from the heap. If the function isn’t being held somewhere else (such as inside an event handler), it will become eligible for garbage collection, and the Swift closure will be eventually released.JavaScriptHostFuncRef
is now obtained from a global “expando” variable becauseJSClosure { ... }; JSClosure { ... }
may reuse anObjectIdentifier
. If we decide to add multithreading, we should be careful to only modifyclosureRef
using a lock.WeakRef
/FinalizationRegistry
Fixes #106.