diff --git a/internal/cmd/generator/vm.go.tmpl b/internal/cmd/generator/vm.go.tmpl index b78b5eb..4be6b80 100644 --- a/internal/cmd/generator/vm.go.tmpl +++ b/internal/cmd/generator/vm.go.tmpl @@ -403,48 +403,41 @@ 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 { @@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } 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) diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index b7fa99a..79a3f64 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -222,33 +222,54 @@ 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 } @@ -256,17 +277,17 @@ 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 diff --git a/internal/encoder/map112.go b/internal/encoder/map112.go index 31858d0..e96ffad 100644 --- a/internal/encoder/map112.go +++ b/internal/encoder/map112.go @@ -1,3 +1,4 @@ +//go:build !go1.13 // +build !go1.13 package encoder @@ -5,4 +6,4 @@ package encoder import "unsafe" //go:linkname MapIterValue reflect.mapitervalue -func MapIterValue(it unsafe.Pointer) unsafe.Pointer +func MapIterValue(it *mapIter) unsafe.Pointer diff --git a/internal/encoder/map113.go b/internal/encoder/map113.go index f49c27b..9b69dcc 100644 --- a/internal/encoder/map113.go +++ b/internal/encoder/map113.go @@ -1,3 +1,4 @@ +//go:build go1.13 // +build go1.13 package encoder @@ -5,4 +6,4 @@ package encoder import "unsafe" //go:linkname MapIterValue reflect.mapiterelem -func MapIterValue(it unsafe.Pointer) unsafe.Pointer +func MapIterValue(it *mapIter) unsafe.Pointer diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go index cfd2d5a..903dd6f 100644 --- a/internal/encoder/opcode.go +++ b/internal/encoder/opcode.go @@ -39,10 +39,8 @@ type Opcode struct { Type *runtime.Type // go type Jmp *CompiledCode // for recursive call - ElemIdx uint32 // offset to access array/slice/map elem - Length uint32 // offset to access slice/map length or array length - MapIter uint32 // offset to access map iterator - MapPos uint32 // offset to access position list for sorted map + ElemIdx uint32 // offset to access array/slice elem + Length uint32 // offset to access slice length or array length Indent uint32 // indent number Size uint32 // array/slice elem size DisplayIdx uint32 // opcode index @@ -91,8 +89,6 @@ func (c *Opcode) MaxIdx() uint32 { c.Idx, c.ElemIdx, c.Length, - c.MapIter, - c.MapPos, c.Size, } { if max < value { @@ -341,8 +337,6 @@ func copyOpcode(code *Opcode) *Opcode { DisplayKey: c.DisplayKey, ElemIdx: c.ElemIdx, Length: c.Length, - MapIter: c.MapIter, - MapPos: c.MapPos, Size: c.Size, Indent: c.Indent, Jmp: c.Jmp, @@ -448,26 +442,21 @@ func (c *Opcode) dumpHead(code *Opcode) string { func (c *Opcode) dumpMapHead(code *Opcode) string { return fmt.Sprintf( - `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + `[%03d]%s%s ([idx:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, code.Idx/uintptrSize, - code.ElemIdx/uintptrSize, - code.Length/uintptrSize, - code.MapIter/uintptrSize, ) } func (c *Opcode) dumpMapEnd(code *Opcode) string { return fmt.Sprintf( - `[%03d]%s%s ([idx:%d][mapPos:%d][length:%d])`, + `[%03d]%s%s ([idx:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, code.Idx/uintptrSize, - code.MapPos/uintptrSize, - code.Length/uintptrSize, ) } @@ -504,25 +493,21 @@ func (c *Opcode) dumpField(code *Opcode) string { func (c *Opcode) dumpKey(code *Opcode) string { return fmt.Sprintf( - `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + `[%03d]%s%s ([idx:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, code.Idx/uintptrSize, - code.ElemIdx/uintptrSize, - code.Length/uintptrSize, - code.MapIter/uintptrSize, ) } func (c *Opcode) dumpValue(code *Opcode) string { return fmt.Sprintf( - `[%03d]%s%s ([idx:%d][mapIter:%d])`, + `[%03d]%s%s ([idx:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, code.Idx/uintptrSize, - code.MapIter/uintptrSize, ) } @@ -629,19 +614,11 @@ func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, leng func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode { idx := opcodeOffset(ctx.ptrIndex) ctx.incPtrIndex() - elemIdx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - length := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - mapIter := opcodeOffset(ctx.ptrIndex) return &Opcode{ Op: OpMap, Type: typ, Idx: idx, DisplayIdx: ctx.opcodeIndex, - ElemIdx: elemIdx, - Length: length, - MapIter: mapIter, Indent: ctx.indent, } } @@ -650,11 +627,8 @@ func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode return &Opcode{ Op: OpMapKey, Type: typ, - Idx: opcodeOffset(ctx.ptrIndex), + Idx: head.Idx, DisplayIdx: ctx.opcodeIndex, - ElemIdx: head.ElemIdx, - Length: head.Length, - MapIter: head.MapIter, Indent: ctx.indent, } } @@ -663,28 +637,20 @@ func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opco return &Opcode{ Op: OpMapValue, Type: typ, - Idx: opcodeOffset(ctx.ptrIndex), + Idx: head.Idx, DisplayIdx: ctx.opcodeIndex, - ElemIdx: head.ElemIdx, - Length: head.Length, - MapIter: head.MapIter, Indent: ctx.indent, } } func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode { - mapPos := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - idx := opcodeOffset(ctx.ptrIndex) return &Opcode{ Op: OpMapEnd, Type: typ, - Idx: idx, - Next: newEndOp(ctx, typ), + Idx: head.Idx, DisplayIdx: ctx.opcodeIndex, - Length: head.Length, - MapPos: mapPos, Indent: ctx.indent, + Next: newEndOp(ctx, typ), } } diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index b78b5eb..4be6b80 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -403,48 +403,41 @@ 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 { @@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } 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) diff --git a/internal/encoder/vm_color/vm.go b/internal/encoder/vm_color/vm.go index c7c6818..b13abe8 100644 --- a/internal/encoder/vm_color/vm.go +++ b/internal/encoder/vm_color/vm.go @@ -403,48 +403,41 @@ 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 { @@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } 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) diff --git a/internal/encoder/vm_color_indent/vm.go b/internal/encoder/vm_color_indent/vm.go index 691ffc6..a45aa54 100644 --- a/internal/encoder/vm_color_indent/vm.go +++ b/internal/encoder/vm_color_indent/vm.go @@ -403,48 +403,41 @@ 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 { @@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } 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) diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index fcc3b32..d1e0b45 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -403,48 +403,41 @@ 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 { @@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } 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) diff --git a/size_test.go b/size_test.go index 3a47195..9804cab 100644 --- a/size_test.go +++ b/size_test.go @@ -11,8 +11,8 @@ func TestOpcodeSize(t *testing.T) { const uintptrSize = 4 << (^uintptr(0) >> 63) if uintptrSize == 8 { size := unsafe.Sizeof(encoder.Opcode{}) - if size != 120 { - t.Fatalf("unexpected opcode size: expected 120bytes but got %dbytes", size) + if size != 112 { + t.Fatalf("unexpected opcode size: expected 112bytes but got %dbytes", size) } } }