Skip to content

Commit de328ff

Browse files
committed
Prevent early deallocation of object references
1 parent cba6775 commit de328ff

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

Diff for: IntegrationTests/JavaScriptKitExec/Sources/JavaScriptKitExec/main.swift

+24
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,27 @@ Object_Conversion: do {
299299
} catch {
300300
print(error)
301301
}
302+
303+
ObjectRef_Lifetime: do {
304+
// ```js
305+
// global.globalObject1 = {
306+
// "prop_1": {
307+
// "nested_prop": 1,
308+
// },
309+
// "prop_2": 2,
310+
// "prop_3": true,
311+
// "prop_4": [
312+
// 3, 4, "str_elm_1", 5,
313+
// ],
314+
// ...
315+
// }
316+
// ```
317+
318+
let identity = JSClosure { $0[0] }
319+
let ref1 = getJSValue(this: .global, name: "globalObject1").object!
320+
let ref2 = identity(ref1).object!
321+
try expectEqual(ref1.prop_2, .number(2))
322+
try expectEqual(ref2.prop_2, .number(2))
323+
} catch {
324+
print(error)
325+
}

Diff for: Sources/JavaScriptKit/JSObject.swift

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
import _CJavaScriptKit
22

3+
private struct Weak<T: AnyObject> {
4+
weak var ref: T?
5+
}
6+
7+
private var cache = [UInt32: Weak<JSObjectRef>]()
8+
39
@dynamicMemberLookup
410
public class JSObjectRef: Equatable {
511
internal var id: UInt32
612
init(id: UInt32) {
713
self.id = id
814
}
915

16+
static func retrieve(id: UInt32) -> JSObjectRef {
17+
if id != 0, let ref = cache[id]?.ref {
18+
return ref
19+
} else {
20+
let ref = JSObjectRef(id: id)
21+
cache[id] = Weak(ref: ref)
22+
return ref
23+
}
24+
}
25+
1026
@_disfavoredOverload
1127
public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? {
1228
get {
@@ -46,7 +62,9 @@ public class JSObjectRef: Equatable {
4662
static let _JS_Predef_Value_Global: UInt32 = 0
4763
public static let global = JSObjectRef(id: _JS_Predef_Value_Global)
4864

49-
deinit { _destroy_ref(id) }
65+
deinit {
66+
_destroy_ref(id)
67+
}
5068

5169
public static func == (lhs: JSObjectRef, rhs: JSObjectRef) -> Bool {
5270
return lhs.id == rhs.id

Diff for: Sources/JavaScriptKit/JSValueConvertible.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ extension RawJSValue: JSValueConvertible {
111111
let string = String(decodingCString: UnsafePointer(buffer), as: UTF8.self)
112112
return .string(string)
113113
case JavaScriptValueKind_Object:
114-
return .object(JSObjectRef(id: UInt32(payload1)))
114+
return .object(JSObjectRef.retrieve(id: UInt32(payload1)))
115115
case JavaScriptValueKind_Null:
116116
return .null
117117
case JavaScriptValueKind_Undefined:

0 commit comments

Comments
 (0)