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

View File

@ -1774,11 +1774,11 @@ func TestCoverInt(t *testing.T) {
enc.SetIndent("", " ")
}
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)
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 {
return nil, err
}
encodeConvertHeadOnlyCode(code, isPtr)
if !code.indirect && isPtr {
code.indirect = true
}
encodeOptimizeStructEnd(code)
encodeLinkRecursiveCode(code)
return code, nil
@ -105,11 +107,13 @@ func encodeCompileHead(ctx *encodeCompileContext) (*opcode, error) {
} else if isPtr && typ.Implements(marshalJSONType) {
typ = orgType
}
code, err := encodeCompile(ctx.withType(typ))
code, err := encodeCompile(ctx.withType(typ), isPtr)
if err != nil {
return nil, err
}
encodeConvertHeadOnlyCode(code, isPtr)
if !code.indirect && isPtr {
code.indirect = true
}
encodeOptimizeStructEnd(code)
encodeLinkRecursiveCode(code)
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 {
switch {
case typ.Implements(marshalJSONType):
@ -263,7 +218,7 @@ func encodeImplementsMarshaler(typ *rtype) bool {
return false
}
func encodeCompile(ctx *encodeCompileContext) (*opcode, error) {
func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) {
typ := ctx.typ
switch {
case typ.Implements(marshalJSONType):
@ -289,7 +244,7 @@ func encodeCompile(ctx *encodeCompileContext) (*opcode, error) {
case reflect.Map:
return encodeCompileMap(ctx, true)
case reflect.Struct:
return encodeCompileStruct(ctx, false)
return encodeCompileStruct(ctx, isPtr)
case reflect.Interface:
return encodeCompileInterface(ctx)
case reflect.Int:
@ -371,7 +326,7 @@ func encodeCompilePtr(ctx *encodeCompileContext) (*opcode, error) {
ptrOpcodeIndex := ctx.opcodeIndex
ptrIndex := ctx.ptrIndex
ctx.incIndex()
code, err := encodeCompile(ctx.withType(ctx.typ.Elem()))
code, err := encodeCompile(ctx.withType(ctx.typ.Elem()), true)
if err != nil {
return nil, err
}
@ -642,7 +597,7 @@ func encodeCompileSlice(ctx *encodeCompileContext) (*opcode, error) {
header := newSliceHeaderCode(ctx)
ctx.incIndex()
code, err := encodeCompile(ctx.withType(ctx.typ.Elem()).incIndent())
code, err := encodeCompile(ctx.withType(ctx.typ.Elem()).incIndent(), false)
if err != nil {
return nil, err
}
@ -676,7 +631,7 @@ func encodeCompileArray(ctx *encodeCompileContext) (*opcode, error) {
header := newArrayHeaderCode(ctx, alen)
ctx.incIndex()
code, err := encodeCompile(ctx.withType(elem).incIndent())
code, err := encodeCompile(ctx.withType(elem).incIndent(), false)
if err != nil {
return nil, err
}
@ -734,7 +689,7 @@ func encodeCompileMap(ctx *encodeCompileContext, withLoad bool) (*opcode, error)
ctx.incIndex()
valueType := typ.Elem()
valueCode, err := encodeCompile(ctx.withType(valueType))
valueCode, err := encodeCompile(ctx.withType(valueType), false)
if err != nil {
return nil, err
}
@ -1227,6 +1182,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
// ^ |
// |__________|
fieldNum := typ.NumField()
indirect := ifaceIndir(typ)
fieldIdx := 0
var (
head *opcode
@ -1258,7 +1214,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
fieldOpcodeIndex := ctx.opcodeIndex
fieldPtrIndex := ctx.ptrIndex
ctx.incIndex()
valueCode, err := encodeCompile(ctx.withType(fieldType))
valueCode, err := encodeCompile(ctx.withType(fieldType), false)
if err != nil {
return nil, err
}
@ -1280,6 +1236,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
}
key := fmt.Sprintf(`"%s":`, tag.key)
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
valueCode.indirect = indirect
fieldCode := &opcode{
typ: valueCode.typ,
displayIdx: fieldOpcodeIndex,
@ -1292,6 +1249,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
isTaggedKey: tag.isTaggedKey,
displayKey: tag.key,
offset: field.Offset,
indirect: indirect,
}
if fieldIdx == 0 {
fieldCode.headIdx = fieldCode.idx

View File

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

View File

@ -1722,7 +1722,7 @@ func (t opType) headToPtrHead() opType {
}
suffix := "Ptr" + t.String()[idx+len("Field"):]
const toPtrOffset = 12
const toPtrOffset = 6
if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset)
}
@ -1743,7 +1743,7 @@ func (t opType) headToNPtrHead() opType {
}
suffix := "NPtr" + t.String()[idx+len("Field"):]
const toPtrOffset = 24
const toPtrOffset = 12
if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset)
}
@ -1751,7 +1751,7 @@ func (t opType) headToNPtrHead() opType {
}
func (t opType) headToAnonymousHead() opType {
const toAnonymousOffset = 6
const toAnonymousOffset = 3
if strings.Contains(opType(int(t)+toAnonymousOffset).String(), "Anonymous") {
return opType(int(t) + toAnonymousOffset)
}
@ -1759,7 +1759,7 @@ func (t opType) headToAnonymousHead() opType {
}
func (t opType) headToOmitEmptyHead() opType {
const toOmitEmptyOffset = 2
const toOmitEmptyOffset = 1
if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") {
return opType(int(t) + toOmitEmptyOffset)
}
@ -1768,7 +1768,7 @@ func (t opType) headToOmitEmptyHead() opType {
}
func (t opType) headToStringTagHead() opType {
const toStringTagOffset = 4
const toStringTagOffset = 2
if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") {
return opType(int(t) + toStringTagOffset)
}
@ -1782,7 +1782,7 @@ func (t opType) ptrHeadToHead() opType {
}
suffix := t.String()[idx+len("Ptr"):]
const toPtrOffset = 12
const toPtrOffset = 6
if strings.Contains(opType(int(t)-toPtrOffset).String(), suffix) {
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)
}
//go:linkname ifaceIndir reflect.ifaceIndir
//go:noescape
func ifaceIndir(*rtype) bool
//go:linkname rtype2type reflect.toType
//go:noescape
func rtype2type(t *rtype) reflect.Type