Files
tinygo/src/runtime/arch_tinygowasm_malloc.go
T
2026-09-10 08:49:07 +02:00

76 lines
2.0 KiB
Go

//go:build tinygo.wasm && !(custommalloc || wasm_unknown || gc.boehm)
package runtime
import (
"internal/gclayout"
"unsafe"
)
// The below functions override the default allocator of wasi-libc. This ensures
// code linked from other languages can allocate memory without colliding with
// our GC allocations.
// Map of allocations, where the key is the allocated pointer and the value is
// the size of the allocation.
// TODO: make this a map[unsafe.Pointer]uintptr, since that results in slightly
// smaller binaries. But for that to work, unsafe.Pointer needs to be seen as a
// binary key (which it is not at the moment).
// See https://github.com/tinygo-org/tinygo/pull/4898 for details.
var allocs = make(map[*byte]uintptr)
//export malloc
func libc_malloc(size uintptr) unsafe.Pointer {
if size == 0 {
return nil
}
ptr := alloc(size, gclayout.NoPtrs.AsPtr())
allocs[(*byte)(ptr)] = size
return ptr
}
//export free
func libc_free(ptr unsafe.Pointer) {
if ptr == nil {
return
}
if _, ok := allocs[(*byte)(ptr)]; ok {
delete(allocs, (*byte)(ptr))
} else {
runtimeFatal("free: invalid pointer")
}
}
//export calloc
func libc_calloc(nmemb, size uintptr) unsafe.Pointer {
// No difference between calloc and malloc.
return libc_malloc(nmemb * size)
}
//export realloc
func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer {
if size == 0 {
libc_free(oldPtr)
return nil
}
// It's hard to optimize this to expand the current buffer with our GC, but
// it is theoretically possible. For now, just always allocate fresh.
// TODO: we could skip this if the new allocation is smaller than the old.
ptr := alloc(size, gclayout.NoPtrs.AsPtr())
if oldPtr != nil {
if oldSize, ok := allocs[(*byte)(oldPtr)]; ok {
oldBuf := unsafe.Slice((*byte)(oldPtr), oldSize)
newBuf := unsafe.Slice((*byte)(ptr), size)
copy(newBuf, oldBuf)
delete(allocs, (*byte)(oldPtr))
} else {
runtimeFatal("realloc: invalid pointer")
}
}
allocs[(*byte)(ptr)] = size
return ptr
}