From 75b72584a5e57085076402863d141e5099daa9ae Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 1 May 2021 14:53:48 +0900 Subject: [PATCH] Use typedmemmove for copying element of slice --- decode_slice.go | 22 ++++++++++------------ decode_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/decode_slice.go b/decode_slice.go index f8ab536..da8350c 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -67,6 +67,12 @@ func copySlice(elemType *rtype, dst, src sliceHeader) int //go:linkname newArray reflect.unsafe_NewArray 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 { return &UnmarshalTypeError{ 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) if d.isElemUnmarshalJSONType { - receiver := unsafe_New(d.elemType) - if d.elemType.Kind() == reflect.Slice { - **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = receiver - } else { - **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = **(**unsafe.Pointer)(unsafe.Pointer(&receiver)) - } + // assign new element to the slice + typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) } else if d.isElemPointerType { **(**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) if d.isElemUnmarshalJSONType { - receiver := unsafe_New(d.elemType) - if d.elemType.Kind() == reflect.Slice { - **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = receiver - } else { - **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = **(**unsafe.Pointer)(unsafe.Pointer(&receiver)) - } + // assign new element to the slice + typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) } else if d.isElemPointerType { **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer } diff --git a/decode_test.go b/decode_test.go index 3073553..4fbf1ec 100644 --- a/decode_test.go +++ b/decode_test.go @@ -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 func (u *intUnmarshaler) UnmarshalJSON(b []byte) error {