@@ -1167,6 +1167,15 @@ var globalAlloc struct {
1167
1167
persistentAlloc
1168
1168
}
1169
1169
1170
+ // persistentChunkSize is the number of bytes we allocate when we grow
1171
+ // a persistentAlloc.
1172
+ const persistentChunkSize = 256 << 10
1173
+
1174
+ // persistentChunks is a list of all the persistent chunks we have
1175
+ // allocated. The list is maintained through the first word in the
1176
+ // persistent chunk. This is updated atomically.
1177
+ var persistentChunks * notInHeap
1178
+
1170
1179
// Wrapper around sysAlloc that can allocate small chunks.
1171
1180
// There is no associated free operation.
1172
1181
// Intended for things like function/type/debug-related persistent data.
@@ -1187,7 +1196,6 @@ func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
1187
1196
//go:systemstack
1188
1197
func persistentalloc1 (size , align uintptr , sysStat * uint64 ) * notInHeap {
1189
1198
const (
1190
- chunk = 256 << 10
1191
1199
maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
1192
1200
)
1193
1201
@@ -1218,15 +1226,24 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) *notInHeap {
1218
1226
persistent = & globalAlloc .persistentAlloc
1219
1227
}
1220
1228
persistent .off = round (persistent .off , align )
1221
- if persistent .off + size > chunk || persistent .base == nil {
1222
- persistent .base = (* notInHeap )(sysAlloc (chunk , & memstats .other_sys ))
1229
+ if persistent .off + size > persistentChunkSize || persistent .base == nil {
1230
+ persistent .base = (* notInHeap )(sysAlloc (persistentChunkSize , & memstats .other_sys ))
1223
1231
if persistent .base == nil {
1224
1232
if persistent == & globalAlloc .persistentAlloc {
1225
1233
unlock (& globalAlloc .mutex )
1226
1234
}
1227
1235
throw ("runtime: cannot allocate memory" )
1228
1236
}
1229
- persistent .off = 0
1237
+
1238
+ // Add the new chunk to the persistentChunks list.
1239
+ for {
1240
+ chunks := uintptr (unsafe .Pointer (persistentChunks ))
1241
+ * (* uintptr )(unsafe .Pointer (persistent .base )) = chunks
1242
+ if atomic .Casuintptr ((* uintptr )(unsafe .Pointer (& persistentChunks )), chunks , uintptr (unsafe .Pointer (persistent .base ))) {
1243
+ break
1244
+ }
1245
+ }
1246
+ persistent .off = sys .PtrSize
1230
1247
}
1231
1248
p := persistent .base .add (persistent .off )
1232
1249
persistent .off += size
@@ -1242,6 +1259,21 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) *notInHeap {
1242
1259
return p
1243
1260
}
1244
1261
1262
+ // inPersistentAlloc reports whether p points to memory allocated by
1263
+ // persistentalloc. This must be nosplit because it is called by the
1264
+ // cgo checker code, which is called by the write barrier code.
1265
+ //go:nosplit
1266
+ func inPersistentAlloc (p uintptr ) bool {
1267
+ chunk := atomic .Loaduintptr ((* uintptr )(unsafe .Pointer (& persistentChunks )))
1268
+ for chunk != 0 {
1269
+ if p >= chunk && p < chunk + persistentChunkSize {
1270
+ return true
1271
+ }
1272
+ chunk = * (* uintptr )(unsafe .Pointer (chunk ))
1273
+ }
1274
+ return false
1275
+ }
1276
+
1245
1277
// linearAlloc is a simple linear allocator that pre-reserves a region
1246
1278
// of memory and then maps that region as needed. The caller is
1247
1279
// responsible for locking.
0 commit comments