From 0f69d016a032ede785ef21d1aebaf3afad8edd31 Mon Sep 17 00:00:00 2001 From: Rouven Broszeit Date: Fri, 22 Oct 2021 21:30:52 +0200 Subject: [PATCH] Added realloc implementation to GCs When using the latest wasi-libc I experienced a panic on an attempt to call realloc. My first attempt to add it to arch_tinygowasm.go was obviously not good (PR #2194). So here is another suggestion. --- src/runtime/arch_tinygowasm.go | 3 +-- src/runtime/gc_conservative.go | 22 ++++++++++++++++++++++ src/runtime/gc_extalloc.go | 4 ++++ src/runtime/gc_leaking.go | 12 ++++++++++++ src/runtime/gc_none.go | 2 ++ 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 7dc04f07b..235d2526b 100644 --- a/src/runtime/arch_tinygowasm.go +++ b/src/runtime/arch_tinygowasm.go @@ -84,8 +84,7 @@ func libc_calloc(nmemb, size uintptr) unsafe.Pointer { //export realloc func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { - runtimePanic("unimplemented: realloc") - return nil + return realloc(ptr, size) } //export posix_memalign diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go index cabd41427..955b6d99a 100644 --- a/src/runtime/gc_conservative.go +++ b/src/runtime/gc_conservative.go @@ -341,6 +341,28 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { } } +func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { + if ptr == nil { + return alloc(size, nil) + } + + ptrAddress := uintptr(ptr) + endOfTailAddress := blockFromAddr(ptrAddress).findNext().address() + + // this might be a few bytes longer than the original size of + // ptr, because we align to full blocks of size bytesPerBlock + oldSize := endOfTailAddress - ptrAddress + if size <= oldSize { + return ptr + } + + newAlloc := alloc(size, nil) + memcpy(newAlloc, ptr, oldSize) + free(ptr) + + return newAlloc +} + func free(ptr unsafe.Pointer) { // TODO: free blocks on request, when the compiler knows they're unused. } diff --git a/src/runtime/gc_extalloc.go b/src/runtime/gc_extalloc.go index 7fbeec110..094da50da 100644 --- a/src/runtime/gc_extalloc.go +++ b/src/runtime/gc_extalloc.go @@ -630,6 +630,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { } } +func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { + runtimePanic("unimplemented: gc_extalloc.realloc") +} + func free(ptr unsafe.Pointer) { // Currently unimplemented due to bugs in coroutine lowering. } diff --git a/src/runtime/gc_leaking.go b/src/runtime/gc_leaking.go index 345539d68..47b7d4faa 100644 --- a/src/runtime/gc_leaking.go +++ b/src/runtime/gc_leaking.go @@ -35,6 +35,18 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(addr) } +func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { + newAlloc := alloc(size, nil) + if ptr == nil { + return newAlloc + } + // according to POSIX everything beyond the previous pointer's + // size will have indeterminate values so we can just copy garbage + memcpy(newAlloc, ptr, size) + + return newAlloc +} + func free(ptr unsafe.Pointer) { // Memory is never freed. } diff --git a/src/runtime/gc_none.go b/src/runtime/gc_none.go index 403675f82..f769a07fa 100644 --- a/src/runtime/gc_none.go +++ b/src/runtime/gc_none.go @@ -12,6 +12,8 @@ import ( func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer +func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer + func free(ptr unsafe.Pointer) { // Nothing to free when nothing gets allocated. }