Optimize opcode.idx and seenPtr

This commit is contained in:
Masaaki Goshima 2020-08-31 03:14:37 +09:00
parent 572d4842a5
commit a6276c4d8e
5 changed files with 104 additions and 94 deletions

View File

@ -164,9 +164,9 @@ func (e *Encoder) encode(v interface{}) error {
} }
ctx := codeSet.ctx.Get().(*encodeRuntimeContext) ctx := codeSet.ctx.Get().(*encodeRuntimeContext)
p := uintptr(header.ptr) p := uintptr(header.ptr)
ctx.reset()
ctx.init(p) ctx.init(p)
err := e.run(ctx, code) seenPtr := map[uintptr]struct{}{}
err := e.run(ctx, seenPtr, code)
if e.enabledIndent { if e.enabledIndent {
codeSet.codeIndent.Put(code) codeSet.codeIndent.Put(code)
} else { } else {
@ -210,8 +210,7 @@ func (e *Encoder) encode(v interface{}) error {
ctx: sync.Pool{ ctx: sync.Pool{
New: func() interface{} { New: func() interface{} {
return &encodeRuntimeContext{ return &encodeRuntimeContext{
ptrs: make([]uintptr, codeLength), ptrs: make([]uintptr, codeLength),
seenPtr: map[uintptr]struct{}{},
} }
}, },
}, },
@ -219,19 +218,22 @@ func (e *Encoder) encode(v interface{}) error {
cachedOpcode.set(typeptr, codeSet) cachedOpcode.set(typeptr, codeSet)
p := uintptr(header.ptr) p := uintptr(header.ptr)
ctx := codeSet.ctx.Get().(*encodeRuntimeContext) ctx := codeSet.ctx.Get().(*encodeRuntimeContext)
ctx.reset()
ctx.init(p) ctx.init(p)
var c *opcode
if e.enabledIndent { if e.enabledIndent {
err := e.run(ctx, codeIndent) c = codeIndent
codeSet.ctx.Put(ctx) } else {
return err c = code
} }
if err := e.run(ctx, code); err != nil {
seenPtr := map[uintptr]struct{}{}
if err := e.run(ctx, seenPtr, c); err != nil {
codeSet.ctx.Put(ctx) codeSet.ctx.Put(ctx)
return err return err
} }
codeSet.ctx.Put(ctx) codeSet.ctx.Put(ctx)
return err return nil
} }
func (e *Encoder) encodeInt(v int) { func (e *Encoder) encodeInt(v int) {

View File

@ -267,11 +267,12 @@ func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) {
func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
code := (*opcode)(unsafe.Pointer(&interfaceCode{ code := (*opcode)(unsafe.Pointer(&interfaceCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opInterface, op: opInterface,
typ: ctx.typ, typ: ctx.typ,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
next: newEndOp(ctx), indent: ctx.indent,
next: newEndOp(ctx),
}, },
root: ctx.root, root: ctx.root,
})) }))
@ -588,11 +589,12 @@ func (e *Encoder) optimizeStructField(op opType, tag *structTag, withIndent bool
func (e *Encoder) recursiveCode(ctx *encodeCompileContext, code *compiledCode) *opcode { func (e *Encoder) recursiveCode(ctx *encodeCompileContext, code *compiledCode) *opcode {
c := (*opcode)(unsafe.Pointer(&recursiveCode{ c := (*opcode)(unsafe.Pointer(&recursiveCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructFieldRecursive, op: opStructFieldRecursive,
typ: ctx.typ, typ: ctx.typ,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
next: newEndOp(ctx), indent: ctx.indent,
next: newEndOp(ctx),
}, },
jmp: code, jmp: code,
})) }))
@ -726,7 +728,7 @@ func (e *Encoder) optimizeAnonymousFields(head *structFieldCode) {
if codeType == codeStructField { if codeType == codeStructField {
if e.isNotExistsField(code.next.toStructFieldCode()) { if e.isNotExistsField(code.next.toStructFieldCode()) {
code.next = code.nextField code.next = code.nextField
diff := code.next.idx - code.idx diff := code.next.displayIdx - code.displayIdx
for i := 0; i < diff; i++ { for i := 0; i < diff; i++ {
code.next.decOpcodeIndex() code.next.decOpcodeIndex()
} }
@ -763,7 +765,7 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
} else if f.op == opStructEnd { } else if f.op == opStructEnd {
f.op = opStructAnonymousEnd f.op = opStructAnonymousEnd
} else if existsKey { } else if existsKey {
diff := f.nextField.idx - f.idx diff := f.nextField.displayIdx - f.displayIdx
for i := 0; i < diff; i++ { for i := 0; i < diff; i++ {
f.nextField.decOpcodeIndex() f.nextField.decOpcodeIndex()
} }
@ -814,7 +816,7 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
// head operation // head operation
fieldPair.curField.op = opStructFieldAnonymousHead fieldPair.curField.op = opStructFieldAnonymousHead
} else { } else {
diff := fieldPair.curField.nextField.idx - fieldPair.curField.idx diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
for i := 0; i < diff; i++ { for i := 0; i < diff; i++ {
fieldPair.curField.nextField.decOpcodeIndex() fieldPair.curField.nextField.decOpcodeIndex()
} }
@ -831,7 +833,7 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
// head operation // head operation
fieldPair.curField.op = opStructFieldAnonymousHead fieldPair.curField.op = opStructFieldAnonymousHead
} else { } else {
diff := fieldPair.curField.nextField.idx - fieldPair.curField.idx diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
for i := 0; i < diff; i++ { for i := 0; i < diff; i++ {
fieldPair.curField.nextField.decOpcodeIndex() fieldPair.curField.nextField.decOpcodeIndex()
} }
@ -919,10 +921,11 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
key := fmt.Sprintf(`"%s":`, tag.key) key := fmt.Sprintf(`"%s":`, tag.key)
fieldCode := &structFieldCode{ fieldCode := &structFieldCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
typ: valueCode.typ, typ: valueCode.typ,
idx: fieldOpcodeIndex, displayIdx: fieldOpcodeIndex,
next: valueCode, idx: uintptr(fieldOpcodeIndex) * 8,
indent: ctx.indent, next: valueCode,
indent: ctx.indent,
}, },
anonymousKey: field.Anonymous, anonymousKey: field.Anonymous,
key: []byte(key), key: []byte(key),
@ -958,10 +961,11 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
if head == nil { if head == nil {
head = &structFieldCode{ head = &structFieldCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructFieldHead, op: opStructFieldHead,
typ: typ, typ: typ,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
nextField: structEndCode, nextField: structEndCode,
} }
@ -972,7 +976,8 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
code = (*opcode)(unsafe.Pointer(head)) code = (*opcode)(unsafe.Pointer(head))
} }
structEndCode.idx = ctx.opcodeIndex structEndCode.displayIdx = ctx.opcodeIndex
structEndCode.idx = uintptr(ctx.opcodeIndex) * 8
ctx.incOpcodeIndex() ctx.incOpcodeIndex()
if ctx.withIndent { if ctx.withIndent {

View File

@ -59,12 +59,7 @@ func (c *encodeCompileContext) decOpcodeIndex() {
} }
type encodeRuntimeContext struct { type encodeRuntimeContext struct {
ptrs []uintptr ptrs []uintptr
seenPtr map[uintptr]struct{}
}
func (c *encodeRuntimeContext) reset() {
c.seenPtr = map[uintptr]struct{}{}
} }
func (c *encodeRuntimeContext) init(p uintptr) { func (c *encodeRuntimeContext) init(p uintptr) {

View File

@ -13,20 +13,22 @@ func copyOpcode(code *opcode) *opcode {
} }
type opcodeHeader struct { type opcodeHeader struct {
op opType op opType
typ *rtype typ *rtype
idx int displayIdx int
indent int idx uintptr
next *opcode indent int
next *opcode
} }
func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader { func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader {
return &opcodeHeader{ return &opcodeHeader{
op: h.op, op: h.op,
typ: h.typ, typ: h.typ,
idx: h.idx, displayIdx: h.displayIdx,
indent: h.indent, idx: h.idx,
next: h.next.copy(codeMap), indent: h.indent,
next: h.next.copy(codeMap),
} }
} }
@ -41,11 +43,12 @@ func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode { func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
return &opcode{ return &opcode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: op, op: op,
typ: ctx.typ, typ: ctx.typ,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
next: next, indent: ctx.indent,
next: next,
}, },
} }
} }
@ -79,7 +82,7 @@ func (c *opcode) beforeLastCode() *opcode {
func (c *opcode) length() int { func (c *opcode) length() int {
var idx int var idx int
for code := c; code.op != opEnd; { for code := c; code.op != opEnd; {
idx = code.idx idx = code.displayIdx
switch code.op.codeType() { switch code.op.codeType() {
case codeArrayElem: case codeArrayElem:
code = code.toArrayElemCode().end code = code.toArrayElemCode().end
@ -96,7 +99,8 @@ func (c *opcode) length() int {
func (c *opcode) decOpcodeIndex() { func (c *opcode) decOpcodeIndex() {
for code := c; code.op != opEnd; { for code := c; code.op != opEnd; {
code.idx-- code.displayIdx--
code.idx -= 8
switch code.op.codeType() { switch code.op.codeType() {
case codeArrayElem: case codeArrayElem:
code = code.toArrayElemCode().end code = code.toArrayElemCode().end
@ -153,22 +157,22 @@ func (c *opcode) dump() string {
indent := strings.Repeat(" ", code.indent) indent := strings.Repeat(" ", code.indent)
switch code.op.codeType() { switch code.op.codeType() {
case codeArrayElem: case codeArrayElem:
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.idx, indent, code.op, unsafe.Pointer(code))) codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
code = code.toArrayElemCode().end code = code.toArrayElemCode().end
case codeSliceElem: case codeSliceElem:
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.idx, indent, code.op, unsafe.Pointer(code))) codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
code = code.toSliceElemCode().end code = code.toSliceElemCode().end
case codeMapKey: case codeMapKey:
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.idx, indent, code.op, unsafe.Pointer(code))) codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
code = code.toMapKeyCode().end code = code.toMapKeyCode().end
case codeStructField: case codeStructField:
sf := code.toStructFieldCode() sf := code.toStructFieldCode()
key := sf.displayKey key := sf.displayKey
offset := sf.offset offset := sf.offset
codes = append(codes, fmt.Sprintf("[%d]%s%s [%s:%d] ( %p )", code.idx, indent, code.op, key, offset, unsafe.Pointer(code))) codes = append(codes, fmt.Sprintf("[%d]%s%s [%s:%d] ( %p )", code.displayIdx, indent, code.op, key, offset, unsafe.Pointer(code)))
code = code.next code = code.next
default: default:
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.idx, indent, code.op, unsafe.Pointer(code))) codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
code = code.next code = code.next
} }
} }
@ -224,9 +228,10 @@ type sliceHeaderCode struct {
func newSliceHeaderCode(ctx *encodeCompileContext) *sliceHeaderCode { func newSliceHeaderCode(ctx *encodeCompileContext) *sliceHeaderCode {
return &sliceHeaderCode{ return &sliceHeaderCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opSliceHead, op: opSliceHead,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
} }
} }
@ -234,9 +239,10 @@ func newSliceHeaderCode(ctx *encodeCompileContext) *sliceHeaderCode {
func newSliceElemCode(ctx *encodeCompileContext, size uintptr) *sliceElemCode { func newSliceElemCode(ctx *encodeCompileContext, size uintptr) *sliceElemCode {
return &sliceElemCode{ return &sliceElemCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opSliceElem, op: opSliceElem,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
size: size, size: size,
} }
@ -307,9 +313,10 @@ type arrayHeaderCode struct {
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *arrayHeaderCode { func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *arrayHeaderCode {
return &arrayHeaderCode{ return &arrayHeaderCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opArrayHead, op: opArrayHead,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
len: uintptr(alen), len: uintptr(alen),
} }
@ -318,8 +325,9 @@ func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *arrayHeaderCode {
func newArrayElemCode(ctx *encodeCompileContext, alen int, size uintptr) *arrayElemCode { func newArrayElemCode(ctx *encodeCompileContext, alen int, size uintptr) *arrayElemCode {
return &arrayElemCode{ return &arrayElemCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opArrayElem, op: opArrayElem,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
idx: uintptr(ctx.opcodeIndex) * 8,
}, },
len: uintptr(alen), len: uintptr(alen),
size: size, size: size,
@ -536,10 +544,11 @@ func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *mapHeaderCode {
} }
return &mapHeaderCode{ return &mapHeaderCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: op, op: op,
typ: ctx.typ, typ: ctx.typ,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
} }
} }
@ -547,9 +556,10 @@ func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *mapHeaderCode {
func newMapKeyCode(ctx *encodeCompileContext) *mapKeyCode { func newMapKeyCode(ctx *encodeCompileContext) *mapKeyCode {
return &mapKeyCode{ return &mapKeyCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opMapKey, op: opMapKey,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
} }
} }
@ -557,9 +567,10 @@ func newMapKeyCode(ctx *encodeCompileContext) *mapKeyCode {
func newMapValueCode(ctx *encodeCompileContext) *mapValueCode { func newMapValueCode(ctx *encodeCompileContext) *mapValueCode {
return &mapValueCode{ return &mapValueCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opMapValue, op: opMapValue,
idx: ctx.opcodeIndex, displayIdx: ctx.opcodeIndex,
indent: ctx.indent, idx: uintptr(ctx.opcodeIndex) * 8,
indent: ctx.indent,
}, },
} }
} }

View File

@ -11,17 +11,16 @@ import (
"unsafe" "unsafe"
) )
func load(base uintptr, idx int) uintptr { func load(base uintptr, idx uintptr) uintptr {
return *(*uintptr)(unsafe.Pointer(base + uintptr(idx)*8)) return *(*uintptr)(unsafe.Pointer(base + idx))
} }
func store(base uintptr, idx int, p uintptr) { func store(base uintptr, idx uintptr, p uintptr) {
*(*uintptr)(unsafe.Pointer(base + uintptr(idx)*8)) = p *(*uintptr)(unsafe.Pointer(base + idx)) = p
} }
func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error { func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, code *opcode) error {
ctxptr := ctx.ptr() ctxptr := ctx.ptr()
seenPtr := ctx.seenPtr
for { for {
switch code.op { switch code.op {
case opPtr: case opPtr:
@ -143,11 +142,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
c = code c = code
} }
ctx := &encodeRuntimeContext{ ctx := &encodeRuntimeContext{
ptrs: make([]uintptr, c.length()), ptrs: make([]uintptr, c.length()),
seenPtr: seenPtr,
} }
ctx.init(uintptr(header.ptr)) ctx.init(uintptr(header.ptr))
if err := e.run(ctx, c); err != nil { if err := e.run(ctx, seenPtr, c); err != nil {
return err return err
} }
code = ifaceCode.next code = ifaceCode.next
@ -566,11 +564,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
recursive.seenPtr = ptr recursive.seenPtr = ptr
recursiveCode := newRecursiveCode(recursive) recursiveCode := newRecursiveCode(recursive)
ctx := &encodeRuntimeContext{ ctx := &encodeRuntimeContext{
ptrs: make([]uintptr, recursiveCode.length()), ptrs: make([]uintptr, recursiveCode.length()),
seenPtr: seenPtr,
} }
ctx.init(ptr) ctx.init(ptr)
if err := e.run(ctx, recursiveCode); err != nil { if err := e.run(ctx, seenPtr, recursiveCode); err != nil {
return err return err
} }
code = recursive.next code = recursive.next