diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 7dc04f07..235d2526 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 cabd4142..955b6d99 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 7fbeec11..094da50d 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 345539d6..47b7d4fa 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 403675f8..f769a07f 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. }