diff --git a/src/runtime/arch_tinygowasm_malloc.go b/src/runtime/arch_tinygowasm_malloc.go index 239f7c73eb..824031ef63 100644 --- a/src/runtime/arch_tinygowasm_malloc.go +++ b/src/runtime/arch_tinygowasm_malloc.go @@ -8,16 +8,19 @@ import "unsafe" // code linked from other languages can allocate memory without colliding with // our GC allocations. -var allocs = make(map[uintptr][]byte) +// Map of allocations, where the key is the allocated pointer and the value is +// the size of the allocation. +var allocs = make(map[unsafe.Pointer]uintptr) //export malloc func libc_malloc(size uintptr) unsafe.Pointer { if size == 0 { return nil } - buf := make([]byte, size) + const wordSize = unsafe.Sizeof(unsafe.Pointer(nil)) + buf := make([]unsafe.Pointer, (size+wordSize-1)/wordSize) ptr := unsafe.Pointer(&buf[0]) - allocs[uintptr(ptr)] = buf + allocs[ptr] = size return ptr } @@ -26,8 +29,8 @@ func libc_free(ptr unsafe.Pointer) { if ptr == nil { return } - if _, ok := allocs[uintptr(ptr)]; ok { - delete(allocs, uintptr(ptr)) + if _, ok := allocs[ptr]; ok { + delete(allocs, ptr) } else { panic("free: invalid pointer") } @@ -48,18 +51,22 @@ func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer { // 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. - buf := make([]byte, size) + // TODO: we could skip this if the new allocation is smaller than the old. + const wordSize = unsafe.Sizeof(unsafe.Pointer(nil)) + buf := make([]unsafe.Pointer, (size+wordSize-1)/wordSize) + ptr := unsafe.Pointer(&buf[0]) if oldPtr != nil { - if oldBuf, ok := allocs[uintptr(oldPtr)]; ok { - copy(buf, oldBuf) - delete(allocs, uintptr(oldPtr)) + if oldSize, ok := allocs[oldPtr]; ok { + oldBuf := unsafe.Slice((*byte)(oldPtr), oldSize) + newBuf := unsafe.Slice((*byte)(ptr), size) + copy(newBuf, oldBuf) + delete(allocs, oldPtr) } else { panic("realloc: invalid pointer") } } - ptr := unsafe.Pointer(&buf[0]) - allocs[uintptr(ptr)] = buf + allocs[ptr] = size return ptr } diff --git a/src/runtime/runtime_wasip2.go b/src/runtime/runtime_wasip2.go index 46ce3d853b..82e5d8f5b7 100644 --- a/src/runtime/runtime_wasip2.go +++ b/src/runtime/runtime_wasip2.go @@ -30,8 +30,21 @@ func os_runtime_args() []string { } //export cabi_realloc -func cabi_realloc(ptr, oldsize, align, newsize unsafe.Pointer) unsafe.Pointer { - return realloc(ptr, uintptr(newsize)) +func cabi_realloc(ptr unsafe.Pointer, oldSize, align, newSize uintptr) unsafe.Pointer { + if newSize == 0 { + return nil + } + newPtr := realloc(ptr, newSize) + if ptr != nil { + for i := range wasmAllocs { + if wasmAllocs[i] == ptr { + wasmAllocs[i] = newPtr + return newPtr + } + } + } + wasmAllocs = append(wasmAllocs, newPtr) + return newPtr } func ticksToNanoseconds(ticks timeUnit) int64 { diff --git a/src/runtime/runtime_wasmentry.go b/src/runtime/runtime_wasmentry.go index 59cacb3b04..160d643dbd 100644 --- a/src/runtime/runtime_wasmentry.go +++ b/src/runtime/runtime_wasmentry.go @@ -96,8 +96,15 @@ func wasmExportExit() { // //go:wasmexport function has exited. schedulerExit = true + // Clear wasm allocations. + wasmAllocs = nil + task.Pause() // TODO: we could cache the allocated stack so we don't have to keep // allocating a new stack on every //go:wasmexport call. } + +// wasmAllocs holds memory allocated by the host in guest memory. +// See func cabi_realloc for more information. +var wasmAllocs []unsafe.Pointer