mirror of https://github.com/goccy/go-json.git
632 lines
14 KiB
Go
632 lines
14 KiB
Go
package json
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
func copyOpcode(code *opcode) *opcode {
|
|
codeMap := map[uintptr]*opcode{}
|
|
return code.copy(codeMap)
|
|
}
|
|
|
|
type opcodeHeader struct {
|
|
op opType
|
|
typ *rtype
|
|
displayIdx int
|
|
idx uintptr
|
|
indent int
|
|
next *opcode
|
|
}
|
|
|
|
func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader {
|
|
return &opcodeHeader{
|
|
op: h.op,
|
|
typ: h.typ,
|
|
displayIdx: h.displayIdx,
|
|
idx: h.idx,
|
|
indent: h.indent,
|
|
next: h.next.copy(codeMap),
|
|
}
|
|
}
|
|
|
|
type opcode struct {
|
|
*opcodeHeader
|
|
}
|
|
|
|
func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
|
|
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
|
}
|
|
|
|
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
|
|
return &opcode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: op,
|
|
typ: ctx.typ,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
next: next,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newEndOp(ctx *encodeCompileContext) *opcode {
|
|
return newOpCodeWithNext(ctx, opEnd, nil)
|
|
}
|
|
|
|
func (c *opcode) beforeLastCode() *opcode {
|
|
code := c
|
|
for {
|
|
var nextCode *opcode
|
|
switch code.op.codeType() {
|
|
case codeArrayElem:
|
|
nextCode = code.toArrayElemCode().end
|
|
case codeSliceElem:
|
|
nextCode = code.toSliceElemCode().end
|
|
case codeMapKey:
|
|
nextCode = code.toMapKeyCode().end
|
|
default:
|
|
nextCode = code.next
|
|
}
|
|
if nextCode.op == opEnd {
|
|
return code
|
|
}
|
|
code = nextCode
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *opcode) length() int {
|
|
var idx int
|
|
for code := c; code.op != opEnd; {
|
|
idx = code.displayIdx
|
|
switch code.op.codeType() {
|
|
case codeArrayElem:
|
|
code = code.toArrayElemCode().end
|
|
case codeSliceElem:
|
|
code = code.toSliceElemCode().end
|
|
case codeMapKey:
|
|
code = code.toMapKeyCode().end
|
|
default:
|
|
code = code.next
|
|
}
|
|
}
|
|
return idx + 1
|
|
}
|
|
|
|
func (c *opcode) decOpcodeIndex() {
|
|
for code := c; code.op != opEnd; {
|
|
code.displayIdx--
|
|
code.idx -= 8
|
|
switch code.op.codeType() {
|
|
case codeArrayElem:
|
|
code = code.toArrayElemCode().end
|
|
case codeSliceElem:
|
|
code = code.toSliceElemCode().end
|
|
case codeMapKey:
|
|
code = code.toMapKeyCode().end
|
|
default:
|
|
code = code.next
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
var code *opcode
|
|
switch c.op.codeType() {
|
|
case codeArrayHead:
|
|
code = c.toArrayHeaderCode().copy(codeMap)
|
|
case codeArrayElem:
|
|
code = c.toArrayElemCode().copy(codeMap)
|
|
case codeSliceHead:
|
|
code = c.toSliceHeaderCode().copy(codeMap)
|
|
case codeSliceElem:
|
|
code = c.toSliceElemCode().copy(codeMap)
|
|
case codeMapHead:
|
|
code = c.toMapHeadCode().copy(codeMap)
|
|
case codeMapKey:
|
|
code = c.toMapKeyCode().copy(codeMap)
|
|
case codeMapValue:
|
|
code = c.toMapValueCode().copy(codeMap)
|
|
case codeStructFieldRecursive:
|
|
code = c.toRecursiveCode().copy(codeMap)
|
|
case codeStructField:
|
|
code = c.toStructFieldCode().copy(codeMap)
|
|
default:
|
|
code = &opcode{}
|
|
codeMap[addr] = code
|
|
|
|
code.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
}
|
|
return code
|
|
}
|
|
|
|
func (c *opcode) dump() string {
|
|
codes := []string{}
|
|
for code := c; code.op != opEnd; {
|
|
indent := strings.Repeat(" ", code.indent)
|
|
switch code.op.codeType() {
|
|
case codeArrayElem:
|
|
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
|
|
code = code.toArrayElemCode().end
|
|
case codeSliceElem:
|
|
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
|
|
code = code.toSliceElemCode().end
|
|
case codeMapKey:
|
|
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
|
|
code = code.toMapKeyCode().end
|
|
case codeStructField:
|
|
sf := code.toStructFieldCode()
|
|
key := sf.displayKey
|
|
offset := sf.offset
|
|
codes = append(codes, fmt.Sprintf("[%d]%s%s [%s:%d] ( %p )", code.displayIdx, indent, code.op, key, offset, unsafe.Pointer(code)))
|
|
code = code.next
|
|
default:
|
|
codes = append(codes, fmt.Sprintf("[%d]%s%s ( %p )", code.displayIdx, indent, code.op, unsafe.Pointer(code)))
|
|
code = code.next
|
|
}
|
|
}
|
|
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) toArrayHeaderCode() *arrayHeaderCode {
|
|
return (*arrayHeaderCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toArrayElemCode() *arrayElemCode {
|
|
return (*arrayElemCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toStructFieldCode() *structFieldCode {
|
|
return (*structFieldCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toMapHeadCode() *mapHeaderCode {
|
|
return (*mapHeaderCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toMapKeyCode() *mapKeyCode {
|
|
return (*mapKeyCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toMapValueCode() *mapValueCode {
|
|
return (*mapValueCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toInterfaceCode() *interfaceCode {
|
|
return (*interfaceCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *opcode) toRecursiveCode() *recursiveCode {
|
|
return (*recursiveCode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
type sliceHeaderCode struct {
|
|
*opcodeHeader
|
|
elem *sliceElemCode
|
|
end *opcode
|
|
}
|
|
|
|
func newSliceHeaderCode(ctx *encodeCompileContext) *sliceHeaderCode {
|
|
return &sliceHeaderCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opSliceHead,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newSliceElemCode(ctx *encodeCompileContext, size uintptr) *sliceElemCode {
|
|
return &sliceElemCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opSliceElem,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
size: size,
|
|
}
|
|
}
|
|
|
|
func (c *sliceHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
header := &sliceHeaderCode{}
|
|
code := (*opcode)(unsafe.Pointer(header))
|
|
codeMap[addr] = code
|
|
|
|
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
header.elem = (*sliceElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
|
|
header.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type sliceElemCode struct {
|
|
*opcodeHeader
|
|
idx uintptr
|
|
len uintptr
|
|
size uintptr
|
|
data uintptr
|
|
end *opcode
|
|
}
|
|
|
|
func (c *sliceElemCode) set(header *reflect.SliceHeader) {
|
|
c.idx = uintptr(0)
|
|
c.len = uintptr(header.Len)
|
|
c.data = header.Data
|
|
}
|
|
|
|
func (c *sliceElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
elem := &sliceElemCode{
|
|
idx: c.idx,
|
|
len: c.len,
|
|
size: c.size,
|
|
data: c.data,
|
|
}
|
|
code := (*opcode)(unsafe.Pointer(elem))
|
|
codeMap[addr] = code
|
|
|
|
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
elem.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type arrayHeaderCode struct {
|
|
*opcodeHeader
|
|
len uintptr
|
|
elem *arrayElemCode
|
|
end *opcode
|
|
}
|
|
|
|
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *arrayHeaderCode {
|
|
return &arrayHeaderCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opArrayHead,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
len: uintptr(alen),
|
|
}
|
|
}
|
|
|
|
func newArrayElemCode(ctx *encodeCompileContext, alen int, size uintptr) *arrayElemCode {
|
|
return &arrayElemCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opArrayElem,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
},
|
|
len: uintptr(alen),
|
|
size: size,
|
|
}
|
|
}
|
|
|
|
func (c *arrayHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
header := &arrayHeaderCode{}
|
|
code := (*opcode)(unsafe.Pointer(header))
|
|
codeMap[addr] = code
|
|
|
|
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
header.len = c.len
|
|
header.elem = (*arrayElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
|
|
header.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type arrayElemCode struct {
|
|
*opcodeHeader
|
|
idx uintptr
|
|
len uintptr
|
|
size uintptr
|
|
end *opcode
|
|
}
|
|
|
|
func (c *arrayElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
elem := &arrayElemCode{
|
|
idx: c.idx,
|
|
len: c.len,
|
|
size: c.size,
|
|
}
|
|
code := (*opcode)(unsafe.Pointer(elem))
|
|
codeMap[addr] = code
|
|
|
|
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
elem.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type structFieldCode struct {
|
|
*opcodeHeader
|
|
key []byte
|
|
displayKey string
|
|
isTaggedKey bool
|
|
offset uintptr
|
|
anonymousKey bool
|
|
nextField *opcode
|
|
end *opcode
|
|
}
|
|
|
|
func linkPrevToNextField(prev, cur *structFieldCode) {
|
|
prev.nextField = cur.nextField
|
|
code := prev.toOpcode()
|
|
fcode := cur.toOpcode()
|
|
for {
|
|
var nextCode *opcode
|
|
switch code.op.codeType() {
|
|
case codeArrayElem:
|
|
nextCode = code.toArrayElemCode().end
|
|
case codeSliceElem:
|
|
nextCode = code.toSliceElemCode().end
|
|
case codeMapKey:
|
|
nextCode = code.toMapKeyCode().end
|
|
default:
|
|
nextCode = code.next
|
|
}
|
|
if nextCode == fcode {
|
|
code.next = fcode.next
|
|
break
|
|
} else if nextCode.op == opEnd {
|
|
break
|
|
}
|
|
code = nextCode
|
|
}
|
|
}
|
|
|
|
func (c *structFieldCode) toOpcode() *opcode {
|
|
return (*opcode)(unsafe.Pointer(c))
|
|
}
|
|
|
|
func (c *structFieldCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
field := &structFieldCode{
|
|
key: c.key,
|
|
isTaggedKey: c.isTaggedKey,
|
|
displayKey: c.displayKey,
|
|
anonymousKey: c.anonymousKey,
|
|
offset: c.offset,
|
|
}
|
|
code := (*opcode)(unsafe.Pointer(field))
|
|
codeMap[addr] = code
|
|
|
|
field.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
field.nextField = c.nextField.copy(codeMap)
|
|
field.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type mapHeaderCode struct {
|
|
*opcodeHeader
|
|
key *mapKeyCode
|
|
value *mapValueCode
|
|
end *opcode
|
|
}
|
|
|
|
func (c *mapHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
header := &mapHeaderCode{}
|
|
code := (*opcode)(unsafe.Pointer(header))
|
|
codeMap[addr] = code
|
|
|
|
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
header.key = (*mapKeyCode)(unsafe.Pointer(c.key.copy(codeMap)))
|
|
header.value = (*mapValueCode)(unsafe.Pointer(c.value.copy(codeMap)))
|
|
header.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type mapKeyCode struct {
|
|
*opcodeHeader
|
|
idx int
|
|
len int
|
|
iter unsafe.Pointer
|
|
end *opcode
|
|
}
|
|
|
|
func (c *mapKeyCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
key := &mapKeyCode{
|
|
idx: c.idx,
|
|
len: c.len,
|
|
iter: c.iter,
|
|
}
|
|
code := (*opcode)(unsafe.Pointer(key))
|
|
codeMap[addr] = code
|
|
|
|
key.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
key.end = c.end.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
func (c *mapKeyCode) set(len int, iter unsafe.Pointer) {
|
|
c.idx = 0
|
|
c.len = len
|
|
c.iter = iter
|
|
}
|
|
|
|
type mapValueCode struct {
|
|
*opcodeHeader
|
|
iter unsafe.Pointer
|
|
}
|
|
|
|
func (c *mapValueCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
value := &mapValueCode{
|
|
iter: c.iter,
|
|
}
|
|
code := (*opcode)(unsafe.Pointer(value))
|
|
codeMap[addr] = code
|
|
|
|
value.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
func (c *mapValueCode) set(iter unsafe.Pointer) {
|
|
c.iter = iter
|
|
}
|
|
|
|
func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *mapHeaderCode {
|
|
var op opType
|
|
if withLoad {
|
|
op = opMapHeadLoad
|
|
} else {
|
|
op = opMapHead
|
|
}
|
|
return &mapHeaderCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: op,
|
|
typ: ctx.typ,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newMapKeyCode(ctx *encodeCompileContext) *mapKeyCode {
|
|
return &mapKeyCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opMapKey,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newMapValueCode(ctx *encodeCompileContext) *mapValueCode {
|
|
return &mapValueCode{
|
|
opcodeHeader: &opcodeHeader{
|
|
op: opMapValue,
|
|
displayIdx: ctx.opcodeIndex,
|
|
idx: uintptr(ctx.opcodeIndex) * 8,
|
|
indent: ctx.indent,
|
|
},
|
|
}
|
|
}
|
|
|
|
type interfaceCode struct {
|
|
*opcodeHeader
|
|
root bool
|
|
}
|
|
|
|
func (c *interfaceCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
iface := &interfaceCode{}
|
|
code := (*opcode)(unsafe.Pointer(iface))
|
|
codeMap[addr] = code
|
|
|
|
iface.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
return code
|
|
}
|
|
|
|
type recursiveCode struct {
|
|
*opcodeHeader
|
|
jmp *compiledCode
|
|
seenPtr uintptr
|
|
}
|
|
|
|
func (c *recursiveCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
if code, exists := codeMap[addr]; exists {
|
|
return code
|
|
}
|
|
recur := &recursiveCode{seenPtr: c.seenPtr}
|
|
code := (*opcode)(unsafe.Pointer(recur))
|
|
codeMap[addr] = code
|
|
|
|
recur.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
|
recur.jmp = &compiledCode{
|
|
code: c.jmp.code.copy(codeMap),
|
|
}
|
|
return code
|
|
}
|
|
|
|
func newRecursiveCode(recursive *recursiveCode) *opcode {
|
|
code := copyOpcode(recursive.jmp.code)
|
|
head := (*structFieldCode)(unsafe.Pointer(code))
|
|
head.end.next = newEndOp(&encodeCompileContext{})
|
|
|
|
code.op = code.op.ptrHeadToHead()
|
|
return code
|
|
}
|