Remove only operation and add indirect property to opcode

This commit is contained in:
Masaaki Goshima 2021-02-28 23:22:46 +09:00
parent 40cc5ff367
commit c6f40ed546
10 changed files with 456 additions and 5193 deletions

View File

@ -163,7 +163,7 @@ func (t opType) headToPtrHead() opType {
} }
suffix := "Ptr"+t.String()[idx+len("Field"):] suffix := "Ptr"+t.String()[idx+len("Field"):]
const toPtrOffset = 12 const toPtrOffset = 6
if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset) return opType(int(t) + toPtrOffset)
} }
@ -184,7 +184,7 @@ func (t opType) headToNPtrHead() opType {
} }
suffix := "NPtr"+t.String()[idx+len("Field"):] suffix := "NPtr"+t.String()[idx+len("Field"):]
const toPtrOffset = 24 const toPtrOffset = 12
if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset) return opType(int(t) + toPtrOffset)
} }
@ -192,7 +192,7 @@ func (t opType) headToNPtrHead() opType {
} }
func (t opType) headToAnonymousHead() opType { func (t opType) headToAnonymousHead() opType {
const toAnonymousOffset = 6 const toAnonymousOffset = 3
if strings.Contains(opType(int(t) + toAnonymousOffset).String(), "Anonymous") { if strings.Contains(opType(int(t) + toAnonymousOffset).String(), "Anonymous") {
return opType(int(t) + toAnonymousOffset) return opType(int(t) + toAnonymousOffset)
} }
@ -200,7 +200,7 @@ func (t opType) headToAnonymousHead() opType {
} }
func (t opType) headToOmitEmptyHead() opType { func (t opType) headToOmitEmptyHead() opType {
const toOmitEmptyOffset = 2 const toOmitEmptyOffset = 1
if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
return opType(int(t) + toOmitEmptyOffset) return opType(int(t) + toOmitEmptyOffset)
} }
@ -209,7 +209,7 @@ func (t opType) headToOmitEmptyHead() opType {
} }
func (t opType) headToStringTagHead() opType { func (t opType) headToStringTagHead() opType {
const toStringTagOffset = 4 const toStringTagOffset = 2
if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") { if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") {
return opType(int(t) + toStringTagOffset) return opType(int(t) + toStringTagOffset)
} }
@ -223,7 +223,7 @@ func (t opType) ptrHeadToHead() opType {
} }
suffix := t.String()[idx+len("Ptr"):] suffix := t.String()[idx+len("Ptr"):]
const toPtrOffset = 12 const toPtrOffset = 6
if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) {
return opType(int(t) - toPtrOffset) return opType(int(t) - toPtrOffset)
} }

View File

@ -1774,11 +1774,11 @@ func TestCoverInt(t *testing.T) {
enc.SetIndent("", " ") enc.SetIndent("", " ")
} }
if err := enc.Encode(test.data); err != nil { if err := enc.Encode(test.data); err != nil {
t.Fatalf("%s(htmlEscape:%T): %+v: %s", test.name, htmlEscape, test.data, err) t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err)
} }
stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape) stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape)
if buf.String() != stdresult { if buf.String() != stdresult {
t.Errorf("%s(htmlEscape:%T): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, stdresult, buf.String()) t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String())
} }
} }
} }

View File

