Optimize opcode

This commit is contained in:
Masaaki Goshima 2020-04-30 01:44:48 +09:00
parent 4f3b1262b2
commit 40544f1ea2
3 changed files with 137 additions and 102 deletions

View File

@ -54,18 +54,21 @@ func (e *Encoder) compileOp(typ *rtype) (*opcode, error) {
} }
func (e *Encoder) compilePtrOp(typ *rtype) (*opcode, error) { func (e *Encoder) compilePtrOp(typ *rtype) (*opcode, error) {
elem := typ.Elem() code, err := e.compileOp(typ.Elem())
code, err := e.compileOp(elem)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &opcode{ switch code.op {
opcodeHeader: &opcodeHeader{ case opStructFieldHead:
op: opPtr, code.op = opStructFieldPtrHead
typ: typ, case opStructFieldHeadInt:
next: code, code.op = opStructFieldPtrHeadInt
}, case opStructFieldHeadString:
}, nil code.op = opStructFieldPtrHeadString
default:
return newOpCode(opPtr, typ, code), nil
}
return code, nil
} }
func (e *Encoder) compileIntOp(typ *rtype) (*opcode, error) { func (e *Encoder) compileIntOp(typ *rtype) (*opcode, error) {
@ -132,22 +135,21 @@ func (e *Encoder) compileSliceOp(typ *rtype) (*opcode, error) {
return nil, err return nil, err
} }
// header => firstElem => opcode => elem => end // header => opcode => elem => end
// ^ | // ^ |
// |________| // |________|
header := &opcode{opcodeHeader: &opcodeHeader{op: opSliceHead}} header := newSliceHeaderCode()
firstElem := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElemFirst}}
elemCode := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElem}, size: size} 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)) header.elem = elemCode
firstElem.next = code header.end = end
firstElem.elem = elemCode header.next = code
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
elemCode.next = code elemCode.next = code
elemCode.end = end elemCode.end = end
end.next = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} end.next = newEndOp()
return (*opcode)(unsafe.Pointer(header)), nil return (*opcode)(unsafe.Pointer(header)), nil
} }
@ -157,9 +159,11 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) {
// |________| // |________|
fieldNum := typ.NumField() fieldNum := typ.NumField()
fieldIdx := 0 fieldIdx := 0
header := &opcode{opcodeHeader: &opcodeHeader{op: opStructHead}} var (
code := header head *structFieldCode
var prevField *structFieldCode code *opcode
prevField *structFieldCode
)
for i := 0; i < fieldNum; i++ { for i := 0; i < fieldNum; i++ {
field := typ.Field(i) field := typ.Field(i)
if e.isIgnoredStructField(field) { if e.isIgnoredStructField(field) {
@ -182,22 +186,22 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) {
if fieldIdx == 0 { if fieldIdx == 0 {
fieldCode := &structFieldCode{ fieldCode := &structFieldCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructFieldFirst, op: opStructFieldHead,
typ: fieldType, typ: fieldType,
next: valueCode, next: valueCode,
}, },
key: key, key: key,
offset: field.Offset, offset: field.Offset,
} }
code.next = (*opcode)(unsafe.Pointer(fieldCode)) head = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode prevField = fieldCode
if valueCode.op == opInt { switch valueCode.op {
fieldCode.op = opStructFieldFirstInt case opInt:
code = (*opcode)(unsafe.Pointer(fieldCode)) fieldCode.op = opStructFieldHeadInt
} else if valueCode.op == opString { case opString:
fieldCode.op = opStructFieldFirstString fieldCode.op = opStructFieldHeadString
code = (*opcode)(unsafe.Pointer(fieldCode)) default:
} else {
code = valueCode.beforeLastCode() code = valueCode.beforeLastCode()
} }
} else { } else {
@ -213,21 +217,23 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) {
code.next = (*opcode)(unsafe.Pointer(fieldCode)) code.next = (*opcode)(unsafe.Pointer(fieldCode))
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode)) prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode prevField = fieldCode
if valueCode.op == opInt { switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldInt fieldCode.op = opStructFieldInt
code = (*opcode)(unsafe.Pointer(fieldCode)) code = (*opcode)(unsafe.Pointer(fieldCode))
} else if valueCode.op == opString { case opString:
fieldCode.op = opStructFieldString fieldCode.op = opStructFieldString
code = (*opcode)(unsafe.Pointer(fieldCode)) code = (*opcode)(unsafe.Pointer(fieldCode))
} else { default:
code = valueCode.beforeLastCode() code = valueCode.beforeLastCode()
} }
} }
prevField.nextField = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} prevField.nextField = newEndOp()
fieldIdx++ fieldIdx++
} }
structEndCode := &opcode{opcodeHeader: &opcodeHeader{op: opStructEnd}} structEndCode := newOpCode(opStructEnd, nil, nil)
head.end = structEndCode
code.next = structEndCode code.next = structEndCode
structEndCode.next = &opcode{opcodeHeader: &opcodeHeader{op: opEnd}} structEndCode.next = newEndOp()
return header, nil return (*opcode)(unsafe.Pointer(head)), nil
} }

View File

