Improve map encoding performance

This commit is contained in:
Masaaki Goshima 2021-12-27 11:14:42 +09:00
parent de89bd3db6
commit d8aa8348f4
No known key found for this signature in database
GPG Key ID: 6A53785055537153
9 changed files with 168 additions and 269 deletions

View File

@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break break
} }
b = appendStructHead(ctx, b) b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr) mapCtx := encoder.NewMapContext(mlen)
ctx.KeepRefs = append(ctx.KeepRefs, iter) mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.MapIter, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.Length, uintptr(mlen)) ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.MapIter, uintptr(iter))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b) b = appendMapKeyIndent(ctx, code.Next, b)
} else { } else {
mapCtx := encoder.NewMapContext(mlen) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.First = len(b)
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
} }
key := mapiterkey(iter) key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
case encoder.OpMapKey: case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
length := load(ctxptr, code.Length) idx := mapCtx.Idx
idx++ idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length { if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b) b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx) mapCtx.Idx = int(idx)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
b = appendObjectEnd(ctx, code, b) b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next code = code.End.Next
} }
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) if idx < mapCtx.Len {
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.Idx = int(idx)
if idx < length { mapCtx.Start = len(b)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
} }
} }
case encoder.OpMapValue: case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b) b = appendColon(ctx, b)
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b))
} }
ptr := load(ctxptr, code.MapIter) value := mapitervalue(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
store(ctxptr, code.Next.Idx, uintptr(value)) store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter) mapiternext(&mapCtx.Iter)
code = code.Next code = code.Next
case encoder.OpMapEnd: case encoder.OpMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.Length)) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
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],
})
}
sort.Sort(mapCtx.Slice) sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items { for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
} }
buf = appendMapEnd(ctx, code, buf) buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]] b = b[:mapCtx.First]
b = append(b, buf...) b = append(b, buf...)
mapCtx.Buf = buf mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx) encoder.ReleaseMapContext(mapCtx)

View File

@ -207,7 +207,7 @@ type MapItem struct {
} }
type Mapslice struct { type Mapslice struct {
Items []MapItem Items []*MapItem
} }
func (m *Mapslice) Len() int { func (m *Mapslice) Len() int {
@ -222,10 +222,32 @@ func (m *Mapslice) Swap(i, j int) {
m.Items[i], m.Items[j] = m.Items[j], m.Items[i] m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
} }
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 { type MapContext struct {
Pos []int Start int
First int
Idx int
Slice *Mapslice Slice *Mapslice
Buf []byte Buf []byte
Len int
Iter mapIter
} }
var mapContextPool = sync.Pool{ var mapContextPool = sync.Pool{
@ -238,17 +260,21 @@ func NewMapContext(mapLen int) *MapContext {
ctx := mapContextPool.Get().(*MapContext) ctx := mapContextPool.Get().(*MapContext)
if ctx.Slice == nil { if ctx.Slice == nil {
ctx.Slice = &Mapslice{ ctx.Slice = &Mapslice{
Items: make([]MapItem, 0, mapLen), Items: make([]*MapItem, 0, mapLen),
} }
} }
if cap(ctx.Pos) < (mapLen*2 + 1) { if len(ctx.Slice.Items) < mapLen {
ctx.Pos = make([]int, 0, mapLen*2+1) ctx.Slice.Items = make([]*MapItem, mapLen)
ctx.Slice.Items = make([]MapItem, 0, mapLen) for i := 0; i < mapLen; i++ {
ctx.Slice.Items[i] = &MapItem{}
}
} else { } else {
ctx.Pos = ctx.Pos[:0] ctx.Slice.Items = ctx.Slice.Items[:mapLen]
ctx.Slice.Items = ctx.Slice.Items[:0]
} }
ctx.Buf = ctx.Buf[:0] ctx.Buf = ctx.Buf[:0]
ctx.Iter = mapIter{}
ctx.Idx = 0
ctx.Len = mapLen
return ctx return ctx
} }
@ -256,17 +282,17 @@ func ReleaseMapContext(c *MapContext) {
mapContextPool.Put(c) mapContextPool.Put(c)
} }
//go:linkname MapIterInit reflect.mapiterinit //go:linkname MapIterInit runtime.mapiterinit
//go:noescape //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:linkname MapIterKey reflect.mapiterkey
//go:noescape //go:noescape
func MapIterKey(it unsafe.Pointer) unsafe.Pointer func MapIterKey(it *mapIter) unsafe.Pointer
//go:linkname MapIterNext reflect.mapiternext //go:linkname MapIterNext reflect.mapiternext
//go:noescape //go:noescape
func MapIterNext(it unsafe.Pointer) func MapIterNext(it *mapIter)
//go:linkname MapLen reflect.maplen //go:linkname MapLen reflect.maplen
//go:noescape //go:noescape

View File

@ -1,3 +1,4 @@
//go:build !go1.13
// +build !go1.13 // +build !go1.13
package encoder package encoder
@ -5,4 +6,4 @@ package encoder
import "unsafe" import "unsafe"
//go:linkname MapIterValue reflect.mapitervalue //go:linkname MapIterValue reflect.mapitervalue
func MapIterValue(it unsafe.Pointer) unsafe.Pointer func MapIterValue(it *mapIter) unsafe.Pointer

View File

@ -1,3 +1,4 @@
//go:build go1.13
// +build go1.13 // +build go1.13
package encoder package encoder
@ -5,4 +6,4 @@ package encoder
import "unsafe" import "unsafe"
//go:linkname MapIterValue reflect.mapiterelem //go:linkname MapIterValue reflect.mapiterelem
func MapIterValue(it unsafe.Pointer) unsafe.Pointer func MapIterValue(it *mapIter) unsafe.Pointer

View File

@ -685,6 +685,7 @@ func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode
Length: head.Length, Length: head.Length,
MapPos: mapPos, MapPos: mapPos,
Indent: ctx.indent, Indent: ctx.indent,
MapIter: head.MapIter,
} }
} }

