123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- //go:build amd64 && !appengine && !noasm && gc
- // +build amd64,!appengine,!noasm,gc
- package zstd
- import (
- "fmt"
- "io"
- "github.com/klauspost/compress/internal/cpuinfo"
- )
- type decodeSyncAsmContext struct {
- llTable []decSymbol
- mlTable []decSymbol
- ofTable []decSymbol
- llState uint64
- mlState uint64
- ofState uint64
- iteration int
- litRemain int
- out []byte
- outPosition int
- literals []byte
- litPosition int
- history []byte
- windowSize int
- ll int // set on error (not for all errors, please refer to _generate/gen.go)
- ml int // set on error (not for all errors, please refer to _generate/gen.go)
- mo int // set on error (not for all errors, please refer to _generate/gen.go)
- }
- // sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm.
- //
- // Please refer to seqdec_generic.go for the reference implementation.
- //
- //go:noescape
- func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
- // sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions.
- //
- //go:noescape
- func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
- // sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer.
- //
- //go:noescape
- func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
- // sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer.
- //
- //go:noescape
- func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
- // decode sequences from the stream with the provided history but without a dictionary.
- func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
- if len(s.dict) > 0 {
- return false, nil
- }
- if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSize {
- return false, nil
- }
- // FIXME: Using unsafe memory copies leads to rare, random crashes
- // with fuzz testing. It is therefore disabled for now.
- const useSafe = true
- /*
- useSafe := false
- if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
- useSafe = true
- }
- if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
- useSafe = true
- }
- if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
- useSafe = true
- }
- */
- br := s.br
- maxBlockSize := maxCompressedBlockSize
- if s.windowSize < maxBlockSize {
- maxBlockSize = s.windowSize
- }
- ctx := decodeSyncAsmContext{
- llTable: s.litLengths.fse.dt[:maxTablesize],
- mlTable: s.matchLengths.fse.dt[:maxTablesize],
- ofTable: s.offsets.fse.dt[:maxTablesize],
- llState: uint64(s.litLengths.state.state),
- mlState: uint64(s.matchLengths.state.state),
- ofState: uint64(s.offsets.state.state),
- iteration: s.nSeqs - 1,
- litRemain: len(s.literals),
- out: s.out,
- outPosition: len(s.out),
- literals: s.literals,
- windowSize: s.windowSize,
- history: hist,
- }
- s.seqSize = 0
- startSize := len(s.out)
- var errCode int
- if cpuinfo.HasBMI2() {
- if useSafe {
- errCode = sequenceDecs_decodeSync_safe_bmi2(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decodeSync_bmi2(s, br, &ctx)
- }
- } else {
- if useSafe {
- errCode = sequenceDecs_decodeSync_safe_amd64(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decodeSync_amd64(s, br, &ctx)
- }
- }
- switch errCode {
- case noError:
- break
- case errorMatchLenOfsMismatch:
- return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", ctx.ml)
- case errorMatchLenTooBig:
- return true, fmt.Errorf("match len (%d) bigger than max allowed length", ctx.ml)
- case errorMatchOffTooBig:
- return true, fmt.Errorf("match offset (%d) bigger than current history (%d)",
- ctx.mo, ctx.outPosition+len(hist)-startSize)
- case errorNotEnoughLiterals:
- return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
- ctx.ll, ctx.litRemain+ctx.ll)
- case errorOverread:
- return true, io.ErrUnexpectedEOF
- case errorNotEnoughSpace:
- size := ctx.outPosition + ctx.ll + ctx.ml
- if debugDecoder {
- println("msl:", s.maxSyncLen, "cap", cap(s.out), "bef:", startSize, "sz:", size-startSize, "mbs:", maxBlockSize, "outsz:", cap(s.out)-startSize)
- }
- return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
- default:
- return true, fmt.Errorf("sequenceDecs_decode returned erronous code %d", errCode)
- }
- s.seqSize += ctx.litRemain
- if s.seqSize > maxBlockSize {
- return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
- }
- err := br.close()
- if err != nil {
- printf("Closing sequences: %v, %+v\n", err, *br)
- return true, err
- }
- s.literals = s.literals[ctx.litPosition:]
- t := ctx.outPosition
- s.out = s.out[:t]
- // Add final literals
- s.out = append(s.out, s.literals...)
- if debugDecoder {
- t += len(s.literals)
- if t != len(s.out) {
- panic(fmt.Errorf("length mismatch, want %d, got %d", len(s.out), t))
- }
- }
- return true, nil
- }
- // --------------------------------------------------------------------------------
- type decodeAsmContext struct {
- llTable []decSymbol
- mlTable []decSymbol
- ofTable []decSymbol
- llState uint64
- mlState uint64
- ofState uint64
- iteration int
- seqs []seqVals
- litRemain int
- }
- const noError = 0
- // error reported when mo == 0 && ml > 0
- const errorMatchLenOfsMismatch = 1
- // error reported when ml > maxMatchLen
- const errorMatchLenTooBig = 2
- // error reported when mo > available history or mo > s.windowSize
- const errorMatchOffTooBig = 3
- // error reported when the sum of literal lengths exeeceds the literal buffer size
- const errorNotEnoughLiterals = 4
- // error reported when capacity of `out` is too small
- const errorNotEnoughSpace = 5
- // error reported when bits are overread.
- const errorOverread = 6
- // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
- //
- // Please refer to seqdec_generic.go for the reference implementation.
- //
- //go:noescape
- func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
- // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
- //
- // Please refer to seqdec_generic.go for the reference implementation.
- //
- //go:noescape
- func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
- // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
- //
- //go:noescape
- func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
- // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
- //
- //go:noescape
- func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
- // decode sequences from the stream without the provided history.
- func (s *sequenceDecs) decode(seqs []seqVals) error {
- br := s.br
- maxBlockSize := maxCompressedBlockSize
- if s.windowSize < maxBlockSize {
- maxBlockSize = s.windowSize
- }
- ctx := decodeAsmContext{
- llTable: s.litLengths.fse.dt[:maxTablesize],
- mlTable: s.matchLengths.fse.dt[:maxTablesize],
- ofTable: s.offsets.fse.dt[:maxTablesize],
- llState: uint64(s.litLengths.state.state),
- mlState: uint64(s.matchLengths.state.state),
- ofState: uint64(s.offsets.state.state),
- seqs: seqs,
- iteration: len(seqs) - 1,
- litRemain: len(s.literals),
- }
- if debugDecoder {
- println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream")
- }
- s.seqSize = 0
- lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56
- var errCode int
- if cpuinfo.HasBMI2() {
- if lte56bits {
- errCode = sequenceDecs_decode_56_bmi2(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decode_bmi2(s, br, &ctx)
- }
- } else {
- if lte56bits {
- errCode = sequenceDecs_decode_56_amd64(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decode_amd64(s, br, &ctx)
- }
- }
- if errCode != 0 {
- i := len(seqs) - ctx.iteration - 1
- switch errCode {
- case errorMatchLenOfsMismatch:
- ml := ctx.seqs[i].ml
- return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
- case errorMatchLenTooBig:
- ml := ctx.seqs[i].ml
- return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
- case errorNotEnoughLiterals:
- ll := ctx.seqs[i].ll
- return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll)
- case errorOverread:
- return io.ErrUnexpectedEOF
- }
- return fmt.Errorf("sequenceDecs_decode_amd64 returned erronous code %d", errCode)
- }
- if ctx.litRemain < 0 {
- return fmt.Errorf("literal count is too big: total available %d, total requested %d",
- len(s.literals), len(s.literals)-ctx.litRemain)
- }
- s.seqSize += ctx.litRemain
- if s.seqSize > maxBlockSize {
- return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
- }
- if debugDecoder {
- println("decode: ", br.remain(), "bits remain on stream. code:", errCode)
- }
- err := br.close()
- if err != nil {
- printf("Closing sequences: %v, %+v\n", err, *br)
- }
- return err
- }
- // --------------------------------------------------------------------------------
- type executeAsmContext struct {
- seqs []seqVals
- seqIndex int
- out []byte
- history []byte
- literals []byte
- outPosition int
- litPosition int
- windowSize int
- }
- // sequenceDecs_executeSimple_amd64 implements the main loop of sequenceDecs.executeSimple in x86 asm.
- //
- // Returns false if a match offset is too big.
- //
- // Please refer to seqdec_generic.go for the reference implementation.
- //
- //go:noescape
- func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
- // Same as above, but with safe memcopies
- //
- //go:noescape
- func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
- // executeSimple handles cases when dictionary is not used.
- func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
- // Ensure we have enough output size...
- if len(s.out)+s.seqSize+compressedBlockOverAlloc > cap(s.out) {
- addBytes := s.seqSize + len(s.out) + compressedBlockOverAlloc
- s.out = append(s.out, make([]byte, addBytes)...)
- s.out = s.out[:len(s.out)-addBytes]
- }
- if debugDecoder {
- printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
- }
- var t = len(s.out)
- out := s.out[:t+s.seqSize]
- ctx := executeAsmContext{
- seqs: seqs,
- seqIndex: 0,
- out: out,
- history: hist,
- outPosition: t,
- litPosition: 0,
- literals: s.literals,
- windowSize: s.windowSize,
- }
- var ok bool
- if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
- ok = sequenceDecs_executeSimple_safe_amd64(&ctx)
- } else {
- ok = sequenceDecs_executeSimple_amd64(&ctx)
- }
- if !ok {
- return fmt.Errorf("match offset (%d) bigger than current history (%d)",
- seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist))
- }
- s.literals = s.literals[ctx.litPosition:]
- t = ctx.outPosition
- // Add final literals
- copy(out[t:], s.literals)
- if debugDecoder {
- t += len(s.literals)
- if t != len(out) {
- panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
- }
- }
- s.out = out
- return nil
- }
|