Skip to content

Commit c8bb418

Browse files
aykevlydnar
authored andcommitted
wasm: fix C realloc and optimize it a bit
- Do not use make([]byte, ...) to allocate, instead allocate a slice of pointers. This makes sure the precise GC will scan the contents of the allocation, since C could very well put pointers in there. - Simplify the map to use the pointer as the key and the size as the value, instead of storing the slices directly in the map.
1 parent 8e36345 commit c8bb418

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

src/runtime/arch_tinygowasm_malloc.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ import "unsafe"
88
// code linked from other languages can allocate memory without colliding with
99
// our GC allocations.
1010

11-
var allocs = make(map[uintptr][]byte)
11+
// Map of allocations, where the key is the allocated pointer and the value is
12+
// the size of the allocation.
13+
var allocs = make(map[unsafe.Pointer]uintptr)
1214

1315
//export malloc
1416
func libc_malloc(size uintptr) unsafe.Pointer {
1517
if size == 0 {
1618
return nil
1719
}
18-
buf := make([]byte, size)
20+
const wordSize = unsafe.Sizeof(unsafe.Pointer(nil))
21+
buf := make([]unsafe.Pointer, (size+wordSize-1)/wordSize)
1922
ptr := unsafe.Pointer(&buf[0])
20-
allocs[uintptr(ptr)] = buf
23+
allocs[ptr] = size
2124
return ptr
2225
}
2326

@@ -26,8 +29,8 @@ func libc_free(ptr unsafe.Pointer) {
2629
if ptr == nil {
2730
return
2831
}
29-
if _, ok := allocs[uintptr(ptr)]; ok {
30-
delete(allocs, uintptr(ptr))
32+
if _, ok := allocs[ptr]; ok {
33+
delete(allocs, ptr)
3134
} else {
3235
panic("free: invalid pointer")
3336
}
@@ -48,18 +51,22 @@ func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer {
4851

4952
// It's hard to optimize this to expand the current buffer with our GC, but
5053
// it is theoretically possible. For now, just always allocate fresh.
51-
buf := make([]byte, size)
54+
// TODO: we could skip this if the new allocation is smaller than the old.
55+
const wordSize = unsafe.Sizeof(unsafe.Pointer(nil))
56+
buf := make([]unsafe.Pointer, (size+wordSize-1)/wordSize)
57+
ptr := unsafe.Pointer(&buf[0])
5258

5359
if oldPtr != nil {
54-
if oldBuf, ok := allocs[uintptr(oldPtr)]; ok {
55-
copy(buf, oldBuf)
56-
delete(allocs, uintptr(oldPtr))
60+
if oldSize, ok := allocs[oldPtr]; ok {
61+
oldBuf := unsafe.Slice((*byte)(oldPtr), oldSize)
62+
newBuf := unsafe.Slice((*byte)(ptr), size)
63+
copy(newBuf, oldBuf)
64+
delete(allocs, oldPtr)
5765
} else {
5866
panic("realloc: invalid pointer")
5967
}
6068
}
6169

62-
ptr := unsafe.Pointer(&buf[0])
63-
allocs[uintptr(ptr)] = buf
70+
allocs[ptr] = size
6471
return ptr
6572
}

0 commit comments

Comments
 (0)