Compare commits

...

3 Commits

Author SHA1 Message Date
Masaaki Goshima 8ec9df385c Add optimizer 2020-11-15 02:49:38 +09:00
Masaaki Goshima 4855599414 WIP 2020-11-15 02:49:16 +09:00
Masaaki Goshima 1d14ceb03e Fix optimizer 2020-11-14 22:38:16 +09:00
5 changed files with 5830 additions and 4331 deletions

View File

@ -26,16 +26,11 @@ type headType struct {
OmitEmptyPtrHead string
AnonymousOmitEmptyHead string
AnonymousOmitEmptyPtrHead string
StringTagHead string
StringTagPtrHead string
AnonymousStringTagHead string
AnonymousStringTagPtrHead string
}
type fieldType struct {
Field string
OmitEmptyField string
StringTagField string
}
func _main() error {
@ -88,6 +83,46 @@ func (t opType) toIndent() opType {
return t
}
func (t opType) toString() opType {
switch t {
case opInt:
return opIntString
case opInt8:
return opInt8String
case opInt16:
return opInt16String
case opInt32:
return opInt32String
case opInt64:
return opInt64String
case opUint:
return opUintString
case opUint8:
return opUint8String
case opUint16:
return opUint16String
case opUint32:
return opUint32String
case opUint64:
return opUint64String
case opFloat32:
return opFloat32String
case opFloat64:
return opFloat64String
case opBool:
return opBoolString
case opString:
return opStringString
case opBytes:
return opBytesString
case opMarshalJSON:
return opMarshalJSONString
case opMarshalText:
return opMarshalTextString
}
return t
}
func (t opType) headToPtrHead() opType {
switch t {
{{- range $type := .HeadTypes }}
@ -99,10 +134,6 @@ func (t opType) headToPtrHead() opType {
return op{{ $type.OmitEmptyPtrHead }}
case op{{ $type.AnonymousOmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.StringTagPtrHead }}
case op{{ $type.AnonymousStringTagHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- end }}
}
return t
@ -119,10 +150,6 @@ func (t opType) headToAnonymousHead() opType {
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.OmitEmptyPtrHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.AnonymousStringTagHead }}
case op{{ $type.StringTagPtrHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- end }}
}
return t
@ -140,18 +167,6 @@ func (t opType) headToOmitEmptyHead() opType {
return t
}
func (t opType) headToStringTagHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.StringTagHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.StringTagPtrHead }}
{{- end }}
}
return t
}
func (t opType) ptrHeadToHead() opType {
switch t {
{{- range $type := .HeadTypes }}
@ -163,10 +178,6 @@ func (t opType) ptrHeadToHead() opType {
return op{{ $type.OmitEmptyHead }}
case op{{ $type.AnonymousOmitEmptyPtrHead }}:
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.StringTagPtrHead }}:
return op{{ $type.StringTagHead }}
case op{{ $type.AnonymousStringTagPtrHead }}:
return op{{ $type.AnonymousStringTagHead }}
{{- end }}
}
return t
@ -182,16 +193,6 @@ func (t opType) fieldToOmitEmptyField() opType {
return t
}
func (t opType) fieldToStringTagField() opType {
switch t {
{{- range $type := .FieldTypes }}
case op{{ $type.Field }}:
return op{{ $type.StringTagField }}
{{- end }}
}
return t
}
`)
if err != nil {
return err
@ -215,6 +216,14 @@ func (t opType) fieldToStringTagField() opType {
"float32", "float64", "bool", "string", "bytes",
"array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText",
}
// primitiveStringTypes primitive types for StringTag
primitiveStringTypes := []string{}
for _, typ := range primitiveTypes {
primitiveStringTypes = append(primitiveStringTypes, fmt.Sprintf("%sString", typ))
}
primitiveTypes = append(primitiveTypes, primitiveStringTypes...)
primitiveTypesUpper := []string{}
for _, typ := range primitiveTypes {
primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:])
@ -239,19 +248,15 @@ func (t opType) fieldToStringTagField() opType {
{"MapEnd", "MapEndIndent", "Op"},
{"StructFieldHead", "StructFieldHeadIndent", "StructField"},
{"StructFieldHeadOmitEmpty", "StructFieldHeadOmitEmptyIndent", "StructField"},
{"StructFieldHeadStringTag", "StructFieldHeadStringTagIndent", "StructField"},
{"StructFieldAnonymousHead", "StructFieldAnonymousHeadIndent", "StructField"},
{"StructFieldAnonymousSkipHead", "StructFieldAnonymousSkipHeadIndent", "StructField"},
{"StructFieldAnonymousHeadOmitEmpty", "StructFieldAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrAnonymousHeadOmitEmpty", "StructFieldPtrAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldAnonymousHeadStringTag", "StructFieldAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHeadStringTag", "StructFieldPtrAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrHead", "StructFieldPtrHeadIndent", "StructField"},
{"StructFieldPtrHeadOmitEmpty", "StructFieldPtrHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrHeadStringTag", "StructFieldPtrHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHead", "StructFieldPtrAnonymousHeadIndent", "StructField"},
{"StructField", "StructFieldIndent", "StructField"},
{"StructFieldOmitEmpty", "StructFieldOmitEmptyIndent", "StructField"},
{"StructFieldStringTag", "StructFieldStringTagIndent", "StructField"},
{"StructFieldRecursive", "StructFieldRecursiveIndent", "StructFieldRecursive"},
{"StructFieldRecursiveEnd", "StructFieldRecursiveEndIndent", "Op"},
{"StructEnd", "StructEndIndent", "StructField"},
@ -267,20 +272,15 @@ func (t opType) fieldToStringTagField() opType {
for _, prefix := range []string{
"StructFieldHead",
"StructFieldHeadOmitEmpty",
"StructFieldHeadStringTag",
"StructFieldAnonymousHead",
"StructFieldAnonymousHeadOmitEmpty",
"StructFieldAnonymousHeadStringTag",
"StructFieldPtrHead",
"StructFieldPtrHeadOmitEmpty",
"StructFieldPtrHeadStringTag",
"StructFieldPtrAnonymousHead",
"StructFieldPtrAnonymousHeadOmitEmpty",
"StructFieldPtrAnonymousHeadStringTag",
"StructField",
"StructFieldPtr",
"StructFieldOmitEmpty",
"StructFieldStringTag",
} {
for _, typ := range primitiveTypesUpper {
opTypes = append(opTypes, opType{
@ -304,12 +304,8 @@ func (t opType) fieldToStringTagField() opType {
AnonymousPtrHead: "StructFieldPtrAnonymousHead",
OmitEmptyHead: "StructFieldHeadOmitEmpty",
OmitEmptyPtrHead: "StructFieldPtrHeadOmitEmpty",
StringTagHead: "StructFieldHeadStringTag",
StringTagPtrHead: "StructFieldPtrHeadStringTag",
AnonymousOmitEmptyHead: "StructFieldAnonymousHeadOmitEmpty",
AnonymousOmitEmptyPtrHead: "StructFieldPtrAnonymousHeadOmitEmpty",
AnonymousStringTagHead: "StructFieldAnonymousHeadStringTag",
AnonymousStringTagPtrHead: "StructFieldPtrAnonymousHeadStringTag",
}
headTypes := []headType{base}
for _, prim := range primitiveTypesUpper {
@ -322,10 +318,6 @@ func (t opType) fieldToStringTagField() opType {
OmitEmptyPtrHead: fmt.Sprintf("%s%s", base.OmitEmptyPtrHead, prim),
AnonymousOmitEmptyHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyHead, prim),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyPtrHead, prim),
StringTagHead: fmt.Sprintf("%s%s", base.StringTagHead, prim),
StringTagPtrHead: fmt.Sprintf("%s%s", base.StringTagPtrHead, prim),
AnonymousStringTagHead: fmt.Sprintf("%s%s", base.AnonymousStringTagHead, prim),
AnonymousStringTagPtrHead: fmt.Sprintf("%s%s", base.AnonymousStringTagPtrHead, prim),
})
}
for _, typ := range headTypes {
@ -338,31 +330,24 @@ func (t opType) fieldToStringTagField() opType {
OmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.OmitEmptyPtrHead),
AnonymousOmitEmptyHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyHead),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyPtrHead),
StringTagHead: fmt.Sprintf("%sIndent", typ.StringTagHead),
StringTagPtrHead: fmt.Sprintf("%sIndent", typ.StringTagPtrHead),
AnonymousStringTagHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagHead),
AnonymousStringTagPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagPtrHead),
})
}
baseField := fieldType{
Field: "StructField",
OmitEmptyField: "StructFieldOmitEmpty",
StringTagField: "StructFieldStringTag",
}
fieldTypes := []fieldType{baseField}
for _, prim := range primitiveTypesUpper {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%s%s", baseField.Field, prim),
OmitEmptyField: fmt.Sprintf("%s%s", baseField.OmitEmptyField, prim),
StringTagField: fmt.Sprintf("%s%s", baseField.StringTagField, prim),
})
}
for _, typ := range fieldTypes {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%sIndent", typ.Field),
OmitEmptyField: fmt.Sprintf("%sIndent", typ.OmitEmptyField),
StringTagField: fmt.Sprintf("%sIndent", typ.StringTagField),
})
}

View File

@ -139,13 +139,15 @@ func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
if err != nil {
return nil, err
}
ptrHeadOp := code.op.headToPtrHead()
if code.op != ptrHeadOp {
code.op = ptrHeadOp
code.decOpcodeIndex()
ctx.decIndex()
return code, nil
}
/*
ptrHeadOp := code.op.headToPtrHead()
if code.op != ptrHeadOp {
code.op = ptrHeadOp
code.decOpcodeIndex()
ctx.decIndex()
return code, nil
}
*/
c := ctx.context()
c.opcodeIndex = ptrOpcodeIndex
return newOpCodeWithNext(c, opPtr, code), nil
@ -571,12 +573,10 @@ func (e *Encoder) typeToFieldType(code *opcode) opType {
}
func (e *Encoder) optimizeStructHeader(op opType, tag *structTag, withIndent bool) opType {
headType := e.typeToHeaderType(op)
headType := opStructFieldHead // e.typeToHeaderType(op)
switch {
case tag.isOmitEmpty:
headType = headType.headToOmitEmptyHead()
case tag.isString:
headType = headType.headToStringTagHead()
}
if withIndent {
return headType.toIndent()
@ -585,12 +585,10 @@ func (e *Encoder) optimizeStructHeader(op opType, tag *structTag, withIndent boo
}
func (e *Encoder) optimizeStructField(code *opcode, tag *structTag, withIndent bool) opType {
fieldType := e.typeToFieldType(code)
fieldType := opStructField // e.typeToFieldType(code)
switch {
case tag.isOmitEmpty:
fieldType = fieldType.fieldToOmitEmptyField()
case tag.isString:
fieldType = fieldType.fieldToStringTagField()
}
if withIndent {
return fieldType.toIndent()
@ -636,7 +634,6 @@ func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, val
opStructFieldHeadOmitEmptyMap,
opStructFieldHeadOmitEmptyMapLoad,
opStructFieldHeadOmitEmptyStruct,
opStructFieldHeadStringTag,
opStructFieldHeadIndent,
opStructFieldHeadSliceIndent,
opStructFieldHeadArrayIndent,
@ -648,8 +645,7 @@ func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, val
opStructFieldHeadOmitEmptyArrayIndent,
opStructFieldHeadOmitEmptyMapIndent,
opStructFieldHeadOmitEmptyMapLoadIndent,
opStructFieldHeadOmitEmptyStructIndent,
opStructFieldHeadStringTagIndent:
opStructFieldHeadOmitEmptyStructIndent:
return valueCode.beforeLastCode()
}
ctx.decOpcodeIndex()
@ -673,7 +669,6 @@ func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valu
opStructFieldOmitEmptyMap,
opStructFieldOmitEmptyMapLoad,
opStructFieldOmitEmptyStruct,
opStructFieldStringTag,
opStructFieldIndent,
opStructFieldSliceIndent,
opStructFieldArrayIndent,
@ -685,8 +680,7 @@ func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valu
opStructFieldOmitEmptyArrayIndent,
opStructFieldOmitEmptyMapIndent,
opStructFieldOmitEmptyMapLoadIndent,
opStructFieldOmitEmptyStructIndent,
opStructFieldStringTagIndent:
opStructFieldOmitEmptyStructIndent:
return valueCode.beforeLastCode()
}
ctx.decIndex()
@ -751,16 +745,26 @@ type structFieldPair struct {
linked bool
}
func (e *Encoder) isAnonymousStructType(code *opcode) bool {
if code.op == opPtr {
code = code.next
}
return code.op.codeType() == codeStructField
}
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *opcode) map[string][]structFieldPair {
anonymousFields := map[string][]structFieldPair{}
f := valueCode
if f.op == opPtr {
f = f.next
}
var prevAnonymousField *opcode
for {
existsKey := tags.existsKey(f.displayKey)
op := f.op.headToAnonymousHead()
existsKey := tags.existsKey(f.displayKey)
if op != f.op {
if existsKey {
f.op = opStructFieldAnonymousHead
f.op = opStructFieldAnonymousSkipHead
} else {
f.op = op
}
@ -773,7 +777,6 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
}
linkPrevToNextField(prevAnonymousField, f)
}
if f.displayKey == "" {
if f.nextField == nil {
break
@ -802,7 +805,7 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
return anonymousFields
}
func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) {
func (e *Encoder) removeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) {
for _, fieldPairs := range anonymousFields {
if len(fieldPairs) == 1 {
continue
@ -816,7 +819,7 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
if !fieldPair.linked {
if fieldPair.prevField == nil {
// head operation
fieldPair.curField.op = opStructFieldAnonymousHead
fieldPair.curField.op = opStructFieldAnonymousSkipHead
} else {
diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
for i := 0; i < diff; i++ {
@ -833,7 +836,7 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
if !fieldPair.linked {
if fieldPair.prevField == nil {
// head operation
fieldPair.curField.op = opStructFieldAnonymousHead
fieldPair.curField.op = opStructFieldAnonymousSkipHead
} else {
diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
for i := 0; i < diff; i++ {
@ -934,13 +937,16 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
idx: opcodeOffset(fieldPtrIndex),
next: valueCode,
indent: ctx.indent,
anonymousKey: field.Anonymous,
anonymousKey: e.isAnonymousStructType(valueCode) && field.Anonymous,
key: []byte(key),
escapedKey: []byte(escapedKey),
isTaggedKey: tag.isTaggedKey,
displayKey: tag.key,
offset: field.Offset,
}
if tag.isString {
valueCode.op = valueCode.op.toString()
}
if fieldIdx == 0 {
fieldCode.headIdx = fieldCode.idx
code = e.structHeader(ctx, fieldCode, valueCode, tag)
@ -997,8 +1003,8 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
head.end = structEndCode
code.next = structEndCode
e.optimizeConflictAnonymousFields(anonymousFields)
e.optimizeAnonymousFields(head)
e.removeConflictAnonymousFields(anonymousFields)
//e.optimizeAnonymousFields(head)
ret := (*opcode)(unsafe.Pointer(head))
compiled.code = ret

51
encode_optimizer.go Normal file
View File

@ -0,0 +1,51 @@
package json
import "fmt"
type encodeOptimizerPlugin interface {
optimize(*opcode) (*opcode, error)
}
type encodeOptimizer struct {
optimizers []encodeOptimizerPlugin
}
func newEncodeOptimizer() *encodeOptimizer {
return &encodeOptimizer{}
}
func (o *encodeOptimizer) addOptimizer(plg encodeOptimizerPlugin) {
o.optimizers = append(o.optimizers, plg)
}
func (o *encodeOptimizer) optimize(code *opcode) (*opcode, error) {
for _, optimizer := range o.optimizers {
c, err := optimizer.optimize(code)
if err != nil {
return nil, err
}
code = c
}
return code, nil
}
type encodeStructHeadOptimizer struct {
}
func (o *encodeStructHeadOptimizer) optimize(code *opcode) (*opcode, error) {
head := code
for code.op != opEnd {
if code.op == opStructFieldHead {
fmt.Println("StructHead")
}
switch code.op.codeType() {
case codeArrayElem, codeSliceElem:
code = code.end
case codeMapKey:
code = code.end
default:
code = code.next
}
}
return head, nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff