@@ -10,12 +10,16 @@ import BridgeJSUtilities
1010public struct BridgeJSLink {
1111 var skeletons : [ BridgeJSSkeleton ] = [ ]
1212 let sharedMemory : Bool
13+ /// Whether to track the lifetime of Swift objects.
14+ ///
15+ /// This is useful for debugging memory issues.
16+ let enableLifetimeTracking : Bool = false
1317 private let namespaceBuilder = NamespaceBuilder ( )
1418 private let intrinsicRegistry = JSIntrinsicRegistry ( )
1519
1620 public init (
1721 skeletons: [ BridgeJSSkeleton ] = [ ] ,
18- sharedMemory: Bool
22+ sharedMemory: Bool = false
1923 ) {
2024 self . skeletons = skeletons
2125 self . sharedMemory = sharedMemory
@@ -50,37 +54,76 @@ public struct BridgeJSLink {
5054 }
5155 """
5256
53- let swiftHeapObjectClassJs = """
54- const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === " undefined " ) ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => {
55- if (state.hasReleased) {
56- return;
57- }
58- state.hasReleased = true;
59- state.deinit(state.pointer);
60- });
57+ let lifetimeTrackingClassJs = """
58+ const TRACKING = {
59+ wrap: (pointer, deinit, prototype, state) => {
60+ console.log(JSON.stringify({ DEBUG: true, event: " WRP " , class: prototype.constructor.name, state }));
61+ },
62+ release: (obj) => {
63+ console.log(JSON.stringify({ DEBUG: true, event: " REL " , class: obj.constructor.name, state: obj.__swiftHeapObjectState }));
64+ },
65+ finalization: (state) => {
66+ console.log(JSON.stringify({ DEBUG: true, event: " FIN " , state }));
67+ }
68+ };
69+ """
6170
62- /// Represents a Swift heap object like a class instance or an actor instance.
63- class SwiftHeapObject {
64- static __wrap(pointer, deinit, prototype) {
65- const obj = Object.create(prototype);
66- const state = { pointer, deinit, hasReleased: false };
67- obj.pointer = pointer;
68- obj.__swiftHeapObjectState = state;
69- swiftHeapObjectFinalizationRegistry.register(obj, state, state);
70- return obj;
71- }
72-
73- release() {
74- const state = this.__swiftHeapObjectState;
71+ var swiftHeapObjectClassJs : String {
72+ var output = " "
73+ if enableLifetimeTracking {
74+ output += lifetimeTrackingClassJs + " \n "
75+ }
76+ output += """
77+ const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === " undefined " ) ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(( state) => {
78+
79+ """
80+ if enableLifetimeTracking {
81+ output += " TRACKING.finalization(state); \n "
82+ }
83+ output += """
7584 if (state.hasReleased) {
7685 return;
7786 }
7887 state.hasReleased = true;
79- swiftHeapObjectFinalizationRegistry.unregister(state);
8088 state.deinit(state.pointer);
81- }
89+ });
90+
91+ /// Represents a Swift heap object like a class instance or an actor instance.
92+ class SwiftHeapObject {
93+ static __wrap(pointer, deinit, prototype) {
94+ const obj = Object.create(prototype);
95+ const state = { pointer, deinit, hasReleased: false };
96+
97+ """
98+ if enableLifetimeTracking {
99+ output += " TRACKING.wrap(pointer, deinit, prototype, state); \n "
82100 }
83- """
101+ output += """
102+ obj.pointer = pointer;
103+ obj.__swiftHeapObjectState = state;
104+ swiftHeapObjectFinalizationRegistry.register(obj, state, state);
105+ return obj;
106+ }
107+
108+ release() {
109+
110+ """
111+ if enableLifetimeTracking {
112+ output += " TRACKING.release(this); \n "
113+ }
114+ output += """
115+ const state = this.__swiftHeapObjectState;
116+ if (state.hasReleased) {
117+ return;
118+ }
119+ state.hasReleased = true;
120+ swiftHeapObjectFinalizationRegistry.unregister(state);
121+ state.deinit(state.pointer);
122+ }
123+ }
124+ """
125+ return output
126+ }
84127
85128 fileprivate struct LinkData {
86129 var exportsLines : [ String ] = [ ]
0 commit comments