Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(arm): grow slice not clear mem #674

Merged
merged 1 commit into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions internal/rt/growslice.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
45 changes: 0 additions & 45 deletions internal/rt/rt_stubs_go116.go

This file was deleted.

36 changes: 0 additions & 36 deletions internal/rt/rt_stubs_go120.go

This file was deleted.

36 changes: 36 additions & 0 deletions internal/rt/stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为啥noscan需要清理?scan类型不需要清理??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,因为runtime.growslice 对于 [oldlen, newlen) 这段区间的的非指针数据是不需要清空的

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那noscan数据就脏着呗,不清理有啥问题吗

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为 makeslice 里面长度会变成 newLen, 而且如果遇到非匹配类型,会跳过这些类型。因此需要清空

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为makeslice 的语义其实是需要初始化所有元素的,因为如果decode 遇到不需要解析的类型会直接skip,不初始化可能会有脏数据

oldlenmem := uintptr(old.Len) * et.Size
newlenmem := uintptr(newLen) * et.Size
MemclrNoHeapPointers(add(new.Ptr, oldlenmem), newlenmem-oldlenmem)
}

new.Len = newLen
return &new
}
30 changes: 30 additions & 0 deletions internal/rt/stubs_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
})
}
Loading