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) {
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
}

View File

@ -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
}

View File

@ -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()