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 goccy/go-json for go1.18-beta1. #1673

Merged
merged 1 commit into from Dec 29, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 25 additions & 51 deletions internal/go-json/cmd/generator/vm.go.tmpl
Expand Up @@ -403,95 +403,69 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break
}
b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr)
ctx.KeepRefs = append(ctx.KeepRefs, iter)
store(ctxptr, code.ElemIdx, 0)
store(ctxptr, code.Length, uintptr(mlen))
store(ctxptr, code.MapIter, uintptr(iter))
mapCtx := encoder.NewMapContext(mlen)
mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b)
} else {
mapCtx := encoder.NewMapContext(mlen)
mapCtx.Pos = append(mapCtx.Pos, len(b))
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
mapCtx.Start = len(b)
mapCtx.First = len(b)
}
key := mapiterkey(iter)
key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next
case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx)
length := load(ctxptr, code.Length)
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
idx := mapCtx.Idx
idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length {
if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx)
ptr := load(ctxptr, code.MapIter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
mapCtx.Idx = int(idx)
key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next
} else {
b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next
}
} else {
ptr := load(ctxptr, code.End.MapPos)
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
mapCtx.Pos = append(mapCtx.Pos, len(b))
if idx < length {
ptr := load(ctxptr, code.MapIter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
if idx < mapCtx.Len {
mapCtx.Idx = int(idx)
mapCtx.Start = len(b)
key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next
} else {
code = code.End
}
}
case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b)
} else {
ptr := load(ctxptr, code.End.MapPos)
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
mapCtx.Pos = append(mapCtx.Pos, len(b))
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx.Start = len(b)
}
ptr := load(ctxptr, code.MapIter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
value := mapitervalue(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter)
mapiternext(&mapCtx.Iter)
code = code.Next
case encoder.OpMapEnd:
// this operation only used by sorted map.
length := int(load(ctxptr, code.Length))
ptr := load(ctxptr, code.MapPos)
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
pos := mapCtx.Pos
for i := 0; i < length; i++ {
startKey := pos[i*2]
startValue := pos[i*2+1]
var endValue int
if i+1 < length {
endValue = pos[i*2+2]
} else {
endValue = len(b)
}
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
Key: b[startKey:startValue],
Value: b[startValue:endValue],
})
}
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
}
buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]]
b = b[:mapCtx.First]
b = append(b, buf...)
mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx)
Expand Down
127 changes: 127 additions & 0 deletions internal/go-json/encoder/decode_rune.go
@@ -0,0 +1,127 @@
package encoder

import "unicode/utf8"

const (
// The default lowest and highest continuation byte.
locb = 128 //0b10000000
hicb = 191 //0b10111111

// These names of these constants are chosen to give nice alignment in the
// table below. The first nibble is an index into acceptRanges or F for
// special one-byte cases. The second nibble is the Rune length or the
// Status for the special one-byte case.
xx = 0xF1 // invalid: size 1
as = 0xF0 // ASCII: size 1
s1 = 0x02 // accept 0, size 2
s2 = 0x13 // accept 1, size 3
s3 = 0x03 // accept 0, size 3
s4 = 0x23 // accept 2, size 3
s5 = 0x34 // accept 3, size 4
s6 = 0x04 // accept 0, size 4
s7 = 0x44 // accept 4, size 4
)

// first is information about the first byte in a UTF-8 sequence.
var first = [256]uint8{
// 1 2 3 4 5 6 7 8 9 A B C D E F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
// 1 2 3 4 5 6 7 8 9 A B C D E F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
}

// acceptRange gives the range of valid values for the second byte in a UTF-8
// sequence.
type acceptRange struct {
lo uint8 // lowest value for second byte.
hi uint8 // highest value for second byte.
}

const (
lineSep = byte(168) //'\u2028'
paragraphSep = byte(169) //'\u2029'
)

type decodeRuneState int

const (
validUTF8State decodeRuneState = iota
runeErrorState
lineSepState
paragraphSepState
)

