Skip to content

Commit

Permalink
Make JavaScriptBridge use weak references to JSValues
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyMDev committed Oct 23, 2023
1 parent 6218e97 commit 11b6456
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions apollo-ios-codegen/Sources/GraphQLCompiler/JavaScriptBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,20 @@ actor JavaScriptBridge {
}
}

private struct WeakValue: Hashable {
weak var value: JSValue?
var id: ObjectIdentifier

init(_ value: JSValue) {
self.value = value
self.id = ObjectIdentifier(value)
}

func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}

private let virtualMachine = JSVirtualMachine()

let context: JSContext
Expand All @@ -220,11 +234,11 @@ actor JavaScriptBridge {

/// We keep a map between `JSValue` objects and wrapper objects, to avoid repeatedly creating new
/// wrappers and to guarantee referential equality.
/// TODO: We may want to consider making the keys weak here, because this does mean we'll be
/// keeping alive all objects that are passed over the bridge in JavaScript.
/// Making the keys weak here, prevents us from keeping alive all objects that are passed over
/// the bridge in JavaScript.
/// ('JSValue` is an Objective-C object that uses `JSValueProtect` to mark the underlying
/// JavaScript object as ineligible for garbage collection.)
private var wrapperMap: [JSValue: WeakRef] = [:]
private var wrapperMap: [WeakValue: WeakRef] = [:]

init() async throws {
guard let context = JSContext(virtualMachine: virtualMachine) else {
Expand Down Expand Up @@ -262,7 +276,9 @@ actor JavaScriptBridge {
func getReferenceOrInitialize<Wrapper: JavaScriptReferencedObject>(
_ jsValue: JSValue
) -> Wrapper {
if let wrapper = wrapperMap[jsValue]?.value {
precondition(jsValue.context === self.context)
let weakJSValue = WeakValue(jsValue)
if let wrapper = wrapperMap[weakJSValue]?.value {
return checkedDowncast(wrapper)
}

Expand All @@ -278,7 +294,7 @@ actor JavaScriptBridge {
}

let wrapper = wrapperType.init(jsValue, bridge: self)
wrapperMap[jsValue] = WeakRef(wrapper)
wrapperMap[weakJSValue] = WeakRef(wrapper)
wrapper.finalize(jsValue, bridge: self)
return checkedDowncast(wrapper)
}
Expand Down

0 comments on commit 11b6456

Please sign in to comment.