Skip to content

Commit 561b807

Browse files
committed
codec: Use ContainerNext everywhere CheckBreak is used, and enable more inlining in generated code
- remove direct calls to CheckBreak(); use ContainerNext instead. This cleans up the codebase dramatically, and allows us optimize ContainerNext as needed. - updated genVersion to 26 - moved some Decoder fields from decRd into decoder - moved some Encoder fields from encWr into Encoder - removed genHelperEncoder.WriteStr (which wasn't inline'able) and add genHelperEncoder.EncWr() to give access to encWr.WriteStr directly - Ensure WriteStr and StringZC are inline'able (to give optimal performance to codecgen)
1 parent aadf505 commit 561b807

18 files changed

+1744
-4157
lines changed

codec/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ caveats. See Encode documentation.
247247

248248
```go
249249
const CborStreamBytes byte = 0x5f ...
250-
const GenVersion = 25
250+
const GenVersion = 26
251251
var SelfExt = &extFailWrapper{}
252252
var GoRpc goRpc
253253
var MsgpackSpecRpc msgpackSpecRpc

codec/build.sh

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,10 @@ _usage() {
307307

308308
cat <<EOF
309309
primary usage: $0
310-
-[tesow m n l d] -> [t=tests (e=extra, s=short, o=cover, w=wait), m=make, n=inlining diagnostics, l=mid-stack inlining, d=race detector]
311-
-v -> v=verbose
310+
-t[esow] -> t=tests [e=extra, s=short, o=cover, w=wait]
311+
-[md] -> [m=make, d=race detector]
312+
-[n l i] -> [n=inlining diagnostics, l=mid-stack inlining, i=check inlining for path (path)]
313+
-v -> v=verbose
312314
EOF
313315
if [[ "$(type -t _usage_run)" = "function" ]]; then _usage_run ; fi
314316
}
@@ -329,7 +331,7 @@ _main() {
329331
local gocmd=${MYGOCMD:-go}
330332

331333
OPTIND=1
332-
while getopts ":cetmnrgpfvldsowkxyzb:" flag
334+
while getopts ":cetmnrgpfvldsowkxyzi" flag
333335
do
334336
case "x$flag" in
335337
'xo') zcover=1 ;;
@@ -341,7 +343,7 @@ _main() {
341343
'xl') zargs+=("-gcflags"); zargs+=("-l=4") ;;
342344
'xn') zargs+=("-gcflags"); zargs+=("-m=2") ;;
343345
'xd') zargs+=("-race") ;;
344-
'xb') x='b'; zbenchflags=${OPTARG} ;;
346+
# 'xi') x='i'; zbenchflags=${OPTARG} ;;
345347
x\?) _usage; return 1 ;;
346348
*) x=$flag ;;
347349
esac
@@ -359,7 +361,7 @@ _main() {
359361
'xy') _analyze_debug_types "$@" ;;
360362
'xz') _analyze_do_inlining_and_more "$@" ;;
361363
'xk') _go_compiler_validation_suite ;;
362-
'xb') _bench "$@" ;;
364+
'xi') _check_inlining_one "$@" ;;
363365
esac
364366
# unset zforce zargs zbenchflags
365367
}

codec/decode.go

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import (
1616
const msgBadDesc = "unrecognized descriptor byte"
1717

1818
const (
19-
decDefMaxDepth = 1024 // maximum depth
20-
decDefChanCap = 64 // should be large, as cap cannot be expanded
21-
decScratchByteArrayLen = (8 + 2 + 2) * 8 // around cacheLineSize ie ~64, depending on Decoder size
19+
decDefMaxDepth = 1024 // maximum depth
20+
decDefChanCap = 64 // should be large, as cap cannot be expanded
21+
decScratchByteArrayLen = (8 + 2 + 2 + 1) * 8 // around cacheLineSize ie ~64, depending on Decoder size
2222

2323
// MARKER: massage decScratchByteArrayLen to ensure xxxDecDriver structs fit within cacheLine*N
2424

@@ -150,13 +150,11 @@ type decDriver interface {
150150
// If the format doesn't prefix the length, it returns containerLenUnknown.
151151
// If the expected array was a nil in the stream, it returns containerLenNil.
152152
ReadArrayStart() int
153-
ReadArrayEnd()
154153

155154
// ReadMapStart will return the length of the array.
156155
// If the format doesn't prefix the length, it returns containerLenUnknown.
157156
// If the expected array was a nil in the stream, it returns containerLenNil.
158157
ReadMapStart() int
159-
ReadMapEnd()
160158

161159
reset()
162160

@@ -186,6 +184,8 @@ type decDriverContainerTracker interface {
186184
ReadArrayElem()
187185
ReadMapElemKey()
188186
ReadMapElemValue()
187+
ReadArrayEnd()
188+
ReadMapEnd()
189189
}
190190

191191
type decNegintPosintFloatNumber interface {
@@ -202,11 +202,11 @@ func (x decDriverNoopNumberHelper) decFloat() (f float64, ok bool) { panic("decF
202202

203203
type decDriverNoopContainerReader struct{}
204204

205-
func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
206-
func (x decDriverNoopContainerReader) ReadArrayEnd() {}
207-
func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") }
208-
func (x decDriverNoopContainerReader) ReadMapEnd() {}
209-
func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
205+
// func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
206+
// func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") }
207+
func (x decDriverNoopContainerReader) ReadArrayEnd() {}
208+
func (x decDriverNoopContainerReader) ReadMapEnd() {}
209+
func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
210210

211211
// DecodeOptions captures configuration options during decode.
212212
type DecodeOptions struct {
@@ -729,38 +729,21 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
729729
}
730730
// Not much gain from doing it two ways for array.
731731
// Arrays are not used as much for structs.
732-
hasLen := containerLen >= 0
733-
var checkbreak bool
734732
tisfi := ti.sfi.source()
735-
for j, si := range tisfi {
736-
if hasLen {
737-
if j == containerLen {
738-
break
739-
}
740-
} else if d.checkBreak() {
741-
checkbreak = true
742-
break
743-
}
733+
hasLen := containerLen >= 0
734+
735+
// iterate all the items in the stream
736+
// if mapped elem-wise to a field, handle it
737+
// if more stream items than cap be mapped, error it
738+
for j := 0; d.containerNext(j, containerLen, hasLen); j++ {
744739
d.arrayElem()
745-
d.kStructField(si, rv)
746-
}
747-
var proceed bool
748-
if hasLen {
749-
proceed = containerLen > len(tisfi)
750-
} else {
751-
proceed = !checkbreak
752-
}
753-
// if (hasLen && containerLen > len(tisfi)) || (!hasLen && !checkbreak) {
754-
if proceed {
755-
// read remaining values and throw away
756-
for j := len(tisfi); ; j++ {
757-
if !d.containerNext(j, containerLen, hasLen) {
758-
break
759-
}
760-
d.arrayElem()
740+
if j < len(tisfi) {
741+
d.kStructField(tisfi[j], rv)
742+
} else {
761743
d.structFieldNotFound(j, "")
762744
}
763745
}
746+
764747
d.arrayEnd()
765748
} else {
766749
d.onerror(errNeedMapOrArrayDecodeToStruct)
@@ -1422,6 +1405,7 @@ func (d *Decoder) r() *decRd {
14221405

14231406
func (d *Decoder) init(h Handle) {
14241407
initHandle(h)
1408+
d.cbreak = d.js || d.cbor
14251409
d.bytes = true
14261410
d.err = errDecoderNotInitialized
14271411
d.h = h.getBasicHandle()
@@ -1948,7 +1932,34 @@ func (d *Decoder) decodeFloat32() float32 {
19481932

19491933
// MARKER: do not call mapEnd if mapStart returns containerLenNil.
19501934

1935+
// MARKER: optimize decoding since all formats do not truly support all decDriver'ish operations.
1936+
// - Read(Map|Array)Start is only supported by all formats.
1937+
// - CheckBreak is only supported by json and cbor.
1938+
// - Read(Map|Array)End is only supported by json.
1939+
// - Read(Map|Array)Elem(Kay|Value) is only supported by json.
1940+
// Honor these in the code, to reduce the number of interface calls (even if empty).
1941+
1942+
func (d *Decoder) checkBreak() (v bool) {
1943+
// MARKER: jsonDecDriver.CheckBreak() cannot be inlined (over budget inlining cost).
1944+
// Consequently, there's no benefit in incurring the cost of this wrapping function.
1945+
// It is faster to just call the interface method directly.
1946+
1947+
// if d.js {
1948+
// return d.jsondriver().CheckBreak()
1949+
// }
1950+
// if d.cbor {
1951+
// return d.cbordriver().CheckBreak()
1952+
// }
1953+
1954+
if d.cbreak {
1955+
v = d.d.CheckBreak()
1956+
}
1957+
return
1958+
}
1959+
19511960
func (d *Decoder) containerNext(j, containerLen int, hasLen bool) bool {
1961+
// MARKER: keep in sync with gen-helper.go.tmpl
1962+
19521963
// return (hasLen && j < containerLen) || !(hasLen || slh.d.checkBreak())
19531964
if hasLen {
19541965
return j < containerLen
@@ -1979,7 +1990,10 @@ func (d *Decoder) mapElemValue() {
19791990
}
19801991

19811992
func (d *Decoder) mapEnd() {
1982-
d.d.ReadMapEnd()
1993+
if d.js {
1994+
d.jsondriver().ReadMapEnd()
1995+
}
1996+
// d.d.ReadMapEnd()
19831997
d.depthDecr()
19841998
d.c = 0
19851999
}
@@ -2000,7 +2014,10 @@ func (d *Decoder) arrayElem() {
20002014
}
20012015

20022016
func (d *Decoder) arrayEnd() {
2003-
d.d.ReadArrayEnd()
2017+
if d.js {
2018+
d.jsondriver().ReadArrayEnd()
2019+
}
2020+
// d.d.ReadArrayEnd()
20042021
d.depthDecr()
20052022
d.c = 0
20062023
}

0 commit comments

Comments
 (0)