From 02797daba48e36cbde12778be859ef7789fb5743 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 25 Jan 2021 13:10:07 +0900 Subject: [PATCH] Optimize map operation --- encode_vm.go | 56 +++++++++++++++-------------------- encode_vm_escaped.go | 14 +++++---- encode_vm_escaped_indent.go | 58 ++++++++++++++++--------------------- encode_vm_indent.go | 57 ++++++++++++++++-------------------- 4 files changed, 82 insertions(+), 103 deletions(-) diff --git a/encode_vm.go b/encode_vm.go index 3d80ff4..3f08600 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -378,11 +378,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( store(ctxptr, code.length, uintptr(mlen)) store(ctxptr, code.mapIter, uintptr(iter)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } key := mapiterkey(iter) store(ctxptr, code.next.idx, uintptr(key)) @@ -419,11 +418,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( key := mapiterkey(iter) store(ctxptr, code.next.idx, uintptr(key)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } code = code.next } else { @@ -451,8 +449,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( } } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) if idx < length { ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -470,8 +468,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( b[last] = ':' } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) } ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -482,14 +480,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( case opMapEnd: // this operation only used by sorted map. length := int(load(ctxptr, code.length)) - type mapKV struct { - key string - value string - } - kvs := make([]mapKV, 0, length) ptr := load(ctxptr, code.mapPos) - posPtr := e.ptrToUnsafePtr(ptr) - pos := *(*[]int)(posPtr) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + pos := mapCtx.pos for i := 0; i < length; i++ { startKey := pos[i*2] startValue := pos[i*2+1] @@ -499,25 +492,24 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ( } else { endValue = len(b) } - kvs = append(kvs, mapKV{ - key: string(b[startKey:startValue]), - value: string(b[startValue:endValue]), + mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ + key: b[startKey:startValue], + value: b[startValue:endValue], }) } - sort.Slice(kvs, func(i, j int) bool { - return kvs[i].key < kvs[j].key - }) - buf := b[pos[0]:] - buf = buf[:0] - for _, kv := range kvs { - buf = append(buf, []byte(kv.key)...) + sort.Sort(mapCtx.slice) + buf := mapCtx.buf + for _, item := range mapCtx.slice.items { + buf = append(buf, item.key...) buf[len(buf)-1] = ':' - buf = append(buf, []byte(kv.value)...) + buf = append(buf, item.value...) } buf[len(buf)-1] = '}' buf = append(buf, ',') b = b[:pos[0]] b = append(b, buf...) + mapCtx.buf = buf + releaseMapContext(mapCtx) code = code.next case opStructFieldPtrAnonymousHeadRecursive: store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) diff --git a/encode_vm_escaped.go b/encode_vm_escaped.go index e18b903..8085891 100644 --- a/encode_vm_escaped.go +++ b/encode_vm_escaped.go @@ -460,15 +460,17 @@ func (e *Encoder) runEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcod }) } sort.Sort(mapCtx.slice) + buf := mapCtx.buf for _, item := range mapCtx.slice.items { - mapCtx.buf = append(mapCtx.buf, item.key...) - mapCtx.buf[len(mapCtx.buf)-1] = ':' - mapCtx.buf = append(mapCtx.buf, item.value...) + buf = append(buf, item.key...) + buf[len(buf)-1] = ':' + buf = append(buf, item.value...) } - mapCtx.buf[len(mapCtx.buf)-1] = '}' - mapCtx.buf = append(mapCtx.buf, ',') + buf[len(buf)-1] = '}' + buf = append(buf, ',') b = b[:pos[0]] - b = append(b, mapCtx.buf...) + b = append(b, buf...) + mapCtx.buf = buf releaseMapContext(mapCtx) code = code.next case opStructFieldPtrAnonymousHeadRecursive: diff --git a/encode_vm_escaped_indent.go b/encode_vm_escaped_indent.go index 66eeb92..a11a7fa 100644 --- a/encode_vm_escaped_indent.go +++ b/encode_vm_escaped_indent.go @@ -405,11 +405,10 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet store(ctxptr, code.mapIter, uintptr(iter)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } else { b = e.encodeIndent(b, code.next.indent) } @@ -452,11 +451,10 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet store(ctxptr, code.next.idx, uintptr(key)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } else { b = e.encodeIndent(b, code.next.indent) } @@ -490,8 +488,8 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet } } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) if idx < length { ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -508,8 +506,8 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet b = append(b, ':', ' ') } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) } ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -520,13 +518,9 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet case opMapEnd: // this operation only used by sorted map length := int(load(ctxptr, code.length)) - type mapKV struct { - key string - value string - } - kvs := make([]mapKV, 0, length) ptr := load(ctxptr, code.mapPos) - pos := *(*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + pos := mapCtx.pos for i := 0; i < length; i++ { startKey := pos[i*2] startValue := pos[i*2+1] @@ -536,33 +530,31 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet } else { endValue = len(b) } - kvs = append(kvs, mapKV{ - key: string(b[startKey:startValue]), - value: string(b[startValue:endValue]), + mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ + key: b[startKey:startValue], + value: b[startValue:endValue], }) } - sort.Slice(kvs, func(i, j int) bool { - return kvs[i].key < kvs[j].key - }) - buf := b[pos[0]:] - buf = buf[:0] - - for _, kv := range kvs { + sort.Sort(mapCtx.slice) + buf := mapCtx.buf + for _, item := range mapCtx.slice.items { buf = append(buf, e.prefix...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...) - - buf = append(buf, []byte(kv.key)...) + buf = append(buf, item.key...) buf[len(buf)-2] = ':' buf[len(buf)-1] = ' ' - buf = append(buf, []byte(kv.value)...) + buf = append(buf, item.value...) } buf = buf[:len(buf)-2] buf = append(buf, '\n') buf = append(buf, e.prefix...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...) buf = append(buf, '}', ',', '\n') + b = b[:pos[0]] b = append(b, buf...) + mapCtx.buf = buf + releaseMapContext(mapCtx) code = code.next case opStructFieldPtrHead: p := load(ctxptr, code.idx) diff --git a/encode_vm_indent.go b/encode_vm_indent.go index fdac498..4800085 100644 --- a/encode_vm_indent.go +++ b/encode_vm_indent.go @@ -405,11 +405,10 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode store(ctxptr, code.mapIter, uintptr(iter)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } else { b = e.encodeIndent(b, code.next.indent) } @@ -452,11 +451,10 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode store(ctxptr, code.next.idx, uintptr(key)) if !e.unorderedMap { - pos := make([]int, 0, mlen) - pos = append(pos, len(b)) - posPtr := unsafe.Pointer(&pos) - ctx.keepRefs = append(ctx.keepRefs, posPtr) - store(ctxptr, code.end.mapPos, uintptr(posPtr)) + mapCtx := 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))) } else { b = e.encodeIndent(b, code.next.indent) } @@ -490,8 +488,8 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode } } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) if idx < length { ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -508,8 +506,8 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode b = append(b, ':', ' ') } else { ptr := load(ctxptr, code.end.mapPos) - posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) - *posPtr = append(*posPtr, len(b)) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + mapCtx.pos = append(mapCtx.pos, len(b)) } ptr := load(ctxptr, code.mapIter) iter := e.ptrToUnsafePtr(ptr) @@ -520,13 +518,9 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode case opMapEnd: // this operation only used by sorted map length := int(load(ctxptr, code.length)) - type mapKV struct { - key string - value string - } - kvs := make([]mapKV, 0, length) ptr := load(ctxptr, code.mapPos) - pos := *(*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) + mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr)) + pos := mapCtx.pos for i := 0; i < length; i++ { startKey := pos[i*2] startValue := pos[i*2+1] @@ -536,32 +530,31 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode } else { endValue = len(b) } - kvs = append(kvs, mapKV{ - key: string(b[startKey:startValue]), - value: string(b[startValue:endValue]), + mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ + key: b[startKey:startValue], + value: b[startValue:endValue], }) } - sort.Slice(kvs, func(i, j int) bool { - return kvs[i].key < kvs[j].key - }) - buf := b[pos[0]:] - buf = buf[:0] - for _, kv := range kvs { + sort.Sort(mapCtx.slice) + buf := mapCtx.buf + for _, item := range mapCtx.slice.items { buf = append(buf, e.prefix...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...) - - buf = append(buf, []byte(kv.key)...) + buf = append(buf, item.key...) buf[len(buf)-2] = ':' buf[len(buf)-1] = ' ' - buf = append(buf, []byte(kv.value)...) + buf = append(buf, item.value...) } buf = buf[:len(buf)-2] buf = append(buf, '\n') buf = append(buf, e.prefix...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...) buf = append(buf, '}', ',', '\n') + b = b[:pos[0]] b = append(b, buf...) + mapCtx.buf = buf + releaseMapContext(mapCtx) code = code.next case opStructFieldPtrHead: p := load(ctxptr, code.idx)