Add InterfaceEnd operation

This commit is contained in:
Masaaki Goshima 2020-09-03 15:36:11 +09:00
parent 4f4060f808
commit 34b662b98e
4 changed files with 846 additions and 782 deletions

View File

@ -220,6 +220,7 @@ func (t opType) fieldToStringTagField() opType {
opTypes := []opType{
{"End", "EndIndent", "Op"},
{"Interface", "InterfaceIndent", "Op"},
{"InterfaceEnd", "InterfaceEndIndent", "Op"},
{"Ptr", "PtrIndent", "Op"},
{"SliceHead", "SliceHeadIndent", "SliceHead"},
{"RootSliceHead", "RootSliceHeadIndent", "SliceHead"},
@ -252,6 +253,7 @@ func (t opType) fieldToStringTagField() opType {
{"StructFieldOmitEmpty", "StructFieldOmitEmptyIndent", "StructField"},
{"StructFieldStringTag", "StructFieldStringTagIndent", "StructField"},
{"StructFieldRecursive", "StructFieldRecursiveIndent", "StructFieldRecursive"},
{"StructFieldRecursiveEnd", "StructFieldRecursiveEndIndent", "Op"},
{"StructEnd", "StructEndIndent", "StructField"},
{"StructAnonymousEnd", "StructAnonymousEndIndent", "StructField"},
}

View File

@ -80,7 +80,10 @@ func (c *opcode) beforeLastCode() *opcode {
func (c *opcode) totalLength() int {
var idx int
for code := c; code.op != opEnd; {
idx = code.displayIdx
idx = int(code.idx / uintptrSize)
if code.op == opInterfaceEnd {
break
}
switch code.op.codeType() {
case codeArrayElem, codeSliceElem, codeMapKey:
code = code.end
@ -88,7 +91,7 @@ func (c *opcode) totalLength() int {
code = code.next
}
}
return idx + 1
return idx + 2 // opEnd + 1
}
func (c *opcode) decOpcodeIndex() {
@ -378,8 +381,8 @@ func newInterfaceCode(ctx *encodeCompileContext) *opcode {
displayIdx: ctx.opcodeIndex,
idx: opcodeOffset(ctx.ptrIndex),
indent: ctx.indent,
next: newEndOp(ctx),
root: ctx.root,
next: newEndOp(ctx),
}
}

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@ func store(base uintptr, idx uintptr, p uintptr) {
}
func (e *Encoder) run(ctx *encodeRuntimeContext, recursiveLevel int, seenPtr map[uintptr]struct{}, code *opcode) error {
ptrOffset := uintptr(0)
ctxptr := ctx.ptr()
for {
switch code.op {
@ -142,13 +143,43 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, recursiveLevel int, seenPtr map
}
c = code
}
ctx := &encodeRuntimeContext{
ptrs: make([]uintptr, c.totalLength()),
beforeLastCode := c.beforeLastCode()
lastCode := beforeLastCode.next
lastCode.idx = beforeLastCode.idx + uintptrSize
totalLength := uintptr(code.totalLength())
nextTotalLength := uintptr(c.totalLength())
curlen := uintptr(len(ctx.ptrs))
offsetNum := ptrOffset / uintptrSize
oldOffset := ptrOffset
ptrOffset = ptrOffset + totalLength*uintptrSize // curlen * uintptrSize
}
ctx.init(uintptr(header.ptr))
if err := e.run(ctx, recursiveLevel+1, seenPtr, c); err != nil {
return err
newLen := offsetNum + totalLength + nextTotalLength
if curlen < newLen {
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
store(ctx.ptr()+ptrOffset, 0, uintptr(header.ptr))
} else {
store(ctx.ptr()+ptrOffset, 0, uintptr(header.ptr))
}
ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr
if load(ctxptr, 0) != uintptr(header.ptr) {
panic(nil)
}
// save current ctxptr
store(ctxptr, lastCode.idx, oldOffset)
// link lastCode ( opInterfaceEnd ) => code.next
lastCode.op = opInterfaceEnd
lastCode.next = code.next
code = c
recursiveLevel++
case opInterfaceEnd:
recursiveLevel--
// restore ctxptr
offset := load(ctxptr, code.idx)
ctxptr = ctx.ptr() + offset
ptrOffset = offset
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)