mirror of https://github.com/goccy/go-json.git
Optimize opcode
This commit is contained in:
parent
4f3b1262b2
commit
40544f1ea2
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
96
encode_vm.go
96
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()
|
||||
|
|
Loading…
Reference in New Issue