View File

@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break break
} }
b = appendStructHead(ctx, b) b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr) mapCtx := encoder.NewMapContext(mlen)
ctx.KeepRefs = append(ctx.KeepRefs, iter) mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.MapIter, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.Length, uintptr(mlen)) ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.MapIter, uintptr(iter))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b) b = appendMapKeyIndent(ctx, code.Next, b)
} else { } else {
mapCtx := encoder.NewMapContext(mlen) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.First = len(b)
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
} }
key := mapiterkey(iter) key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
case encoder.OpMapKey: case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
length := load(ctxptr, code.Length) idx := mapCtx.Idx
idx++ idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length { if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b) b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx) mapCtx.Idx = int(idx)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
b = appendObjectEnd(ctx, code, b) b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next code = code.End.Next
} }
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) if idx < mapCtx.Len {
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.Idx = int(idx)
if idx < length { mapCtx.Start = len(b)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
} }
} }
case encoder.OpMapValue: case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b) b = appendColon(ctx, b)
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b))
} }
ptr := load(ctxptr, code.MapIter) value := mapitervalue(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
store(ctxptr, code.Next.Idx, uintptr(value)) store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter) mapiternext(&mapCtx.Iter)
code = code.Next code = code.Next
case encoder.OpMapEnd: case encoder.OpMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.Length)) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
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],
})
}
sort.Sort(mapCtx.Slice) sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items { for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
} }
buf = appendMapEnd(ctx, code, buf) buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]] b = b[:mapCtx.First]
b = append(b, buf...) b = append(b, buf...)
mapCtx.Buf = buf mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx) encoder.ReleaseMapContext(mapCtx)

View File

@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break break
} }
b = appendStructHead(ctx, b) b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr) mapCtx := encoder.NewMapContext(mlen)
ctx.KeepRefs = append(ctx.KeepRefs, iter) mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.MapIter, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.Length, uintptr(mlen)) ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.MapIter, uintptr(iter))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b) b = appendMapKeyIndent(ctx, code.Next, b)
} else { } else {
mapCtx := encoder.NewMapContext(mlen) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.First = len(b)
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
} }
key := mapiterkey(iter) key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
case encoder.OpMapKey: case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
length := load(ctxptr, code.Length) idx := mapCtx.Idx
idx++ idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length { if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b) b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx) mapCtx.Idx = int(idx)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
b = appendObjectEnd(ctx, code, b) b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next code = code.End.Next
} }
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) if idx < mapCtx.Len {
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.Idx = int(idx)
if idx < length { mapCtx.Start = len(b)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
} }
} }
case encoder.OpMapValue: case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b) b = appendColon(ctx, b)
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b))
} }
ptr := load(ctxptr, code.MapIter) value := mapitervalue(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
store(ctxptr, code.Next.Idx, uintptr(value)) store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter) mapiternext(&mapCtx.Iter)
code = code.Next code = code.Next
case encoder.OpMapEnd: case encoder.OpMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.Length)) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
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],
})
}
sort.Sort(mapCtx.Slice) sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items { for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
} }
buf = appendMapEnd(ctx, code, buf) buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]] b = b[:mapCtx.First]
b = append(b, buf...) b = append(b, buf...)
mapCtx.Buf = buf mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx) encoder.ReleaseMapContext(mapCtx)

View File

