From 65b7fbeca64e3988ad67bf336ca2882814a95a66 Mon Sep 17 00:00:00 2001 From: liu Date: Wed, 17 Jul 2024 12:50:14 +0800 Subject: [PATCH] fix(arm): grow slice not clear mem (#674) --- internal/rt/growslice.go | 9 +++++-- internal/rt/rt_stubs_go116.go | 45 ----------------------------------- internal/rt/rt_stubs_go120.go | 36 ---------------------------- internal/rt/stubs.go | 36 ++++++++++++++++++++++++++++ internal/rt/stubs_test.go | 30 +++++++++++++++++++++++ 5 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 internal/rt/rt_stubs_go116.go delete mode 100644 internal/rt/rt_stubs_go120.go create mode 100644 internal/rt/stubs_test.go diff --git a/internal/rt/growslice.go b/internal/rt/growslice.go index ef1856948..fe182a5c9 100644 --- a/internal/rt/growslice.go +++ b/internal/rt/growslice.go @@ -20,8 +20,13 @@ package rt import "unsafe" -func GrowSlice(et *GoType, old GoSlice, cap int) GoSlice { - s := growslice(old.Ptr, cap, old.Cap, cap - old.Len, et) +// Growslice to newCap, not append length +// Note: the [old, newCap) will not be zeroed if et does not have any ptr data. +func GrowSlice(et *GoType, old GoSlice, newCap int) GoSlice { + if newCap < old.Len { + panic("growslice's newCap is smaller than old length") + } + s := growslice(old.Ptr, newCap, old.Cap, newCap - old.Len, et) s.Len = old.Len return s } diff --git a/internal/rt/rt_stubs_go116.go b/internal/rt/rt_stubs_go116.go deleted file mode 100644 index 2c60e164c..000000000 --- a/internal/rt/rt_stubs_go116.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build go1.17 && !go1.20 -// +build go1.17,!go1.20 - -package rt - -import ( - "unsafe" -) - - -//go:linkname makeslice runtime.makeslice -//goland:noinspection GoUnusedParameter -func makeslice(et *GoType, len int, cap int) unsafe.Pointer - -func MakeSlice(oldPtr unsafe.Pointer, et *GoType, newLen int) *GoSlice { - if newLen == 0 { - return &EmptySlice - } - - if *(*unsafe.Pointer)(oldPtr) == nil { - return &GoSlice{ - Ptr: makeslice(et, newLen, newLen), - Len: newLen, - Cap: newLen, - } - } - - old := (*GoSlice)(oldPtr) - if old.Cap >= newLen { - old.Len = newLen - return old - } - - new := GrowSlice(et, *old, newLen) - - // we sould clear the memory from [oldLen:newLen] - if et.PtrData == 0 { - oldlenmem := uintptr(old.Len) * et.Size - newlenmem := uintptr(newLen) * et.Size - MemclrNoHeapPointers(add(new.Ptr, oldlenmem), newlenmem-oldlenmem) - } - - new.Len = newLen - return &new -} diff --git a/internal/rt/rt_stubs_go120.go b/internal/rt/rt_stubs_go120.go deleted file mode 100644 index 735be152d..000000000 --- a/internal/rt/rt_stubs_go120.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build go1.20 && !go1.23 -// +build go1.20,!go1.23 - -package rt - -import ( - "unsafe" -) - -//go:linkname makeslice runtime.makeslice -//goland:noinspection GoUnusedParameter -func makeslice(et *GoType, len int, cap int) unsafe.Pointer - -func MakeSlice(oldPtr unsafe.Pointer, et *GoType, newLen int) *GoSlice { - if newLen == 0 { - return &EmptySlice - } - - if *(*unsafe.Pointer)(oldPtr) == nil { - return &GoSlice{ - Ptr: makeslice(et, newLen, newLen), - Len: newLen, - Cap: newLen, - } - } - - old := (*GoSlice)(oldPtr) - if old.Cap >= newLen { - old.Len = newLen - return old - } - - new := GrowSlice(et, *old, newLen-old.Len) - new.Len = newLen - return &new -} diff --git a/internal/rt/stubs.go b/internal/rt/stubs.go index 36e9a808e..5104a0793 100644 --- a/internal/rt/stubs.go +++ b/internal/rt/stubs.go @@ -127,3 +127,39 @@ func GetMap64Assign(vt reflect.Type) Map64Assign { var emptyBytes = make([]byte, 0, 0) var EmptySlice = *(*GoSlice)(unsafe.Pointer(&emptyBytes)) + +//go:linkname makeslice runtime.makeslice +//goland:noinspection GoUnusedParameter +func makeslice(et *GoType, len int, cap int) unsafe.Pointer + +func MakeSlice(oldPtr unsafe.Pointer, et *GoType, newLen int) *GoSlice { + if newLen == 0 { + return &EmptySlice + } + + if *(*unsafe.Pointer)(oldPtr) == nil { + return &GoSlice{ + Ptr: makeslice(et, newLen, newLen), + Len: newLen, + Cap: newLen, + } + } + + old := (*GoSlice)(oldPtr) + if old.Cap >= newLen { + old.Len = newLen + return old + } + + new := GrowSlice(et, *old, newLen) + + // we sould clear the memory from [oldLen:newLen] + if et.PtrData == 0 { + oldlenmem := uintptr(old.Len) * et.Size + newlenmem := uintptr(newLen) * et.Size + MemclrNoHeapPointers(add(new.Ptr, oldlenmem), newlenmem-oldlenmem) + } + + new.Len = newLen + return &new +} diff --git a/internal/rt/stubs_test.go b/internal/rt/stubs_test.go new file mode 100644 index 000000000..e2defda3e --- /dev/null +++ b/internal/rt/stubs_test.go @@ -0,0 +1,30 @@ +package rt + +import ( + "reflect" + "testing" + "unsafe" + + "github.com/stretchr/testify/assert" +) + + +func TestStubsMake(t *testing.T) { + t.Run("NonPtr", func(t *testing.T) { + old := &[]int{} + news := MakeSlice(unsafe.Pointer(old), UnpackType(reflect.TypeOf(int(1))), 10000) + new := *(*[]int)(unsafe.Pointer(news)) + for i := 0; i < 10000; i++ { + assert.Equal(t, new[i], 0) + } + }) + + t.Run("HasPtr", func(t *testing.T) { + old := &[]*int{} + news := MakeSlice(unsafe.Pointer(old), UnpackType(reflect.TypeOf((*int)(nil))), 10000) + new := *(*[]*int)(unsafe.Pointer(news)) + for i := 0; i < 10000; i++ { + assert.Equal(t, new[i], (*int)(nil)) + } + }) +} \ No newline at end of file