@ -27,15 +27,16 @@ const (
opBool opBool
opPtr opPtr
opSliceHead opSliceHead
opSliceElemFirst
opSliceElem opSliceElem
opSliceEnd opSliceEnd
opStructHead opStructFieldHead
opStructFieldFirst opStructFieldHeadInt
opStructFieldHeadString
opStructFieldPtrHead
opStructFieldPtrHeadInt
opStructFieldPtrHeadString
opStructField opStructField
opStructFieldFirstInt
opStructFieldInt opStructFieldInt
opStructFieldFirstString
opStructFieldString opStructFieldString
opStructEnd opStructEnd
) )
@ -76,24 +77,26 @@ func (t opType) String() string {
return "PTR" return "PTR"
case opSliceHead: case opSliceHead:
return "SLICE_HEAD" return "SLICE_HEAD"
case opSliceElemFirst:
return "SLICE_ELEM_FIRST"
case opSliceElem: case opSliceElem:
return "SLICE_ELEM" return "SLICE_ELEM"
case opSliceEnd: case opSliceEnd:
return "SLICE_END" return "SLICE_END"
case opStructHead: case opStructFieldHead:
return "STRUCT_HEAD" return "STRUCT_FIELD_HEAD"
case opStructFieldFirst: case opStructFieldHeadInt:
return "STRUCT_FIELD_FIRST" 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: case opStructField:
return "STRUCT_FIELD" return "STRUCT_FIELD"
case opStructFieldFirstInt:
return "STRUCT_FIELD_FIRST_INT"
case opStructFieldInt: case opStructFieldInt:
return "STRUCT_FIELD_INT" return "STRUCT_FIELD_INT"
case opStructFieldFirstString:
return "STRUCT_FIELD_FIRST_STRING"
case opStructFieldString: case opStructFieldString:
return "STRUCT_FIELD_STRING" return "STRUCT_FIELD_STRING"
case opStructEnd: case opStructEnd:
@ -157,18 +160,32 @@ func (c *opcode) dump() string {
return strings.Join(codes, "\n") return strings.Join(codes, "\n")
} }
func (c *opcode) toSliceHeaderCode() *sliceHeaderCode {
return (*sliceHeaderCode)(unsafe.Pointer(c))
}
func (c *opcode) toSliceElemCode() *sliceElemCode { func (c *opcode) toSliceElemCode() *sliceElemCode {
return (*sliceElemCode)(unsafe.Pointer(c)) return (*sliceElemCode)(unsafe.Pointer(c))
} }
func (c *opcode) toStructHeaderCode() *structHeaderCode {
return (*structHeaderCode)(unsafe.Pointer(c))
}
func (c *opcode) toStructFieldCode() *structFieldCode { func (c *opcode) toStructFieldCode() *structFieldCode {
return (*structFieldCode)(unsafe.Pointer(c)) 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 { type sliceElemCode struct {
*opcodeHeader *opcodeHeader
idx uintptr idx uintptr
@ -185,14 +202,10 @@ func (c *sliceElemCode) set(header *reflect.SliceHeader) {
c.data = header.Data c.data = header.Data
} }
type structHeaderCode struct {
*opcodeHeader
end *opcode
}
type structFieldCode struct { type structFieldCode struct {
*opcodeHeader *opcodeHeader
key string key string
offset uintptr offset uintptr
nextField *opcode nextField *opcode
end *opcode
} }

View File

@ -59,24 +59,22 @@ func (e *Encoder) run(code *opcode) error {
code = code.next code = code.next
case opSliceHead: case opSliceHead:
p := code.ptr p := code.ptr
headerCode := code.toSliceHeaderCode()
if p == 0 { if p == 0 {
e.encodeString("null") e.encodeString("null")
code = code.next.toSliceElemCode().end code = headerCode.end.next
} else { } else {
e.encodeByte('[') e.encodeByte('[')
header := (*reflect.SliceHeader)(unsafe.Pointer(p)) header := (*reflect.SliceHeader)(unsafe.Pointer(p))
firstElem := code.next.toSliceElemCode() headerCode := code.toSliceHeaderCode()
firstElem.set(header) headerCode.elem.set(header)
firstElem.elem.set(header) if header.Len > 0 {
code = code.next code = code.next
} code.ptr = header.Data
case opSliceElemFirst:
c := code.toSliceElemCode()
if c.len > 0 {
code = code.next
code.ptr = c.data
} else { } else {
code = c.end e.encodeByte(']')
code = headerCode.end.next
}
} }
case opSliceElem: case opSliceElem:
c := code.toSliceElemCode() c := code.toSliceElemCode()
@ -86,39 +84,57 @@ func (e *Encoder) run(code *opcode) error {
code = code.next code = code.next
code.ptr = c.data + c.idx*c.size code.ptr = c.data + c.idx*c.size
} else { } else {
code = c.end
}
case opSliceEnd:
e.encodeByte(']') e.encodeByte(']')
code = code.next code = c.end.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 { if ptr == 0 {
e.encodeString("null") e.encodeString("null")
code = code.toStructHeaderCode().end code = field.end
} else { } else {
e.encodeByte('{') e.encodeByte('{')
code = code.next e.encodeString(field.key)
code.ptr = ptr 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: case opStructField:
e.encodeByte(',') e.encodeByte(',')
c := code.toStructFieldCode() c := code.toStructFieldCode()