From 40544f1ea20be26f477cb624091197df247c7a3b Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 30 Apr 2020 01:44:48 +0900 Subject: [PATCH] Optimize opcode --- encode_compile.go | 82 +++++++++++++++++++++------------------- encode_opcode.go | 61 ++++++++++++++++++------------ encode_vm.go | 96 +++++++++++++++++++++++++++-------------------- 3 files changed, 137 insertions(+), 102 deletions(-) diff --git a/encode_compile.go b/encode_compile.go index 7be73c9..83f89b9 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -54,18 +54,21 @@ func (e *Encoder) compileOp(typ *rtype) (*opcode, error) { } func (e *Encoder) compilePtrOp(typ *rtype) (*opcode, error) { - elem := typ.Elem() - code, err := e.compileOp(elem) + code, err := e.compileOp(typ.Elem()) if err != nil { return nil, err } - return &opcode{ - opcodeHeader: &opcodeHeader{ - op: opPtr, - typ: typ, - next: code, - }, - }, nil + switch code.op { + case opStructFieldHead: + code.op = opStructFieldPtrHead + case opStructFieldHeadInt: + code.op = opStructFieldPtrHeadInt + case opStructFieldHeadString: + code.op = opStructFieldPtrHeadString + default: + return newOpCode(opPtr, typ, code), nil + } + return code, nil } func (e *Encoder) compileIntOp(typ *rtype) (*opcode, error) { @@ -132,22 +135,21 @@ func (e *Encoder) compileSliceOp(typ *rtype) (*opcode, error) { return nil, err } - // header => firstElem => opcode => elem => end - // ^ | - // |________| + // header => opcode => elem => end + // ^ | + // |________| - header := &opcode{opcodeHeader: &opcodeHeader{op: opSliceHead}} - firstElem := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElemFirst}} + header := newSliceHeaderCode() elemCode := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElem}, size: size} - end := &opcode{opcodeHeader: &opcodeHeader{op: opSliceEnd}} + end := newOpCode(opSliceEnd, nil, nil) - header.next = (*opcode)(unsafe.Pointer(firstElem)) - firstElem.next = code - firstElem.elem = elemCode + header.elem = elemCode + header.end = end + header.next = code code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) elemCode.next = code elemCode.end = end - end.next = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} + end.next = newEndOp() return (*opcode)(unsafe.Pointer(header)), nil } @@ -157,9 +159,11 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) { // |________| fieldNum := typ.NumField() fieldIdx := 0 - header := &opcode{opcodeHeader: &opcodeHeader{op: opStructHead}} - code := header - var prevField *structFieldCode + var ( + head *structFieldCode + code *opcode + prevField *structFieldCode + ) for i := 0; i < fieldNum; i++ { field := typ.Field(i) if e.isIgnoredStructField(field) { @@ -182,22 +186,22 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) { if fieldIdx == 0 { fieldCode := &structFieldCode{ opcodeHeader: &opcodeHeader{ - op: opStructFieldFirst, + op: opStructFieldHead, typ: fieldType, next: valueCode, }, key: key, offset: field.Offset, } - code.next = (*opcode)(unsafe.Pointer(fieldCode)) + head = fieldCode + code = (*opcode)(unsafe.Pointer(fieldCode)) prevField = fieldCode - if valueCode.op == opInt { - fieldCode.op = opStructFieldFirstInt - code = (*opcode)(unsafe.Pointer(fieldCode)) - } else if valueCode.op == opString { - fieldCode.op = opStructFieldFirstString - code = (*opcode)(unsafe.Pointer(fieldCode)) - } else { + switch valueCode.op { + case opInt: + fieldCode.op = opStructFieldHeadInt + case opString: + fieldCode.op = opStructFieldHeadString + default: code = valueCode.beforeLastCode() } } else { @@ -213,21 +217,23 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) { code.next = (*opcode)(unsafe.Pointer(fieldCode)) prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode)) prevField = fieldCode - if valueCode.op == opInt { + switch valueCode.op { + case opInt: fieldCode.op = opStructFieldInt code = (*opcode)(unsafe.Pointer(fieldCode)) - } else if valueCode.op == opString { + case opString: fieldCode.op = opStructFieldString code = (*opcode)(unsafe.Pointer(fieldCode)) - } else { + default: code = valueCode.beforeLastCode() } } - prevField.nextField = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} + prevField.nextField = newEndOp() fieldIdx++ } - structEndCode := &opcode{opcodeHeader: &opcodeHeader{op: opStructEnd}} + structEndCode := newOpCode(opStructEnd, nil, nil) + head.end = structEndCode code.next = structEndCode - structEndCode.next = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} - return header, nil + structEndCode.next = newEndOp() + return (*opcode)(unsafe.Pointer(head)), nil } diff --git a/encode_opcode.go b/encode_opcode.go index 992ed58..81a789c 100644 --- a/encode_opcode.go +++ b/encode_opcode.go @@ -27,15 +27,16 @@ const ( opBool opPtr opSliceHead - opSliceElemFirst opSliceElem opSliceEnd - opStructHead - opStructFieldFirst + opStructFieldHead + opStructFieldHeadInt + opStructFieldHeadString + opStructFieldPtrHead + opStructFieldPtrHeadInt + opStructFieldPtrHeadString opStructField - opStructFieldFirstInt opStructFieldInt - opStructFieldFirstString opStructFieldString opStructEnd ) @@ -76,24 +77,26 @@ func (t opType) String() string { return "PTR" case opSliceHead: return "SLICE_HEAD" - case opSliceElemFirst: - return "SLICE_ELEM_FIRST" case opSliceElem: return "SLICE_ELEM" case opSliceEnd: return "SLICE_END" - case opStructHead: - return "STRUCT_HEAD" - case opStructFieldFirst: - return "STRUCT_FIELD_FIRST" + case opStructFieldHead: + return "STRUCT_FIELD_HEAD" + case opStructFieldHeadInt: + return "STRUCT_FIELD_HEAD_INT" + case opStructFieldHeadString: + return "STRUCT_FIELD_HEAD_STRING" + case opStructFieldPtrHead: + return "STRUCT_FIELD_PTR_HEAD" + case opStructFieldPtrHeadInt: + return "STRUCT_FIELD_PTR_HEAD_INT" + case opStructFieldPtrHeadString: + return "STRUCT_FIELD_PTR_HEAD_STRING" case opStructField: return "STRUCT_FIELD" - case opStructFieldFirstInt: - return "STRUCT_FIELD_FIRST_INT" case opStructFieldInt: return "STRUCT_FIELD_INT" - case opStructFieldFirstString: - return "STRUCT_FIELD_FIRST_STRING" case opStructFieldString: return "STRUCT_FIELD_STRING" case opStructEnd: @@ -157,18 +160,32 @@ func (c *opcode) dump() string { return strings.Join(codes, "\n") } +func (c *opcode) toSliceHeaderCode() *sliceHeaderCode { + return (*sliceHeaderCode)(unsafe.Pointer(c)) +} + func (c *opcode) toSliceElemCode() *sliceElemCode { return (*sliceElemCode)(unsafe.Pointer(c)) } -func (c *opcode) toStructHeaderCode() *structHeaderCode { - return (*structHeaderCode)(unsafe.Pointer(c)) -} - func (c *opcode) toStructFieldCode() *structFieldCode { return (*structFieldCode)(unsafe.Pointer(c)) } +type sliceHeaderCode struct { + *opcodeHeader + elem *sliceElemCode + end *opcode +} + +func newSliceHeaderCode() *sliceHeaderCode { + return &sliceHeaderCode{ + opcodeHeader: &opcodeHeader{ + op: opSliceHead, + }, + } +} + type sliceElemCode struct { *opcodeHeader idx uintptr @@ -185,14 +202,10 @@ func (c *sliceElemCode) set(header *reflect.SliceHeader) { c.data = header.Data } -type structHeaderCode struct { - *opcodeHeader - end *opcode -} - type structFieldCode struct { *opcodeHeader key string offset uintptr nextField *opcode + end *opcode } diff --git a/encode_vm.go b/encode_vm.go index 1695904..c122b36 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -59,24 +59,22 @@ func (e *Encoder) run(code *opcode) error { code = code.next case opSliceHead: p := code.ptr + headerCode := code.toSliceHeaderCode() if p == 0 { e.encodeString("null") - code = code.next.toSliceElemCode().end + code = headerCode.end.next } else { e.encodeByte('[') header := (*reflect.SliceHeader)(unsafe.Pointer(p)) - firstElem := code.next.toSliceElemCode() - firstElem.set(header) - firstElem.elem.set(header) - code = code.next - } - case opSliceElemFirst: - c := code.toSliceElemCode() - if c.len > 0 { - code = code.next - code.ptr = c.data - } else { - code = c.end + headerCode := code.toSliceHeaderCode() + headerCode.elem.set(header) + if header.Len > 0 { + code = code.next + code.ptr = header.Data + } else { + e.encodeByte(']') + code = headerCode.end.next + } } case opSliceElem: c := code.toSliceElemCode() @@ -86,39 +84,57 @@ func (e *Encoder) run(code *opcode) error { code = code.next code.ptr = c.data + c.idx*c.size } else { - code = c.end + e.encodeByte(']') + code = c.end.next } - case opSliceEnd: - e.encodeByte(']') - code = code.next - case opStructHead: - ptr := code.ptr + case opStructFieldPtrHead: + code.ptr = e.ptrToPtr(code.ptr) + fallthrough + case opStructFieldHead: + field := code.toStructFieldCode() + ptr := field.ptr if ptr == 0 { e.encodeString("null") - code = code.toStructHeaderCode().end + code = field.end } else { e.encodeByte('{') - code = code.next - code.ptr = ptr + e.encodeString(field.key) + code = field.next + code.ptr = field.ptr + field.offset + field.nextField.ptr = field.ptr + } + case opStructFieldPtrHeadInt: + code.ptr = e.ptrToPtr(code.ptr) + fallthrough + case opStructFieldHeadInt: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeString("null") + code = field.end + } else { + e.encodeByte('{') + e.encodeString(field.key) + e.encodeInt(e.ptrToInt(field.ptr + field.offset)) + field.nextField.ptr = field.ptr + code = field.next + } + case opStructFieldPtrHeadString: + code.ptr = e.ptrToPtr(code.ptr) + fallthrough + case opStructFieldHeadString: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeString("null") + code = field.end + } else { + e.encodeByte('{') + e.encodeString(field.key) + e.encodeEscapedString(e.ptrToString(field.ptr + field.offset)) + field.nextField.ptr = field.ptr + code = field.next } - case opStructFieldFirst: - c := code.toStructFieldCode() - e.encodeString(c.key) - code = code.next - code.ptr = c.ptr + c.offset - c.nextField.ptr = c.ptr - case opStructFieldFirstInt: - c := code.toStructFieldCode() - e.encodeString(c.key) - c.nextField.ptr = c.ptr - e.encodeInt(e.ptrToInt(c.ptr + c.offset)) - code = code.next - case opStructFieldFirstString: - c := code.toStructFieldCode() - e.encodeString(c.key) - c.nextField.ptr = c.ptr - e.encodeEscapedString(e.ptrToString(c.ptr + c.offset)) - code = code.next case opStructField: e.encodeByte(',') c := code.toStructFieldCode()