@@ -87,12 +87,13 @@ const (
8787// on an immutable snapshot. This avoids data races without requiring
8888// the reader to take a lock (which is important because the reader runs
8989// on the system stack during stack unwinding and signal handling).
90- const maxUserFrameRegions = 64
9190
9291// userFrameSnapshot is the immutable snapshot published to readers.
92+ // regions is a variable-length trailing array allocated by
93+ // allocUserFrameSnapshot.
9394type userFrameSnapshot struct {
94- regions [maxUserFrameRegions ]userFrameRegion
9595 count int
96+ regions [1 ]userFrameRegion
9697}
9798
9899var (
@@ -109,6 +110,29 @@ func loadUserFrameSnapshot() *userFrameSnapshot {
109110 return (* userFrameSnapshot )(p )
110111}
111112
113+ func allocUserFrameSnapshot (count int ) * userFrameSnapshot {
114+ if count < 0 {
115+ throw ("registerUserFrameRegion: too many regions" )
116+ }
117+ regionBytes := uintptr (count ) * unsafe .Sizeof (userFrameRegion {})
118+ if count != 0 && regionBytes / unsafe .Sizeof (userFrameRegion {}) != uintptr (count ) {
119+ throw ("registerUserFrameRegion: too many regions" )
120+ }
121+ bytes := unsafe .Offsetof (userFrameSnapshot {}.regions ) + regionBytes
122+ if bytes < regionBytes {
123+ throw ("registerUserFrameRegion: too many regions" )
124+ }
125+ mem := persistentalloc (bytes , unsafe .Alignof (userFrameSnapshot {}), & memstats .other_sys )
126+ snap := (* userFrameSnapshot )(mem )
127+ snap .count = count
128+ return snap
129+ }
130+
131+ //go:nosplit
132+ func (snap * userFrameSnapshot ) region (i int ) * userFrameRegion {
133+ return (* userFrameRegion )(add (unsafe .Pointer (snap ), unsafe .Offsetof (userFrameSnapshot {}.regions )+ uintptr (i )* unsafe .Sizeof (userFrameRegion {})))
134+ }
135+
112136func registerUserFrameRegion (r userFrameRegion ) uintptr {
113137 if r .start >= r .end {
114138 throw ("registerUserFrameRegion: invalid address range" )
@@ -122,14 +146,9 @@ func registerUserFrameRegion(r userFrameRegion) uintptr {
122146 oldCount = old .count
123147 }
124148
125- if oldCount >= maxUserFrameRegions {
126- unlock (& userFrameLock )
127- throw ("registerUserFrameRegion: too many regions" )
128- }
129-
130149 // Check for overlaps.
131150 for i := 0 ; i < oldCount ; i ++ {
132- fr := & old .regions [ i ]
151+ fr := old .region ( i )
133152 if r .start < fr .end && r .end > fr .start {
134153 unlock (& userFrameLock )
135154 throw ("registerUserFrameRegion: overlapping region" )
@@ -141,27 +160,25 @@ func registerUserFrameRegion(r userFrameRegion) uintptr {
141160 r .handle = userFrameHandle
142161
143162 // Build new snapshot with the region inserted in sorted order.
144- mem := persistentalloc (unsafe .Sizeof (userFrameSnapshot {}), unsafe .Sizeof (uintptr (0 )), & memstats .other_sys )
145- snap := (* userFrameSnapshot )(mem )
163+ snap := allocUserFrameSnapshot (oldCount + 1 )
146164
147165 pos := oldCount
148166 for i := 0 ; i < oldCount ; i ++ {
149- if r .start < old .regions [ i ] .start {
167+ if r .start < old .region ( i ) .start {
150168 pos = i
151169 break
152170 }
153171 }
154172 // Copy elements before pos.
155173 for i := 0 ; i < pos ; i ++ {
156- snap .regions [ i ] = old .regions [ i ]
174+ * snap .region ( i ) = * old .region ( i )
157175 }
158176 // Insert new region.
159- snap .regions [ pos ] = r
177+ * snap .region ( pos ) = r
160178 // Copy elements after pos.
161179 for i := pos ; i < oldCount ; i ++ {
162- snap .regions [ i + 1 ] = old .regions [ i ]
180+ * snap .region ( i + 1 ) = * old .region ( i )
163181 }
164- snap .count = oldCount + 1
165182
166183 // Publish atomically. Readers will see the complete new snapshot.
167184 atomic .StorepNoWB (unsafe .Pointer (& userFrameSnap ), unsafe .Pointer (snap ))
@@ -182,7 +199,7 @@ func unregisterUserFrameRegion(handle uintptr) {
182199 // Find the region.
183200 idx := - 1
184201 for i := 0 ; i < old .count ; i ++ {
185- if old .regions [ i ] .handle == handle {
202+ if old .region ( i ) .handle == handle {
186203 idx = i
187204 break
188205 }
@@ -193,17 +210,14 @@ func unregisterUserFrameRegion(handle uintptr) {
193210 }
194211
195212 // Build new snapshot without the region.
196- mem := persistentalloc (unsafe .Sizeof (userFrameSnapshot {}), unsafe .Sizeof (uintptr (0 )), & memstats .other_sys )
197- snap := (* userFrameSnapshot )(mem )
213+ snap := allocUserFrameSnapshot (old .count - 1 )
198214 j := 0
199215 for i := 0 ; i < old .count ; i ++ {
200216 if i != idx {
201- snap .regions [ j ] = old .regions [ i ]
217+ * snap .region ( j ) = * old .region ( i )
202218 j ++
203219 }
204220 }
205- snap .count = old .count - 1
206-
207221 atomic .StorepNoWB (unsafe .Pointer (& userFrameSnap ), unsafe .Pointer (snap ))
208222
209223 unlock (& userFrameLock )
@@ -222,12 +236,13 @@ func findUserFrameRegion(pc uintptr) *userFrameRegion {
222236 lo , hi := 0 , snap .count
223237 for lo < hi {
224238 mid := int (uint (lo + hi ) >> 1 )
225- if snap .regions [mid ].end <= pc {
239+ region := snap .region (mid )
240+ if region .end <= pc {
226241 lo = mid + 1
227- } else if snap . regions [ mid ] .start > pc {
242+ } else if region .start > pc {
228243 hi = mid
229244 } else {
230- return & snap . regions [ mid ]
245+ return region
231246 }
232247 }
233248 return nil
@@ -435,7 +450,7 @@ func jit_addUserFrameStackMaps(handle uintptr, stackMaps []userFrameStackMapInpu
435450 snap := loadUserFrameSnapshot ()
436451 if snap != nil {
437452 for i := 0 ; i < snap .count ; i ++ {
438- r := & snap .regions [ i ]
453+ r := snap .region ( i )
439454 if r .handle == handle {
440455 appendUserFrameStackMaps (r .stackMaps , r .start , r .end , r .unwindMode , stackMaps )
441456 unlock (& userFrameLock )
0 commit comments