@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break break
} }
b = appendStructHead(ctx, b) b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr) mapCtx := encoder.NewMapContext(mlen)
ctx.KeepRefs = append(ctx.KeepRefs, iter) mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.MapIter, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.Length, uintptr(mlen)) ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.MapIter, uintptr(iter))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b) b = appendMapKeyIndent(ctx, code.Next, b)
} else { } else {
mapCtx := encoder.NewMapContext(mlen) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.First = len(b)
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
} }
key := mapiterkey(iter) key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
case encoder.OpMapKey: case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
length := load(ctxptr, code.Length) idx := mapCtx.Idx
idx++ idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length { if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b) b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx) mapCtx.Idx = int(idx)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
b = appendObjectEnd(ctx, code, b) b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next code = code.End.Next
} }
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) if idx < mapCtx.Len {
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.Idx = int(idx)
if idx < length { mapCtx.Start = len(b)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
} }
} }
case encoder.OpMapValue: case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b) b = appendColon(ctx, b)
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b))
} }
ptr := load(ctxptr, code.MapIter) value := mapitervalue(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
store(ctxptr, code.Next.Idx, uintptr(value)) store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter) mapiternext(&mapCtx.Iter)
code = code.Next code = code.Next
case encoder.OpMapEnd: case encoder.OpMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.Length)) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
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],
})
}
sort.Sort(mapCtx.Slice) sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items { for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
} }
buf = appendMapEnd(ctx, code, buf) buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]] b = b[:mapCtx.First]
b = append(b, buf...) b = append(b, buf...)
mapCtx.Buf = buf mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx) encoder.ReleaseMapContext(mapCtx)

View File

@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
break break
} }
b = appendStructHead(ctx, b) b = appendStructHead(ctx, b)
iter := mapiterinit(code.Type, uptr) mapCtx := encoder.NewMapContext(mlen)
ctx.KeepRefs = append(ctx.KeepRefs, iter) mapiterinit(code.Type, uptr, &mapCtx.Iter)
store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.MapIter, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.Length, uintptr(mlen)) ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.MapIter, uintptr(iter))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendMapKeyIndent(ctx, code.Next, b) b = appendMapKeyIndent(ctx, code.Next, b)
} else { } else {
mapCtx := encoder.NewMapContext(mlen) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.First = len(b)
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
} }
key := mapiterkey(iter) key := mapiterkey(&mapCtx.Iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
case encoder.OpMapKey: case encoder.OpMapKey:
idx := load(ctxptr, code.ElemIdx) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
length := load(ctxptr, code.Length) idx := mapCtx.Idx
idx++ idx++
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
if idx < length { if idx < mapCtx.Len {
b = appendMapKeyIndent(ctx, code, b) b = appendMapKeyIndent(ctx, code, b)
store(ctxptr, code.ElemIdx, idx) mapCtx.Idx = int(idx)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
b = appendObjectEnd(ctx, code, b) b = appendObjectEnd(ctx, code, b)
encoder.ReleaseMapContext(mapCtx)
code = code.End.Next code = code.End.Next
} }
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) if idx < mapCtx.Len {
mapCtx.Pos = append(mapCtx.Pos, len(b)) mapCtx.Idx = int(idx)
if idx < length { mapCtx.Start = len(b)
ptr := load(ctxptr, code.MapIter) key := mapiterkey(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
store(ctxptr, code.ElemIdx, idx)
key := mapiterkey(iter)
store(ctxptr, code.Next.Idx, uintptr(key)) store(ctxptr, code.Next.Idx, uintptr(key))
code = code.Next code = code.Next
} else { } else {
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
} }
} }
case encoder.OpMapValue: case encoder.OpMapValue:
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
b = appendColon(ctx, b) b = appendColon(ctx, b)
} else { } else {
ptr := load(ctxptr, code.End.MapPos) mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) mapCtx.Start = len(b)
mapCtx.Pos = append(mapCtx.Pos, len(b))
} }
ptr := load(ctxptr, code.MapIter) value := mapitervalue(&mapCtx.Iter)
iter := ptrToUnsafePtr(ptr)
value := mapitervalue(iter)
store(ctxptr, code.Next.Idx, uintptr(value)) store(ctxptr, code.Next.Idx, uintptr(value))
mapiternext(iter) mapiternext(&mapCtx.Iter)
code = code.Next code = code.Next
case encoder.OpMapEnd: case encoder.OpMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.Length)) mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.MapIter)))
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],
})
}
sort.Sort(mapCtx.Slice) sort.Sort(mapCtx.Slice)
buf := mapCtx.Buf buf := mapCtx.Buf
for _, item := range mapCtx.Slice.Items { for _, item := range mapCtx.Slice.Items {
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
} }
buf = appendMapEnd(ctx, code, buf) buf = appendMapEnd(ctx, code, buf)
b = b[:pos[0]] b = b[:mapCtx.First]
b = append(b, buf...) b = append(b, buf...)
mapCtx.Buf = buf mapCtx.Buf = buf
encoder.ReleaseMapContext(mapCtx) encoder.ReleaseMapContext(mapCtx)