mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 02:57:46 +00:00
26ee3fb93e
- Do not use make([]byte, ...) to allocate, instead call the allocator
directly with a nil (undefined) layout. 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.
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
//go:build tinygo.wasm && !(custommalloc || wasm_unknown || gc.boehm)
|
|
|
|
package runtime
|
|
|
|
import "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, nil)
|
|
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 {
|
|
panic("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, nil)
|
|
|
|
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 {
|
|
panic("realloc: invalid pointer")
|
|
}
|
|
}
|
|
|
|
allocs[(*byte)(ptr)] = size
|
|
return ptr
|
|
}
|