@ -96,7 +96,9 @@ func encodeCompileHead(ctx *encodeCompileContext) (*opcode, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
encodeConvertHeadOnlyCode(code, isPtr) if !code.indirect && isPtr {
code.indirect = true
}
encodeOptimizeStructEnd(code) encodeOptimizeStructEnd(code)
encodeLinkRecursiveCode(code) encodeLinkRecursiveCode(code)
return code, nil return code, nil
@ -105,11 +107,13 @@ func encodeCompileHead(ctx *encodeCompileContext) (*opcode, error) {
} else if isPtr && typ.Implements(marshalJSONType) { } else if isPtr && typ.Implements(marshalJSONType) {
typ = orgType typ = orgType
} }
code, err := encodeCompile(ctx.withType(typ)) code, err := encodeCompile(ctx.withType(typ), isPtr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
encodeConvertHeadOnlyCode(code, isPtr) if !code.indirect && isPtr {
code.indirect = true
}
encodeOptimizeStructEnd(code) encodeOptimizeStructEnd(code)
encodeLinkRecursiveCode(code) encodeLinkRecursiveCode(code)
return code, nil return code, nil
@ -200,55 +204,6 @@ func encodeOptimizeStructEnd(c *opcode) {
} }
} }
func encodeConvertHeadOnlyCode(c *opcode, isPtrHead bool) {
if c.nextField == nil {
return
}
if c.nextField.op.codeType() != codeStructEnd {
return
}
switch c.op {
case opStructFieldHead:
encodeConvertHeadOnlyCode(c.next, false)
if !strings.Contains(c.next.op.String(), "Only") {
return
}
c.op = opStructFieldHeadOnly
case opStructFieldHeadOmitEmpty:
encodeConvertHeadOnlyCode(c.next, false)
if !strings.Contains(c.next.op.String(), "Only") {
return
}
c.op = opStructFieldHeadOmitEmptyOnly
case opStructFieldHeadStringTag:
encodeConvertHeadOnlyCode(c.next, false)
if !strings.Contains(c.next.op.String(), "Only") {
return
}
c.op = opStructFieldHeadStringTagOnly
case opStructFieldPtrHead:
}
if strings.Contains(c.op.String(), "Marshal") {
return
}
if strings.Contains(c.op.String(), "Slice") {
return
}
if strings.Contains(c.op.String(), "Map") {
return
}
isPtrOp := strings.Contains(c.op.String(), "Ptr")
if isPtrOp && !isPtrHead {
c.op = c.op.headToOnlyHead()
} else if !isPtrOp && isPtrHead {
c.op = c.op.headToPtrHead().headToOnlyHead()
} else if isPtrOp && isPtrHead {
c.op = c.op.headToPtrHead().headToOnlyHead()
}
}
func encodeImplementsMarshaler(typ *rtype) bool { func encodeImplementsMarshaler(typ *rtype) bool {
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
@ -263,7 +218,7 @@ func encodeImplementsMarshaler(typ *rtype) bool {
return false return false
} }
func encodeCompile(ctx *encodeCompileContext) (*opcode, error) { func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) {
typ := ctx.typ typ := ctx.typ
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
@ -289,7 +244,7 @@ func encodeCompile(ctx *encodeCompileContext) (*opcode, error) {
case reflect.Map: case reflect.Map:
return encodeCompileMap(ctx, true) return encodeCompileMap(ctx, true)
case reflect.Struct: case reflect.Struct:
return encodeCompileStruct(ctx, false) return encodeCompileStruct(ctx, isPtr)
case reflect.Interface: case reflect.Interface:
return encodeCompileInterface(ctx) return encodeCompileInterface(ctx)
case reflect.Int: case reflect.Int:
@ -371,7 +326,7 @@ func encodeCompilePtr(ctx *encodeCompileContext) (*opcode, error) {
ptrOpcodeIndex := ctx.opcodeIndex ptrOpcodeIndex := ctx.opcodeIndex
ptrIndex := ctx.ptrIndex ptrIndex := ctx.ptrIndex
ctx.incIndex() ctx.incIndex()
code, err := encodeCompile(ctx.withType(ctx.typ.Elem())) code, err := encodeCompile(ctx.withType(ctx.typ.Elem()), true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -642,7 +597,7 @@ func encodeCompileSlice(ctx *encodeCompileContext) (*opcode, error) {
header := newSliceHeaderCode(ctx) header := newSliceHeaderCode(ctx)
ctx.incIndex() ctx.incIndex()
code, err := encodeCompile(ctx.withType(ctx.typ.Elem()).incIndent()) code, err := encodeCompile(ctx.withType(ctx.typ.Elem()).incIndent(), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -676,7 +631,7 @@ func encodeCompileArray(ctx *encodeCompileContext) (*opcode, error) {
header := newArrayHeaderCode(ctx, alen) header := newArrayHeaderCode(ctx, alen)
ctx.incIndex() ctx.incIndex()
code, err := encodeCompile(ctx.withType(elem).incIndent()) code, err := encodeCompile(ctx.withType(elem).incIndent(), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -734,7 +689,7 @@ func encodeCompileMap(ctx *encodeCompileContext, withLoad bool) (*opcode, error)
ctx.incIndex() ctx.incIndex()
valueType := typ.Elem() valueType := typ.Elem()
valueCode, err := encodeCompile(ctx.withType(valueType)) valueCode, err := encodeCompile(ctx.withType(valueType), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1227,6 +1182,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
// ^ | // ^ |
// |__________| // |__________|
fieldNum := typ.NumField() fieldNum := typ.NumField()
indirect := ifaceIndir(typ)
fieldIdx := 0 fieldIdx := 0
var ( var (
head *opcode head *opcode
@ -1258,7 +1214,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
fieldOpcodeIndex := ctx.opcodeIndex fieldOpcodeIndex := ctx.opcodeIndex
fieldPtrIndex := ctx.ptrIndex fieldPtrIndex := ctx.ptrIndex
ctx.incIndex() ctx.incIndex()
valueCode, err := encodeCompile(ctx.withType(fieldType)) valueCode, err := encodeCompile(ctx.withType(fieldType), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1280,6 +1236,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
} }
key := fmt.Sprintf(`"%s":`, tag.key) key := fmt.Sprintf(`"%s":`, tag.key)
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key))) escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
valueCode.indirect = indirect
fieldCode := &opcode{ fieldCode := &opcode{
typ: valueCode.typ, typ: valueCode.typ,
displayIdx: fieldOpcodeIndex, displayIdx: fieldOpcodeIndex,
@ -1292,6 +1249,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
isTaggedKey: tag.isTaggedKey, isTaggedKey: tag.isTaggedKey,
displayKey: tag.key, displayKey: tag.key,
offset: field.Offset, offset: field.Offset,
indirect: indirect,
} }
if fieldIdx == 0 { if fieldIdx == 0 {
fieldCode.headIdx = fieldCode.idx fieldCode.headIdx = fieldCode.idx

View File

@ -19,11 +19,10 @@ type opcode struct {
isTaggedKey bool // whether tagged key isTaggedKey bool // whether tagged key
anonymousKey bool // whether anonymous key anonymousKey bool // whether anonymous key
root bool // whether root root bool // whether root
indirect bool // whether indirect or not
rshiftNum uint8 // use to take bit for judging whether negative integer or not rshiftNum uint8 // use to take bit for judging whether negative integer or not
mask uint64 // mask for number mask uint64 // mask for number
indent int // indent number indent int // indent number
rshiftNum uint8 // use to take bit for judging whether negative integer or not
mask uint64 // mask for number
idx uintptr // offset to access ptr idx uintptr // offset to access ptr
headIdx uintptr // offset to access slice/struct head headIdx uintptr // offset to access slice/struct head
@ -93,6 +92,7 @@ func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
isTaggedKey: c.isTaggedKey, isTaggedKey: c.isTaggedKey,
anonymousKey: c.anonymousKey, anonymousKey: c.anonymousKey,
root: c.root, root: c.root,
indirect: c.indirect,
indent: c.indent, indent: c.indent,
idx: c.idx, idx: c.idx,
headIdx: c.headIdx, headIdx: c.headIdx,

View File

@ -1722,7 +1722,7 @@ func (t opType) headToPtrHead() opType {
} }
suffix := "Ptr" + t.String()[idx+len("Field"):] suffix := "Ptr" + t.String()[idx+len("Field"):]
const toPtrOffset = 12 const toPtrOffset = 6
if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset) return opType(int(t) + toPtrOffset)
} }
@ -1743,7 +1743,7 @@ func (t opType) headToNPtrHead() opType {
} }
suffix := "NPtr" + t.String()[idx+len("Field"):] suffix := "NPtr" + t.String()[idx+len("Field"):]
const toPtrOffset = 24 const toPtrOffset = 12
if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset) return opType(int(t) + toPtrOffset)
} }
@ -1751,7 +1751,7 @@ func (t opType) headToNPtrHead() opType {
} }
func (t opType) headToAnonymousHead() opType { func (t opType) headToAnonymousHead() opType {
const toAnonymousOffset = 6 const toAnonymousOffset = 3
if strings.Contains(opType(int(t)+toAnonymousOffset).String(), "Anonymous") { if strings.Contains(opType(int(t)+toAnonymousOffset).String(), "Anonymous") {
return opType(int(t) + toAnonymousOffset) return opType(int(t) + toAnonymousOffset)
} }
@ -1759,7 +1759,7 @@ func (t opType) headToAnonymousHead() opType {
} }
func (t opType) headToOmitEmptyHead() opType { func (t opType) headToOmitEmptyHead() opType {
const toOmitEmptyOffset = 2 const toOmitEmptyOffset = 1
if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") {
return opType(int(t) + toOmitEmptyOffset) return opType(int(t) + toOmitEmptyOffset)
} }
@ -1768,7 +1768,7 @@ func (t opType) headToOmitEmptyHead() opType {
} }
func (t opType) headToStringTagHead() opType { func (t opType) headToStringTagHead() opType {
const toStringTagOffset = 4 const toStringTagOffset = 2
if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") { if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") {
return opType(int(t) + toStringTagOffset) return opType(int(t) + toStringTagOffset)
} }
@ -1782,7 +1782,7 @@ func (t opType) ptrHeadToHead() opType {
} }
suffix := t.String()[idx+len("Ptr"):] suffix := t.String()[idx+len("Ptr"):]
const toPtrOffset = 12 const toPtrOffset = 6
if strings.Contains(opType(int(t)-toPtrOffset).String(), suffix) { if strings.Contains(opType(int(t)-toPtrOffset).String(), suffix) {
return opType(int(t) - toPtrOffset) return opType(int(t) - toPtrOffset)
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -244,6 +244,10 @@ func (t *rtype) Out(i int) reflect.Type {
return rtype_Out(t, i) return rtype_Out(t, i)
} }
//go:linkname ifaceIndir reflect.ifaceIndir
//go:noescape
func ifaceIndir(*rtype) bool
//go:linkname rtype2type reflect.toType //go:linkname rtype2type reflect.toType
//go:noescape //go:noescape
func rtype2type(t *rtype) reflect.Type func rtype2type(t *rtype) reflect.Type