func decodeRuneInString(s string) (decodeRuneState, int) {
n := len(s)
s0 := s[0]
x := first[s0]
if x >= as {
// The following code simulates an additional check for x == xx and
// handling the ASCII and invalid cases accordingly. This mask-and-or
// approach prevents an additional branch.
mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
if rune(s[0])&^mask|utf8.RuneError&mask == utf8.RuneError {
return runeErrorState, 1
}
return validUTF8State, 1
}
sz := int(x & 7)
var accept acceptRange
switch x >> 4 {
case 0:
accept = acceptRange{locb, hicb}
case 1:
accept = acceptRange{0xA0, hicb}
case 2:
accept = acceptRange{locb, 0x9F}
case 3:
accept = acceptRange{0x90, hicb}
case 4:
accept = acceptRange{locb, 0x8F}
}
if n < sz {
return runeErrorState, 1
}
s1 := s[1]
if s1 < accept.lo || accept.hi < s1 {
return runeErrorState, 1
}
if sz <= 2 {
return validUTF8State, 2
}
s2 := s[2]
if s2 < locb || hicb < s2 {
return runeErrorState, 1
}
if sz <= 3 {
// separator character prefixes: [2]byte{226, 128}
if s0 == 226 && s1 == 128 {
switch s2 {
case lineSep:
return lineSepState, 3
case paragraphSep:
return paragraphSepState, 3
}
}
return validUTF8State, 3
}
s3 := s[3]
if s3 < locb || hicb < s3 {
return runeErrorState, 1
}
return validUTF8State, 4
}
53 changes: 37 additions & 16 deletions internal/go-json/encoder/encoder.go
Expand Up @@ -222,51 +222,72 @@ func (m *Mapslice) Swap(i, j int) {
m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
}

//nolint:structcheck,unused
type mapIter struct {
key unsafe.Pointer
elem unsafe.Pointer
t unsafe.Pointer
h unsafe.Pointer
buckets unsafe.Pointer
bptr unsafe.Pointer
overflow unsafe.Pointer
oldoverflow unsafe.Pointer
startBucket uintptr
offset uint8
wrapped bool
B uint8
i uint8
bucket uintptr
checkBucket uintptr
}

type MapContext struct {
Pos []int
Start int
First int
Idx int
Slice *Mapslice
Buf []byte
Len int
Iter mapIter
}

var mapContextPool = sync.Pool{
New: func() interface{} {
return &MapContext{}
return &MapContext{
Slice: &Mapslice{},
}
},
}

func NewMapContext(mapLen int) *MapContext {
ctx := mapContextPool.Get().(*MapContext)
if ctx.Slice == nil {
ctx.Slice = &Mapslice{
Items: make([]MapItem, 0, mapLen),
}
}
if cap(ctx.Pos) < (mapLen*2 + 1) {
ctx.Pos = make([]int, 0, mapLen*2+1)
ctx.Slice.Items = make([]MapItem, 0, mapLen)
if len(ctx.Slice.Items) < mapLen {
ctx.Slice.Items = make([]MapItem, mapLen)
} else {
ctx.Pos = ctx.Pos[:0]
ctx.Slice.Items = ctx.Slice.Items[:0]
ctx.Slice.Items = ctx.Slice.Items[:mapLen]
}
ctx.Buf = ctx.Buf[:0]
ctx.Iter = mapIter{}
ctx.Idx = 0
ctx.Len = mapLen
return ctx
}

func ReleaseMapContext(c *MapContext) {
mapContextPool.Put(c)
}

//go:linkname MapIterInit reflect.mapiterinit
//go:linkname MapIterInit runtime.mapiterinit
//go:noescape
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)

//go:linkname MapIterKey reflect.mapiterkey
//go:noescape
func MapIterKey(it unsafe.Pointer) unsafe.Pointer
func MapIterKey(it *mapIter) unsafe.Pointer

//go:linkname MapIterNext reflect.mapiternext
//go:noescape
func MapIterNext(it unsafe.Pointer)
func MapIterNext(it *mapIter)

//go:linkname MapLen reflect.maplen
//go:noescape
Expand Down
3 changes: 2 additions & 1 deletion internal/go-json/encoder/map112.go
@@ -1,8 +1,9 @@
//go:build !go1.13
// +build !go1.13

package encoder

import "unsafe"

//go:linkname MapIterValue reflect.mapitervalue
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
func MapIterValue(it *mapIter) unsafe.Pointer
3 changes: 2 additions & 1 deletion internal/go-json/encoder/map113.go
@@ -1,8 +1,9 @@
//go:build go1.13
// +build go1.13

package encoder

import "unsafe"

//go:linkname MapIterValue reflect.mapiterelem
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
func MapIterValue(it *mapIter) unsafe.Pointer