-
Notifications
You must be signed in to change notification settings - Fork 13
/
monotonic_arena.go
93 lines (77 loc) · 2.11 KB
/
monotonic_arena.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// SPDX-License-Identifier: Apache-2.0
package nuke
import (
"unsafe"
)
type monotonicArena struct {
buffers []*monotonicBuffer
}
type monotonicBuffer struct {
ptr unsafe.Pointer
offset uintptr
size uintptr
}
func newMonotonicBuffer(size int) *monotonicBuffer {
return &monotonicBuffer{size: uintptr(size)}
}
func (s *monotonicBuffer) alloc(size, alignment uintptr) (unsafe.Pointer, bool) {
if s.ptr == nil {
buf := make([]byte, s.size) // allocate monotonic buffer lazily
s.ptr = unsafe.Pointer(unsafe.SliceData(buf))
}
alignOffset := uintptr(0)
for alignedPtr := uintptr(s.ptr) + s.offset; alignedPtr%alignment != 0; alignedPtr++ {
alignOffset++
}
allocSize := size + alignOffset
if s.availableBytes() < allocSize {
return nil, false
}
ptr := unsafe.Pointer(uintptr(s.ptr) + s.offset + alignOffset)
s.offset += allocSize
// This piece of code will be translated into a runtime.memclrNoHeapPointers
// invocation by the compiler, which is an assembler optimized implementation.
// Architecture specific code can be found at src/runtime/memclr_$GOARCH.s
// in Go source (since https://codereview.appspot.com/137880043).
b := unsafe.Slice((*byte)(ptr), size)
for i := range b {
b[i] = 0
}
return ptr, true
}
func (s *monotonicBuffer) reset(release bool) {
if s.offset == 0 {
return
}
s.offset = 0
if release {
s.ptr = nil
}
}
func (s *monotonicBuffer) availableBytes() uintptr {
return s.size - s.offset
}
// NewMonotonicArena creates a new monotonic arena with a specified number of buffers and a buffer size.
func NewMonotonicArena(bufferSize, bufferCount int) Arena {
a := &monotonicArena{}
for i := 0; i < bufferCount; i++ {
a.buffers = append(a.buffers, newMonotonicBuffer(bufferSize))
}
return a
}
// Alloc satisfies the Arena interface.
func (a *monotonicArena) Alloc(size, alignment uintptr) unsafe.Pointer {
for i := 0; i < len(a.buffers); i++ {
ptr, ok := a.buffers[i].alloc(size, alignment)
if ok {
return ptr
}
}
return nil
}
// Reset satisfies the Arena interface.
func (a *monotonicArena) Reset(release bool) {
for _, s := range a.buffers {
s.reset(release)
}
}