Merge pull request #13 from goccy/feature/fix-parallel-encoding

Fix parallel encoding
This commit is contained in:
Masaaki Goshima 2020-08-09 18:08:42 +09:00 committed by GitHub
commit f3d0d848f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 412 additions and 6 deletions

View File

@ -31,8 +31,8 @@ type opcodeMap struct {
}
type opcodeSet struct {
codeIndent *opcode
code *opcode
codeIndent sync.Pool
code sync.Pool
}
func (m *opcodeMap) get(k uintptr) *opcodeSet {
@ -48,6 +48,7 @@ func (m *opcodeMap) set(k uintptr, op *opcodeSet) {
var (
encPool sync.Pool
codePool sync.Pool
cachedOpcode opcodeMap
marshalJSONType reflect.Type
marshalTextType reflect.Type
@ -147,15 +148,20 @@ func (e *Encoder) encode(v interface{}) error {
if codeSet := cachedOpcode.get(typeptr); codeSet != nil {
var code *opcode
if e.enabledIndent {
code = codeSet.codeIndent
code = codeSet.codeIndent.Get().(*opcode)
} else {
code = codeSet.code
code = codeSet.code.Get().(*opcode)
}
p := uintptr(header.ptr)
code.ptr = p
if err := e.run(code); err != nil {
return err
}
if e.enabledIndent {
codeSet.codeIndent.Put(code)
} else {
codeSet.code.Put(code)
}
return nil
}
@ -170,13 +176,25 @@ func (e *Encoder) encode(v interface{}) error {
if err != nil {
return err
}
codeSet := &opcodeSet{codeIndent: codeIndent, code: code}
codeSet := &opcodeSet{
codeIndent: sync.Pool{
New: func() interface{} {
return copyOpcode(codeIndent)
},
},
code: sync.Pool{
New: func() interface{} {
return copyOpcode(code)
},
},
}
cachedOpcode.set(typeptr, codeSet)
p := uintptr(header.ptr)
code.ptr = p
if e.enabledIndent {
codeIndent.ptr = p
return e.run(codeIndent)
}
code.ptr = p
return e.run(code)
}

View File

@ -731,6 +731,11 @@ func (t opType) String() string {
return ""
}
func copyOpcode(code *opcode) *opcode {
codeMap := map[uintptr]*opcode{}
return code.copy(codeMap)
}
type opcodeHeader struct {
op opType
typ *rtype
@ -739,6 +744,16 @@ type opcodeHeader struct {
next *opcode
}
func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader {
return &opcodeHeader{
op: h.op,
typ: h.typ,
ptr: h.ptr,
indent: h.indent,
next: h.next.copy(codeMap),
}
}
type opcode struct {
*opcodeHeader
}
@ -780,6 +795,220 @@ func (c *opcode) beforeLastCode() *opcode {
return nil
}
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 {
case opArrayHead, opArrayHeadIndent:
code = c.toArrayHeaderCode().copy(codeMap)
case opArrayElem, opArrayElemIndent:
code = c.toArrayElemCode().copy(codeMap)
case opSliceHead, opSliceHeadIndent:
code = c.toSliceHeaderCode().copy(codeMap)
case opSliceElem, opSliceElemIndent:
code = c.toSliceElemCode().copy(codeMap)
case opMapHead, opMapHeadLoad, opMapHeadIndent, opMapHeadLoadIndent:
code = c.toMapHeadCode().copy(codeMap)
case opMapKey, opMapKeyIndent:
code = c.toMapKeyCode().copy(codeMap)
case opMapValue, opMapValueIndent:
code = c.toMapValueCode().copy(codeMap)
case opStructFieldHead,
opStructFieldHeadInt,
opStructFieldHeadInt8,
opStructFieldHeadInt16,
opStructFieldHeadInt32,
opStructFieldHeadInt64,
opStructFieldHeadUint,
opStructFieldHeadUint8,
opStructFieldHeadUint16,
opStructFieldHeadUint32,
opStructFieldHeadUint64,
opStructFieldHeadFloat32,
opStructFieldHeadFloat64,
opStructFieldHeadString,
opStructFieldHeadBool,
opStructFieldHeadIndent,
opStructFieldHeadIntIndent,
opStructFieldHeadInt8Indent,
opStructFieldHeadInt16Indent,
opStructFieldHeadInt32Indent,
opStructFieldHeadInt64Indent,
opStructFieldHeadUintIndent,
opStructFieldHeadUint8Indent,
opStructFieldHeadUint16Indent,
opStructFieldHeadUint32Indent,
opStructFieldHeadUint64Indent,
opStructFieldHeadFloat32Indent,
opStructFieldHeadFloat64Indent,
opStructFieldHeadStringIndent,
opStructFieldHeadBoolIndent,
opStructFieldHeadOmitEmpty,
opStructFieldHeadIntOmitEmpty,
opStructFieldHeadInt8OmitEmpty,
opStructFieldHeadInt16OmitEmpty,
opStructFieldHeadInt32OmitEmpty,
opStructFieldHeadInt64OmitEmpty,
opStructFieldHeadUintOmitEmpty,
opStructFieldHeadUint8OmitEmpty,
opStructFieldHeadUint16OmitEmpty,
opStructFieldHeadUint32OmitEmpty,
opStructFieldHeadUint64OmitEmpty,
opStructFieldHeadFloat32OmitEmpty,
opStructFieldHeadFloat64OmitEmpty,
opStructFieldHeadStringOmitEmpty,
opStructFieldHeadBoolOmitEmpty,
opStructFieldHeadOmitEmptyIndent,
opStructFieldHeadIntOmitEmptyIndent,
opStructFieldHeadInt8OmitEmptyIndent,
opStructFieldHeadInt16OmitEmptyIndent,
opStructFieldHeadInt32OmitEmptyIndent,
opStructFieldHeadInt64OmitEmptyIndent,
opStructFieldHeadUintOmitEmptyIndent,
opStructFieldHeadUint8OmitEmptyIndent,
opStructFieldHeadUint16OmitEmptyIndent,
opStructFieldHeadUint32OmitEmptyIndent,
opStructFieldHeadUint64OmitEmptyIndent,
opStructFieldHeadFloat32OmitEmptyIndent,
opStructFieldHeadFloat64OmitEmptyIndent,
opStructFieldHeadStringOmitEmptyIndent,
opStructFieldHeadBoolOmitEmptyIndent,
opStructFieldPtrHead,
opStructFieldPtrHeadInt,
opStructFieldPtrHeadInt8,
opStructFieldPtrHeadInt16,
opStructFieldPtrHeadInt32,
opStructFieldPtrHeadInt64,
opStructFieldPtrHeadUint,
opStructFieldPtrHeadUint8,
opStructFieldPtrHeadUint16,
opStructFieldPtrHeadUint32,
opStructFieldPtrHeadUint64,
opStructFieldPtrHeadFloat32,
opStructFieldPtrHeadFloat64,
opStructFieldPtrHeadString,
opStructFieldPtrHeadBool,
opStructFieldPtrHeadIndent,
opStructFieldPtrHeadIntIndent,
opStructFieldPtrHeadInt8Indent,
opStructFieldPtrHeadInt16Indent,
opStructFieldPtrHeadInt32Indent,
opStructFieldPtrHeadInt64Indent,
opStructFieldPtrHeadUintIndent,
opStructFieldPtrHeadUint8Indent,
opStructFieldPtrHeadUint16Indent,
opStructFieldPtrHeadUint32Indent,
opStructFieldPtrHeadUint64Indent,
opStructFieldPtrHeadFloat32Indent,
opStructFieldPtrHeadFloat64Indent,
opStructFieldPtrHeadStringIndent,
opStructFieldPtrHeadBoolIndent,
opStructFieldPtrHeadOmitEmpty,
opStructFieldPtrHeadIntOmitEmpty,
opStructFieldPtrHeadInt8OmitEmpty,
opStructFieldPtrHeadInt16OmitEmpty,
opStructFieldPtrHeadInt32OmitEmpty,
opStructFieldPtrHeadInt64OmitEmpty,
opStructFieldPtrHeadUintOmitEmpty,
opStructFieldPtrHeadUint8OmitEmpty,
opStructFieldPtrHeadUint16OmitEmpty,
opStructFieldPtrHeadUint32OmitEmpty,
opStructFieldPtrHeadUint64OmitEmpty,
opStructFieldPtrHeadFloat32OmitEmpty,
opStructFieldPtrHeadFloat64OmitEmpty,
opStructFieldPtrHeadStringOmitEmpty,
opStructFieldPtrHeadBoolOmitEmpty,
opStructFieldPtrHeadOmitEmptyIndent,
opStructFieldPtrHeadIntOmitEmptyIndent,
opStructFieldPtrHeadInt8OmitEmptyIndent,
opStructFieldPtrHeadInt16OmitEmptyIndent,
opStructFieldPtrHeadInt32OmitEmptyIndent,
opStructFieldPtrHeadInt64OmitEmptyIndent,
opStructFieldPtrHeadUintOmitEmptyIndent,
opStructFieldPtrHeadUint8OmitEmptyIndent,
opStructFieldPtrHeadUint16OmitEmptyIndent,
opStructFieldPtrHeadUint32OmitEmptyIndent,
opStructFieldPtrHeadUint64OmitEmptyIndent,
opStructFieldPtrHeadFloat32OmitEmptyIndent,
opStructFieldPtrHeadFloat64OmitEmptyIndent,
opStructFieldPtrHeadStringOmitEmptyIndent,
opStructFieldPtrHeadBoolOmitEmptyIndent,
opStructField,
opStructFieldInt,
opStructFieldInt8,
opStructFieldInt16,
opStructFieldInt32,
opStructFieldInt64,
opStructFieldUint,
opStructFieldUint8,
opStructFieldUint16,
opStructFieldUint32,
opStructFieldUint64,
opStructFieldFloat32,
opStructFieldFloat64,
opStructFieldString,
opStructFieldBool,
opStructFieldIndent,
opStructFieldIntIndent,
opStructFieldInt8Indent,
opStructFieldInt16Indent,
opStructFieldInt32Indent,
opStructFieldInt64Indent,
opStructFieldUintIndent,
opStructFieldUint8Indent,
opStructFieldUint16Indent,
opStructFieldUint32Indent,
opStructFieldUint64Indent,
opStructFieldFloat32Indent,
opStructFieldFloat64Indent,
opStructFieldStringIndent,
opStructFieldBoolIndent,
opStructFieldOmitEmpty,
opStructFieldIntOmitEmpty,
opStructFieldInt8OmitEmpty,
opStructFieldInt16OmitEmpty,
opStructFieldInt32OmitEmpty,
opStructFieldInt64OmitEmpty,
opStructFieldUintOmitEmpty,
opStructFieldUint8OmitEmpty,
opStructFieldUint16OmitEmpty,
opStructFieldUint32OmitEmpty,
opStructFieldUint64OmitEmpty,
opStructFieldFloat32OmitEmpty,
opStructFieldFloat64OmitEmpty,
opStructFieldStringOmitEmpty,
opStructFieldBoolOmitEmpty,
opStructFieldOmitEmptyIndent,
opStructFieldIntOmitEmptyIndent,
opStructFieldInt8OmitEmptyIndent,
opStructFieldInt16OmitEmptyIndent,
opStructFieldInt32OmitEmptyIndent,
opStructFieldInt64OmitEmptyIndent,
opStructFieldUintOmitEmptyIndent,
opStructFieldUint8OmitEmptyIndent,
opStructFieldUint16OmitEmptyIndent,
opStructFieldUint32OmitEmptyIndent,
opStructFieldUint64OmitEmptyIndent,
opStructFieldFloat32OmitEmptyIndent,
opStructFieldFloat64OmitEmptyIndent,
opStructFieldStringOmitEmptyIndent,
opStructFieldBoolOmitEmptyIndent:
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; {
@ -846,6 +1075,24 @@ func newSliceHeaderCode(indent int) *sliceHeaderCode {
}
}
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
@ -861,6 +1108,28 @@ func (c *sliceElemCode) set(header *reflect.SliceHeader) {
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
@ -878,6 +1147,25 @@ func newArrayHeaderCode(indent, alen int) *arrayHeaderCode {
}
}
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
@ -886,6 +1174,27 @@ type arrayElemCode struct {
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
@ -894,6 +1203,27 @@ type structFieldCode struct {
end *opcode
}
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,
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
@ -901,6 +1231,25 @@ type mapHeaderCode struct {
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
@ -909,6 +1258,27 @@ type mapKeyCode struct {
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
@ -920,6 +1290,24 @@ type mapValueCode struct {
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
}