Use typedmemmove for copying element of slice

This commit is contained in:
Masaaki Goshima 2021-05-01 14:53:48 +09:00
parent 6444a1b057
commit 75b72584a5
2 changed files with 57 additions and 12 deletions

View File

@ -67,6 +67,12 @@ func copySlice(elemType *rtype, dst, src sliceHeader) int
//go:linkname newArray reflect.unsafe_NewArray //go:linkname newArray reflect.unsafe_NewArray
func newArray(*rtype, int) unsafe.Pointer func newArray(*rtype, int) unsafe.Pointer
//go:linkname typedmemmovepartial reflect.typedmemmovepartial
func typedmemmovepartial(typ *rtype, dst, src unsafe.Pointer, off, size uintptr)
//go:linkname typedmemmove reflect.typedmemmove
func typedmemmove(t *rtype, dst, src unsafe.Pointer)
func (d *sliceDecoder) errNumber(offset int64) *UnmarshalTypeError { func (d *sliceDecoder) errNumber(offset int64) *UnmarshalTypeError {
return &UnmarshalTypeError{ return &UnmarshalTypeError{
Value: "number", Value: "number",
@ -120,12 +126,8 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
} }
ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size)
if d.isElemUnmarshalJSONType { if d.isElemUnmarshalJSONType {
receiver := unsafe_New(d.elemType) // assign new element to the slice
if d.elemType.Kind() == reflect.Slice { typedmemmove(d.elemType, ep, unsafe_New(d.elemType))
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = receiver
} else {
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = **(**unsafe.Pointer)(unsafe.Pointer(&receiver))
}
} else if d.isElemPointerType { } else if d.isElemPointerType {
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer
} }
@ -241,12 +243,8 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
} }
ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size)
if d.isElemUnmarshalJSONType { if d.isElemUnmarshalJSONType {
receiver := unsafe_New(d.elemType) // assign new element to the slice
if d.elemType.Kind() == reflect.Slice { typedmemmove(d.elemType, ep, unsafe_New(d.elemType))
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = receiver
} else {
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = **(**unsafe.Pointer)(unsafe.Pointer(&receiver))
}
} else if d.isElemPointerType { } else if d.isElemPointerType {
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer
} }

View File

@ -2996,6 +2996,53 @@ func TestDecodeMultipleUnmarshal(t *testing.T) {
}) })
} }
func TestMultipleDecodeWithRawMessage(t *testing.T) {
original := []byte(`{
"Body": {
"List": [
{
"Returns": [
{
"Value": "10",
"nodeType": "Literal"
}
],
"nodeKind": "Return",
"nodeType": "Statement"
}
],
"nodeKind": "Block",
"nodeType": "Statement"
},
"nodeType": "Function"
}`)
var a map[string]json.RawMessage
if err := json.Unmarshal(original, &a); err != nil {
t.Fatal(err)
}
var b map[string]json.RawMessage
if err := json.Unmarshal(a["Body"], &b); err != nil {
t.Fatal(err)
}
var c []json.RawMessage
if err := json.Unmarshal(b["List"], &c); err != nil {
t.Fatal(err)
}
var d map[string]json.RawMessage
if err := json.Unmarshal(c[0], &d); err != nil {
t.Fatal(err)
}
var e []json.RawMessage
if err := json.Unmarshal(d["Returns"], &e); err != nil {
t.Fatal(err)
}
var f map[string]json.RawMessage
if err := json.Unmarshal(e[0], &f); err != nil {
t.Fatal(err)
}
}
type intUnmarshaler int type intUnmarshaler int
func (u *intUnmarshaler) UnmarshalJSON(b []byte) error { func (u *intUnmarshaler) UnmarshalJSON(b []byte) error {