github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/arch_tinygowasm_malloc.go (about) 1 //go:build tinygo.wasm && !(custommalloc || wasm_unknown) 2 3 package runtime 4 5 import "unsafe" 6 7 // The below functions override the default allocator of wasi-libc. This ensures 8 // code linked from other languages can allocate memory without colliding with 9 // our GC allocations. 10 11 var allocs = make(map[uintptr][]byte) 12 13 //export malloc 14 func libc_malloc(size uintptr) unsafe.Pointer { 15 if size == 0 { 16 return nil 17 } 18 buf := make([]byte, size) 19 ptr := unsafe.Pointer(&buf[0]) 20 allocs[uintptr(ptr)] = buf 21 return ptr 22 } 23 24 //export free 25 func libc_free(ptr unsafe.Pointer) { 26 if ptr == nil { 27 return 28 } 29 if _, ok := allocs[uintptr(ptr)]; ok { 30 delete(allocs, uintptr(ptr)) 31 } else { 32 panic("free: invalid pointer") 33 } 34 } 35 36 //export calloc 37 func libc_calloc(nmemb, size uintptr) unsafe.Pointer { 38 // No difference between calloc and malloc. 39 return libc_malloc(nmemb * size) 40 } 41 42 //export realloc 43 func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer { 44 if size == 0 { 45 libc_free(oldPtr) 46 return nil 47 } 48 49 // It's hard to optimize this to expand the current buffer with our GC, but 50 // it is theoretically possible. For now, just always allocate fresh. 51 buf := make([]byte, size) 52 53 if oldPtr != nil { 54 if oldBuf, ok := allocs[uintptr(oldPtr)]; ok { 55 copy(buf, oldBuf) 56 delete(allocs, uintptr(oldPtr)) 57 } else { 58 panic("realloc: invalid pointer") 59 } 60 } 61 62 ptr := unsafe.Pointer(&buf[0]) 63 allocs[uintptr(ptr)] = buf 64 return ptr 65 }