diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c7be2e9277..ead4a4f0f2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -64,18 +64,18 @@ jobs: name: Update Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.8" + go-version: "1.26.9" cache: false - name: Initialize CodeQL - uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: languages: go - name: Autobuild - uses: github/codeql-action/autobuild@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: category: "/language:go" diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 37d55d6dbe..b7b46b5e71 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -37,6 +37,7 @@ jobs: - alpine - debian engine-version: + - master # moby/moby-bin:master - rc # latest rc - 29 # latest - 28 # latest - 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 459abb3163..6b6a5ea564 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,7 +68,7 @@ jobs: name: Set up Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.8" + go-version: "1.26.9" cache: false - name: Test diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 25507e1aab..1396c8d7b0 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -101,7 +101,7 @@ jobs: name: Set up Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: "1.26.8" + go-version: "1.26.9" cache: false - name: Run gocompat check diff --git a/.golangci.yml b/.golangci.yml index ad5a06f1d8..ac80456651 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,7 +5,7 @@ run: # which causes it to fallback to go1.17 semantics. # # TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24 - go: "1.26.8" + go: "1.26.9" timeout: 5m diff --git a/Dockerfile b/Dockerfile index 02d1fc7d7d..59f519dcbe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ ARG BASE_VARIANT=alpine ARG ALPINE_VERSION=3.23 ARG BASE_DEBIAN_DISTRO=bookworm -ARG GO_VERSION=1.26.8 +ARG GO_VERSION=1.26.9 # XX_VERSION specifies the version of the xx utility to use. # It must be a valid tag in the docker.io/tonistiigi/xx image repository. diff --git a/VERSION b/VERSION index 89eac39afb..4552f1e80f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -29.8.2 +29.9.0 diff --git a/cli-plugins/metadata/metadata.go b/cli-plugins/metadata/metadata.go index 7061486a70..c35a5ad028 100644 --- a/cli-plugins/metadata/metadata.go +++ b/cli-plugins/metadata/metadata.go @@ -1,3 +1,6 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package metadata const ( @@ -35,4 +38,7 @@ type Metadata struct { URL string `json:",omitempty"` // Hidden hides the plugin in completion and help message output. Hidden bool `json:",omitempty"` + // Features declares optional contracts supported by the plugin, keyed by + // feature name. + Features map[string]any `json:",omitempty"` } diff --git a/cli/command/cli.go b/cli/command/cli.go index e405c2cc4f..0d2f4b506f 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -68,6 +68,7 @@ type DockerCli struct { serverInfo ServerInfo contextStore store.Store currentContext string + contextResolver func(*DockerCli) (string, error) init sync.Once initErr error dockerEndpoint docker.Endpoint @@ -208,6 +209,8 @@ func (cli *DockerCli) HooksEnabled() bool { // Initialize the dockerCli runs initialization that must happen after command // line flags are parsed. +// +//nolint:gocyclo func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption) error { for _, o := range ops { if err := o(cli); err != nil { @@ -257,6 +260,16 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption) }, } + if cli.contextResolver != nil { + contextName, err := cli.contextResolver(cli) + if err != nil { + return err + } + if contextName != "" { + cli.currentContext = contextName + } + } + // TODO(krissetto): pass ctx to the funcs instead of using this if cli.enableGlobalMeter { cli.createGlobalMeterProvider(cli.baseCtx) diff --git a/cli/command/cli_options.go b/cli/command/cli_options.go index 469932f9c3..733cfbdf64 100644 --- a/cli/command/cli_options.go +++ b/cli/command/cli_options.go @@ -84,6 +84,19 @@ func WithDefaultContextStoreConfig() CLIOption { } } +// WithContextResolver overrides context selection during [DockerCli.Initialize]. +// The resolver runs after configuration and the context store are loaded, but +// before telemetry and endpoint initialization. +// An empty result preserves normal context selection; an error aborts +// initialization. +// The resolver must not initialize the API client. +func WithContextResolver(resolve func(*DockerCli) (string, error)) CLIOption { + return func(cli *DockerCli) error { + cli.contextResolver = resolve + return nil + } +} + // WithAPIClient configures the cli to use the given API client. func WithAPIClient(c client.APIClient) CLIOption { return func(cli *DockerCli) error { diff --git a/cli/command/cli_test.go b/cli/command/cli_test.go index 27be8d348c..09c093d5dd 100644 --- a/cli/command/cli_test.go +++ b/cli/command/cli_test.go @@ -325,6 +325,64 @@ func TestInitializeShouldAlwaysCreateTheContextStore(t *testing.T) { assert.Check(t, cli.ContextStore() != nil) } +func TestInitializeContextResolver(t *testing.T) { + resolverErr := errors.New("resolver failed") + + for _, tc := range []struct { + name string + context string + err error + }{ + {name: "resolved context", context: "resolved"}, + {name: "normal selection"}, + {name: "resolver failure", err: resolverErr}, + } { + t.Run(tc.name, func(t *testing.T) { + originalConfigDir := config.Dir() + t.Cleanup(func() { config.SetDir(originalConfigDir) }) + config.SetDir(t.TempDir()) + + configDir := t.TempDir() + cfg := configfile.New(filepath.Join(configDir, config.ConfigFileName)) + cfg.Features = map[string]string{"cloud": "foobar"} + assert.NilError(t, cfg.Save()) + + cli, err := NewDockerCli() + assert.NilError(t, err) + + var loadedConfig *configfile.ConfigFile + calls := 0 + + err = cli.Initialize(&flags.ClientOptions{ConfigDir: configDir, Context: "original"}, + WithContextResolver(func(cli *DockerCli) (string, error) { + calls++ + assert.Equal(t, config.Dir(), configDir) + loadedConfig = cli.ConfigFile() + assert.Equal(t, loadedConfig.Features["cloud"], "foobar") + assert.Assert(t, cli.ContextStore() != nil) + assert.Assert(t, cli.client == nil) + return tc.context, tc.err + }), + ) + assert.Equal(t, calls, 1) + assert.Assert(t, cli.ConfigFile() == loadedConfig) + assert.Assert(t, cli.client == nil) + + if tc.err != nil { + assert.ErrorIs(t, err, tc.err) + return + } + assert.NilError(t, err) + + wantContext := tc.context + if wantContext == "" { + wantContext = "original" + } + assert.Equal(t, cli.CurrentContext(), wantContext) + }) + } +} + func TestHooksEnabled(t *testing.T) { t.Run("disabled by default", func(t *testing.T) { // Make sure we don't depend on any existing ~/.docker/config.json diff --git a/cmd/docker-trust/go.mod b/cmd/docker-trust/go.mod index edbd6f2a25..2fecc990ac 100644 --- a/cmd/docker-trust/go.mod +++ b/cmd/docker-trust/go.mod @@ -5,13 +5,13 @@ go 1.26.0 require ( github.com/containerd/errdefs v1.0.0 github.com/distribution/reference v0.6.0 - github.com/docker/cli v29.7.2+incompatible + github.com/docker/cli v29.8.2+incompatible github.com/docker/cli-docs-tool v0.11.0 github.com/docker/distribution v2.8.3+incompatible - github.com/docker/go-connections v0.8.1 + github.com/docker/go-connections v0.8.2 github.com/fvbommel/sortorder v1.2.0 - github.com/moby/moby/api v1.55.0 - github.com/moby/moby/client v0.5.1 + github.com/moby/moby/api v1.56.1 + github.com/moby/moby/client v0.6.2 github.com/opencontainers/go-digest v1.0.0 github.com/sirupsen/logrus v1.10.2 github.com/spf13/cobra v1.10.2 @@ -22,7 +22,7 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect @@ -66,11 +66,11 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect go.opentelemetry.io/otel/trace v1.46.0 // indirect go.opentelemetry.io/proto/otlp v1.11.0 // indirect - golang.org/x/crypto v0.56.0 // indirect - golang.org/x/net v0.58.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/term v0.45.0 // indirect - golang.org/x/text v0.41.0 // indirect + golang.org/x/crypto v0.57.0 // indirect + golang.org/x/net v0.60.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/term v0.46.0 // indirect + golang.org/x/text v0.42.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 // indirect google.golang.org/grpc v1.83.2 // indirect diff --git a/cmd/docker-trust/go.sum b/cmd/docker-trust/go.sum index a92361e9a3..c1b0238dae 100644 --- a/cmd/docker-trust/go.sum +++ b/cmd/docker-trust/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 h1:m2xcjRABtG288vnlV3U/PKh/HnPURxZp50RKNUwBxM8= +github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4/go.mod h1:MTUE7ZuZO89FAtAwozGg6AWD83pcdefnEq5gF82MB8s= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -42,8 +42,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY= -github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.8.2+incompatible h1:2zgdFuoFst2T80oS42vhKGxkd0JRo305eIEKTsxR7pQ= +github.com/docker/cli v29.8.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli-docs-tool v0.11.0 h1:7d8QARFb7QEobizqxmEM7fOteZEHwH/zWgHQtHZEcfE= github.com/docker/cli-docs-tool v0.11.0/go.mod h1:ma8BKiisUo8D6W05XEYIh3oa1UbgrZhi1nowyKFJa8Q= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -54,8 +54,8 @@ github.com/docker/docker-credential-helpers v0.9.9/go.mod h1:v1S+hepowrQXITkEfw6 github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-connections v0.8.1 h1:JibmG5hULs5qXSr/cp/w3Pw5fZuStt4MOHMUExb29/M= -github.com/docker/go-connections v0.8.1/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-connections v0.8.2 h1:9d9DEokx5W7qlr0shkFXIxEA7+TTD+llwzcykSlxMNc= +github.com/docker/go-connections v0.8.2/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY= github.com/docker/go-metrics v0.1.0/go.mod h1:PciI3sONtB051kXALN1JoIlpcu54E1FuPh+4DuqEzyw= @@ -133,10 +133,10 @@ github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KH github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc= -github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= -github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw= -github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM= +github.com/moby/moby/api v1.56.1 h1:PpWkvVPB7Fr/No8w+TfyJ/I6rWZ2YPZhT3JorIg+06c= +github.com/moby/moby/api v1.56.1/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= +github.com/moby/moby/client v0.6.2 h1:ekSPlMccrZGcw6Scb8T9D39qE0mB+XupU/yS0zNw9N4= +github.com/moby/moby/client v0.6.2/go.mod h1:DGcnO7qmPJrqobx/ggQgQ/AUk+2wgVdQv7uxB0/mEsc= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8= @@ -236,27 +236,26 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= -golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= -golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU= +golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= -golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= +golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= diff --git a/cmd/docker/cloud.go b/cmd/docker/cloud.go new file mode 100644 index 0000000000..baf962c387 --- /dev/null +++ b/cmd/docker/cloud.go @@ -0,0 +1,322 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "os/exec" + "runtime" + "strconv" + "strings" + + "github.com/containerd/errdefs" + "github.com/docker/cli/cli" + pluginmanager "github.com/docker/cli/cli-plugins/manager" + "github.com/docker/cli/cli-plugins/metadata" + "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/config" + contextdocker "github.com/docker/cli/cli/context/docker" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +// processCloud resolves the global --cloud[=NAME] option after configuration is +// loaded, but before telemetry and endpoint initialization. +// The option appears in help and completion only when the selected provider is +// installed, valid, and declares support for the resolver contract. +// The provider defaults to the offload plugin; features.cloud in the effective +// Docker config.json can override the plugin name, not its executable path. +// Explicit use also requires the provider's capability declaration. +// Discovery for visibility does not provision a context or connect to a daemon. +// +// # Provider contract +// +// The provider must include "Features": {"cloud-context-resolver": true} in its +// docker-cli-plugin-metadata response to declare support for this contract. +// Older plugins without this declaration leave the flag hidden and cannot be +// used for resolution. +// The CLI uses normal plugin discovery and invokes: +// +// docker- --config= __resolve-context -- +// +// Bare --cloud and --cloud= pass default as the target name. +// The effective config directory is also passed as DOCKER_CONFIG. +// The provider must provision into that context store without changing the saved +// current context or recursively forwarding --cloud. +// It inherits the environment and sends progress and prompts to stderr. Stdin +// is forwarded only when both stdin and stderr are terminals with file handles; +// wrapped Windows consoles use the corresponding standard handles. Otherwise +// the provider receives EOF and must not prompt or open a terminal +// separately. Piped and redirected input belongs to the requested command. +// Stdout must contain exactly one JSON object: +// +// {"DOCKER_CONTEXT":"provisioned-context"} +// +// The returned context must exist, must not be the virtual default context, and +// must have a Docker endpoint with a nonempty host. +// Resolver failures abort command execution without falling back to another +// context. +// Cancellation terminates the resolver process; provisioning subprocesses and +// resource cleanup remain the provider's responsibility. +// Downstream plugins receive --context= instead of the global +// --cloud option. +// The provider implementation ships separately and must support this operation +// before enabling the integration. +func processCloud(ctx context.Context, dockerCli *command.DockerCli, cmd *cobra.Command, args, osArgs []string) ([]string, error) { + if !cmd.Flags().Changed("cloud") { + return osArgs, nil + } + if cmd.Flags().Changed("context") || cmd.Flags().Changed("host") { + return osArgs, errors.New("conflicting options: cannot specify --cloud together with --context or --host") + } + + help, err := cloudHelpRequest(cmd, args) + if err != nil { + return osArgs, err + } + + var contextName string + if !help { + name, _ := cmd.Flags().GetString("cloud") + if name == "" { + name = "default" + } + + contextName, err = resolveCloudContext(ctx, dockerCli, cmd, name) + if err != nil { + return osArgs, fmt.Errorf("--cloud: %w", err) + } + if err := cmd.Flags().Set("context", contextName); err != nil { + return osArgs, err + } + } + + return cloudPluginArgs(cmd, osArgs, contextName) +} + +// cloudResolverFeature is the plugin metadata feature that declares support for +// the __resolve-context contract. +const cloudResolverFeature = "cloud-context-resolver" + +const cloudPluginHelp = "to use --cloud, install the plugin. See https://docs.docker.com/go/cloud-flag/" + +func cloudProvider(dockerCli config.Provider, rootCmd *cobra.Command) (*pluginmanager.Plugin, error) { + provider := dockerCli.ConfigFile().Features["cloud"] + if provider == "" { + provider = "offload" + } + var help string + if provider == "offload" { + help = "\n\n" + cloudPluginHelp + } + + plugin, err := pluginmanager.GetPlugin(provider, dockerCli, rootCmd) + if err != nil { + if provider == "offload" && errdefs.IsNotFound(err) { + return nil, errors.New(cloudPluginHelp) + } + return nil, fmt.Errorf("plugin %q unavailable: %w%s", provider, err, help) + } + if plugin.Err != nil { + return nil, fmt.Errorf("invalid plugin %q: %w%s", provider, plugin.Err, help) + } + + if supported, _ := plugin.Features[cloudResolverFeature].(bool); !supported { + return nil, fmt.Errorf("plugin %q does not support --cloud%s", provider, help) + } + + return plugin, nil +} + +// updateCloudFlagVisibility runs only for help and completion, avoiding plugin +// discovery on ordinary invocations that do not use --cloud. +func updateCloudFlagVisibility(dockerCli config.Provider, rootCmd *cobra.Command) { + flag := rootCmd.Flags().Lookup("cloud") + if flag == nil { + return + } + _, err := cloudProvider(dockerCli, rootCmd) + flag.Hidden = err != nil +} + +func resolveCloudContext(ctx context.Context, dockerCli *command.DockerCli, rootCmd *cobra.Command, name string) (string, error) { + if err := ctx.Err(); err != nil { + return "", err + } + + plugin, err := cloudProvider(dockerCli, rootCmd) + if err != nil { + return "", err + } + + cmd := exec.CommandContext(ctx, plugin.Path, "--config="+config.Dir(), plugin.Name, "__resolve-context", "--", name) // #nosec G204 -- executable validated through CLI plugin discovery + cmd.Env = append(os.Environ(), config.EnvOverrideConfigDir+"="+config.Dir(), metadata.ReexecEnvvar+"="+os.Args[0]) + setResolverStdio(cmd, dockerCli) + + out, err := cmd.Output() + if err != nil { + if ctx.Err() != nil { + return "", ctx.Err() + } + return "", fmt.Errorf("cloud resolver failed: %w", err) + } + + var response struct { + DockerContext string `json:"DOCKER_CONTEXT"` + } + if err := json.Unmarshal(out, &response); err != nil { + return "", fmt.Errorf("invalid cloud resolver response: %w", err) + } + response.DockerContext = strings.TrimSpace(response.DockerContext) + if response.DockerContext == "" || response.DockerContext == command.DefaultContextName { + return "", errors.New("cloud resolver must return a non-default DOCKER_CONTEXT") + } + + if err := validateResolvedContext(dockerCli, response.DockerContext); err != nil { + return "", err + } + + return response.DockerContext, nil +} + +// setResolverStdio connects the resolver to the terminal when both stdin and +// stderr are terminals, so the plugin can prompt interactively. Otherwise +// stderr is forwarded and stdin is left unset. +func setResolverStdio(cmd *exec.Cmd, dockerCli *command.DockerCli) { + cmd.Stderr = dockerCli.Err() + stdinTerminal := dockerCli.In().IsTerminal() + stderrTerminal := dockerCli.Err().IsTerminal() + stdin, stdinFile := dockerCli.In().File() + stderr, stderrFile := dockerCli.Err().File() + if runtime.GOOS == "windows" { + // term.StdStreams can wrap console handles for terminal emulation, + // preventing File from exposing them to the child process. + if stdinTerminal && !stdinFile { + stdin, stdinFile = os.Stdin, true + } + if stderrTerminal && !stderrFile { + stderr, stderrFile = os.Stderr, true + } + } + if stdinTerminal && stderrTerminal && stdinFile && stderrFile { + // Pass files directly: wrapping them makes os/exec copy through pipes, + // hiding terminal identity and potentially consuming the command's input. + cmd.Stdin = stdin + cmd.Stderr = stderr + } +} + +// validateResolvedContext checks that the context exists and has a Docker +// endpoint host, so a missing context or endpoint cannot fall back to the +// local engine. +func validateResolvedContext(dockerCli *command.DockerCli, name string) error { + meta, err := dockerCli.ContextStore().GetMetadata(name) + if err != nil { + return fmt.Errorf("loading resolved context %q: %w", name, err) + } + + endpoint, err := contextdocker.EndpointFromContext(meta) + if err != nil { + return fmt.Errorf("invalid resolved context %q: %w", name, err) + } + if endpoint.Host == "" { + return fmt.Errorf("resolved context %q has no Docker endpoint host", name) + } + return nil +} + +// cloudHelpRequest avoids provisioning for help and shell completion. +// Parse known command flags rather than scanning argv: --help may be an option +// value or an argument to a container, not a request for Docker help. +// Unknown flags and missing flag values return a usage error, so a mistyped +// invocation fails without provisioning or falling back to the local engine. +// Flag values are validated only by the command's own parse, after resolution. +func cloudHelpRequest(rootCmd *cobra.Command, args []string) (bool, error) { + help, _ := rootCmd.PersistentFlags().GetBool("help") + version, _ := rootCmd.Flags().GetBool("version") + if help || version || len(args) == 0 { + return true, nil + } + + switch args[0] { + case "help", "completion", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd: + return true, nil + } + + cmd, remaining, err := rootCmd.Find(args) + if err != nil || cmd == rootCmd || pluginmanager.IsPluginCommand(cmd) { + // Plugin flags are opaque. Only recognize help immediately after the + // plugin name; deeper help is available through "docker help PLUGIN". + return len(args) > 1 && isHelpFlag(args[1]), nil + } + + // "build", "bake", "builder", and "image build" are builtin commands that + // processAliases may still rewrite into a call to the builder plugin + // (buildx) after cloud resolution runs, so their flag set here is only the + // legacy builder's and does not reflect what will actually parse the + // remaining args. Treat them like a plugin command above: only recognize + // help immediately after the resolved command path. + if _, _, _, forwarded := forwardBuilder(builderDefaultPlugin, args, args); forwarded { + return len(remaining) > 0 && isHelpFlag(remaining[0]), nil + } + + cmd.InitDefaultHelpFlag() + flags := cmd.Flags() + flags.AddFlagSet(cmd.PersistentFlags()) + flags.AddFlagSet(cmd.InheritedFlags()) + + err = flags.ParseAll(remaining, func(flag *pflag.Flag, value string) error { + if flag.Name == "help" { + var err error + if help, err = strconv.ParseBool(value); err != nil { + return fmt.Errorf("invalid argument %q for \"--help\" flag: %w", value, err) + } + } + return nil + }) + if err != nil { + // Format the usage error directly. The root command's FlagErrorFunc + // first checks whether the daemon supports the command, which would + // connect to the engine selected before --cloud is resolved. + return false, cli.FlagErrorFunc(cmd, err) + } + + return help, nil +} + +// isHelpFlag reports whether arg requests help, in any of the forms pflag +// accepts for a boolean flag. +func isHelpFlag(arg string) bool { + return arg == "--help" || arg == "-h" || arg == "--help=true" +} + +// cloudPluginArgs only rewrites the global prefix, leaving subcommand arguments +// untouched. Parsing also distinguishes --cloud from another flag's value. +func cloudPluginArgs(cmd *cobra.Command, osArgs []string, contextName string) ([]string, error) { + flags := pflag.NewFlagSet(cmd.Name(), pflag.ContinueOnError) + flags.SetInterspersed(false) + flags.AddFlagSet(cmd.Flags()) + flags.AddFlagSet(cmd.PersistentFlags()) + + result := []string{osArgs[0]} + if contextName != "" { + result = append(result, "--context="+contextName) + } + + if err := flags.ParseAll(osArgs[1:], func(flag *pflag.Flag, value string) error { + if flag.Name != "cloud" { + result = append(result, "--"+flag.Name+"="+value) + } + return nil + }); err != nil { + return osArgs, err + } + + if flags.ArgsLenAtDash() >= 0 { + result = append(result, "--") + } + + return append(result, flags.Args()...), nil +} diff --git a/cmd/docker/cloud_test.go b/cmd/docker/cloud_test.go new file mode 100644 index 0000000000..485f3bc2b0 --- /dev/null +++ b/cmd/docker/cloud_test.go @@ -0,0 +1,682 @@ +package main + +import ( + "bytes" + "cmp" + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/creack/pty" + "github.com/docker/cli/cli-plugins/metadata" + "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/configfile" + contextdocker "github.com/docker/cli/cli/context/docker" + "github.com/docker/cli/cli/context/store" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestCloudFlagHidden(t *testing.T) { + dockerCli, err := command.NewDockerCli() + assert.NilError(t, err) + + tcmd := newDockerCommand(dockerCli) + tcmd.SetArgs([]string{"--cloud=team", "--help"}) + cmd, _, err := tcmd.HandleGlobalFlags() + assert.NilError(t, err) + + name, err := cmd.Flags().GetString("cloud") + assert.NilError(t, err) + assert.Equal(t, name, "team") + assert.Assert(t, cmd.Flags().Lookup("cloud").Hidden) + assert.Assert(t, !strings.Contains(cmd.UsageString(), "--cloud")) +} + +func TestCloudHelpRequest(t *testing.T) { + for _, tc := range []struct { + name string + args []string + help bool + }{ + {name: "no command", help: true}, + {name: "global help", args: []string{"--help"}, help: true}, + {name: "global version", args: []string{"--version"}, help: true}, + {name: "help command", args: []string{"help", "run"}, help: true}, + {name: "completion request", args: []string{"__complete", "run", ""}, help: true}, + {name: "completion script", args: []string{"completion", "fish"}, help: true}, + {name: "builtin help", args: []string{"run", "--help"}, help: true}, + {name: "boolean help value", args: []string{"run", "--help=1"}, help: true}, + {name: "nested help", args: []string{"container", "run", "--help"}, help: true}, + {name: "plugin help", args: []string{"compose", "--help"}, help: true}, + {name: "command execution", args: []string{"ps"}}, + {name: "container help", args: []string{"run", "alpine", "--help"}}, + {name: "flag value", args: []string{"run", "--name", "--help", "alpine"}}, + {name: "help disabled", args: []string{"run", "--help=false", "alpine"}}, + {name: "build help", args: []string{"build", "--help"}, help: true}, + {name: "build buildkit-only flag", args: []string{"build", "--secret", "id=s,src=./s", "."}}, + {name: "image build buildkit-only flag", args: []string{"image", "build", "--push", "."}}, + {name: "builder build buildkit-only flag", args: []string{"builder", "build", "--ssh", "default", "."}}, + {name: "bake help", args: []string{"bake", "--help"}, help: true}, + } { + t.Run(tc.name, func(t *testing.T) { + dockerCli, err := command.NewDockerCli() + assert.NilError(t, err) + tcmd := newDockerCommand(dockerCli) + tcmd.SetArgs(append([]string{"--cloud"}, tc.args...)) + cmd, args, err := tcmd.HandleGlobalFlags() + assert.NilError(t, err) + + help, err := cloudHelpRequest(cmd, args) + assert.NilError(t, err) + assert.Equal(t, help, tc.help) + }) + } +} + +// Flag errors are reported before cloud resolution, so they must not run the +// command's daemon feature checks against the engine selected before it. +func TestCloudFlagErrorSkipsDaemon(t *testing.T) { + originalConfig := config.Dir() + t.Cleanup(func() { config.SetDir(originalConfig) }) + config.SetDir(t.TempDir()) + + var pings atomic.Int32 + daemon := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + pings.Add(1) + w.Header().Set("Docker-Experimental", "false") + })) + defer daemon.Close() + t.Setenv("DOCKER_HOST", "tcp://"+daemon.Listener.Addr().String()) + + dockerCli, err := command.NewDockerCli() + assert.NilError(t, err) + tcmd := newDockerCommand(dockerCli) + tcmd.SetArgs([]string{"--cloud", "checkpoint", "ls", "--unknown"}) + cmd, args, err := tcmd.HandleGlobalFlags() + assert.NilError(t, err) + assert.NilError(t, tcmd.Initialize()) + + _, err = cloudHelpRequest(cmd, args) + assert.Check(t, is.ErrorContains(err, "unknown flag: --unknown")) + assert.Check(t, is.Equal(pings.Load(), int32(0))) +} + +func TestCloudPluginArgs(t *testing.T) { + for _, tc := range []struct { + name string + args []string + context string + want []string + }{ + { + name: "global flag only", + args: []string{"docker", "--cloud=foo", "compose", "up", "--cloud=child"}, + context: "cloud-foo", + want: []string{"docker", "--context=cloud-foo", "compose", "up", "--cloud=child"}, + }, + { + name: "flag value is not cloud flag", + args: []string{"docker", "--config", "--cloud", "--cloud", "-D", "compose", "up"}, + context: "cloud-default", + want: []string{"docker", "--context=cloud-default", "--config=--cloud", "--debug=true", "compose", "up"}, + }, + { + name: "delimiter preserved", + args: []string{"docker", "--cloud=foo", "--", "compose", "--", "--cloud"}, + context: "cloud-foo", + want: []string{"docker", "--context=cloud-foo", "--", "compose", "--", "--cloud"}, + }, + { + name: "repeated cloud flags", + args: []string{"docker", "--cloud=foo", "--cloud=bar", "compose", "up"}, + context: "cloud-bar", + want: []string{"docker", "--context=cloud-bar", "compose", "up"}, + }, + { + name: "help without resolution", + args: []string{"docker", "--cloud", "compose", "--help"}, + want: []string{"docker", "compose", "--help"}, + }, + } { + t.Run(tc.name, func(t *testing.T) { + dockerCli, err := command.NewDockerCli() + assert.NilError(t, err) + tcmd := newDockerCommand(dockerCli) + tcmd.SetArgs(tc.args[1:]) + cmd, _, err := tcmd.HandleGlobalFlags() + assert.NilError(t, err) + + got, err := cloudPluginArgs(cmd, tc.args, tc.context) + assert.NilError(t, err) + assert.DeepEqual(t, got, tc.want) + }) + } +} + +// Exercise the real startup and subprocess boundary without a daemon or cloud +// service, including failures that must never dispatch the requested command. +func TestCloudResolution(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("fixture plugins use shell scripts") + } + + executable, err := os.Executable() + assert.NilError(t, err) + + for _, tc := range []struct { + name string + args []string + response string + exit int + wantName string + wantErr string + plugin bool + skip bool + provider string + noProvider bool + legacyProvider bool + invalidProvider bool + wantHelp bool + command []string + visible bool + }{ + { + name: "default target", + args: []string{"--cloud"}, + wantName: "default", + }, + { + name: "empty target", + args: []string{"--cloud="}, + wantName: "default", + }, + { + name: "named target", + args: []string{"--cloud=team"}, + wantName: "team", + }, + { + name: "plugin dispatch", + args: []string{"--cloud=team"}, + wantName: "team", + plugin: true, + }, + { + name: "nonzero exit", + args: []string{"--cloud"}, + exit: 1, + wantErr: "cloud resolver failed", + }, + { + name: "malformed JSON", + args: []string{"--cloud"}, + response: "not JSON", + wantErr: "invalid cloud resolver response", + }, + { + name: "multiple responses", + args: []string{"--cloud"}, + response: `{} {}`, + wantErr: "invalid cloud resolver response", + }, + { + name: "missing field", + args: []string{"--cloud"}, + response: `{}`, + wantErr: "must return a non-default DOCKER_CONTEXT", + }, + { + name: "local context", + args: []string{"--cloud"}, + response: `{"DOCKER_CONTEXT":"default"}`, + wantErr: "must return a non-default DOCKER_CONTEXT", + }, + { + name: "missing context", + args: []string{"--cloud"}, + response: `{"DOCKER_CONTEXT":"missing"}`, + wantErr: `loading resolved context "missing"`, + }, + { + name: "missing endpoint host", + args: []string{"--cloud"}, + response: `{"DOCKER_CONTEXT":"empty-host"}`, + wantErr: "has no Docker endpoint host", + }, + { + name: "explicit context conflict", + args: []string{"--cloud", "--context=other"}, + wantErr: "conflicting options", + skip: true, + }, + { + name: "explicit host conflict", + args: []string{"--cloud", "--host=tcp://localhost:2375"}, + wantErr: "conflicting options", + skip: true, + }, + { + name: "invalid flag before help", + args: []string{"--cloud"}, + command: []string{"run", "--unknown", "--help"}, + wantErr: "unknown flag: --unknown", + skip: true, + }, + { + name: "default provider", + args: []string{"--cloud"}, + noProvider: true, + wantName: "default", + }, + { + name: "legacy default provider", + args: []string{"--cloud"}, + noProvider: true, + legacyProvider: true, + wantErr: `plugin "offload" does not support --cloud`, + wantHelp: true, + skip: true, + }, + { + name: "invalid default provider", + args: []string{"--cloud"}, + noProvider: true, + invalidProvider: true, + wantErr: `invalid plugin "offload": plugin metadata does not define a vendor`, + wantHelp: true, + skip: true, + }, + { + name: "invalid configured provider", + args: []string{"--cloud"}, + invalidProvider: true, + wantErr: `invalid plugin "foobar": plugin metadata does not define a vendor`, + skip: true, + }, + { + name: "legacy configured provider", + args: []string{"--cloud"}, + legacyProvider: true, + wantErr: `plugin "foobar" does not support --cloud`, + skip: true, + }, + { + name: "configured provider unavailable", + args: []string{"--cloud"}, + provider: "missing", + wantErr: `plugin "missing" unavailable`, + skip: true, + }, + { + name: "provider cannot be a path", + args: []string{"--cloud"}, + provider: "../foobar", + wantErr: `plugin "../foobar" unavailable`, + skip: true, + }, + { + name: "no cloud option", + noProvider: true, + skip: true, + }, + { + name: "help", + args: []string{"--cloud", "--help"}, + noProvider: true, + skip: true, + }, + { + name: "version", + args: []string{"--cloud", "--version"}, + noProvider: true, + skip: true, + }, + { + name: "help exposes supported provider", + command: []string{"--help"}, + noProvider: true, + visible: true, + skip: true, + }, + { + name: "help hides legacy provider", + command: []string{"--help"}, + noProvider: true, + legacyProvider: true, + skip: true, + }, + { + name: "help hides missing provider", + command: []string{"--help"}, + provider: "missing", + skip: true, + }, + { + name: "completion exposes supported provider", + command: []string{"__complete", "--cl"}, + noProvider: true, + visible: true, + skip: true, + }, + { + name: "completion hides legacy provider", + command: []string{"__complete", "--cl"}, + noProvider: true, + legacyProvider: true, + skip: true, + }, + { + name: "completion hides missing provider", + command: []string{"__complete", "--cl"}, + provider: "missing", + skip: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + // Explicit --cloud must override inherited endpoint selection. + t.Setenv("DOCKER_CONTEXT", "inherited") + t.Setenv("DOCKER_HOST", "tcp://127.0.0.1:1") + t.Setenv("DOCKER_CLI_HOOKS", "false") + t.Setenv("DOCKER_CONFIG", t.TempDir()) + + configDir := t.TempDir() + installedProvider := "offload" + if !tc.noProvider { + installedProvider = "foobar" + cfg := configfile.New(filepath.Join(configDir, config.ConfigFileName)) + provider := cmp.Or(tc.provider, "foobar") + cfg.Features = map[string]string{"cloud": provider} + assert.NilError(t, cfg.Save()) + } + + pluginDir := filepath.Join(configDir, "cli-plugins") + assert.NilError(t, os.MkdirAll(pluginDir, 0o755)) + + response := cmp.Or(tc.response, `{"DOCKER_CONTEXT":"resolved"}`) + + providerMetadata := metadata.Metadata{SchemaVersion: "0.1.0", Vendor: "test"} + if tc.invalidProvider { + providerMetadata.Vendor = "" + } + if !tc.legacyProvider { + providerMetadata.Features = map[string]any{cloudResolverFeature: true} + } + pluginMetadata, err := json.Marshal(providerMetadata) + assert.NilError(t, err) + + script := fmt.Sprintf(`#!/bin/sh +if [ "$1" = docker-cli-plugin-metadata ]; then + echo '%s' + exit 0 +fi +printf '%%s\n' "$@" >> "$DOCKER_CONFIG/resolver-args" +echo provisioning >&2 +printf '%%s\n' '%s' +exit %d +`, pluginMetadata, response, tc.exit) + assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-"+installedProvider), []byte(script), 0o755)) + assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-cloudtest"), []byte(`#!/bin/sh +if [ "$1" = docker-cli-plugin-metadata ]; then + echo '{"SchemaVersion":"0.1.0","Vendor":"test"}' + exit 0 +fi +printf '%s\n' "$@" > "$CLOUD_TEST_ARGS" +`), 0o755)) + + dispatchFile := filepath.Join(configDir, "dispatch-args") + t.Setenv("CLOUD_TEST_ARGS", dispatchFile) + + contextStore := store.New(filepath.Join(configDir, "contexts"), command.DefaultContextStoreConfig()) + assert.NilError(t, contextStore.CreateOrUpdate(store.Metadata{ + Name: "resolved", + Endpoints: map[string]any{contextdocker.DockerEndpoint: contextdocker.EndpointMeta{Host: "tcp://127.0.0.1:1"}}, + })) + assert.NilError(t, contextStore.CreateOrUpdate(store.Metadata{ + Name: "empty-host", + Endpoints: map[string]any{contextdocker.DockerEndpoint: contextdocker.EndpointMeta{}}, + })) + + args := append([]string{"docker", "--config=" + configDir}, tc.args...) + switch { + case tc.command != nil: + args = append(args, tc.command...) + case tc.plugin || tc.wantErr != "": + args = append(args, "cloudtest", "up", "--cloud=child") + default: + args = append(args, "context", "show") + } + + payload, err := json.Marshal(args) + assert.NilError(t, err) + + var stdout, stderr bytes.Buffer + cmd := exec.CommandContext(t.Context(), executable, "-test.run=^TestCloudCommandProcess$") + cmd.Env = append(os.Environ(), "CLOUD_TEST_COMMAND="+string(payload)) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + err = cmd.Run() + if tc.wantErr != "" { + assert.Assert(t, err != nil) + assert.Check(t, is.Contains(stderr.String(), tc.wantErr)) + assert.Equal(t, strings.Contains(stderr.String(), cloudPluginHelp), tc.wantHelp, stderr.String()) + _, statErr := os.Stat(dispatchFile) + assert.Assert(t, os.IsNotExist(statErr)) + assert.Equal(t, stdout.String(), "") + } else { + assert.NilError(t, err, stderr.String()) + if tc.command != nil { + assert.Equal(t, strings.Contains(stdout.String(), "--cloud"), tc.visible, stdout.String()) + } + if !tc.skip { + if tc.plugin { + args, err := os.ReadFile(dispatchFile) + assert.NilError(t, err) + assert.Equal(t, string(args), "--context=resolved\n--config="+configDir+"\ncloudtest\nup\n--cloud=child\n") + } else { + assert.Equal(t, stdout.String(), "resolved\n") + } + } + } + + invocation, err := os.ReadFile(filepath.Join(configDir, "resolver-args")) + if tc.skip { + assert.Assert(t, os.IsNotExist(err)) + } else { + assert.NilError(t, err) + assert.Check(t, is.Contains(stderr.String(), "provisioning")) + name := cmp.Or(tc.wantName, "default") + assert.Equal(t, string(invocation), "--config="+configDir+"\n"+installedProvider+"\n__resolve-context\n--\n"+name+"\n") + } + }) + } +} + +func TestCloudResolverInput(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("fixture plugins use shell scripts and pseudo-terminals") + } + + executable, err := os.Executable() + assert.NilError(t, err) + + for _, tc := range []struct { + name string + stdinType string + terminalErr bool + prompt bool + }{ + {name: "interactive", stdinType: "terminal", terminalErr: true, prompt: true}, + {name: "piped stdin", stdinType: "pipe", terminalErr: true}, + {name: "redirected stdin", stdinType: "file", terminalErr: true}, + {name: "redirected stderr", stdinType: "terminal"}, + {name: "noninteractive", stdinType: "pipe"}, + } { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("DOCKER_CLI_HOOKS", "false") + configDir := t.TempDir() + pluginDir := filepath.Join(configDir, "cli-plugins") + assert.NilError(t, os.MkdirAll(pluginDir, 0o755)) + assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-offload"), []byte(`#!/bin/sh +if [ "$1" = docker-cli-plugin-metadata ]; then + echo '{"SchemaVersion":"0.1.0","Vendor":"test","Features":{"cloud-context-resolver":true}}' + exit 0 +fi +if [ -t 0 ]; then + [ -t 2 ] || exit 1 + printf 'Continue? ' >&2 + IFS= read -r reply || exit 1 + printf '%s\n' "$reply" > "$DOCKER_CONFIG/resolver-input" +elif IFS= read -r unexpected; then + echo 'resolver consumed command input' >&2 + exit 1 +fi +echo '{"DOCKER_CONTEXT":"resolved"}' +`), 0o755)) + assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-cloudtest"), []byte(`#!/bin/sh +if [ "$1" = docker-cli-plugin-metadata ]; then + echo '{"SchemaVersion":"0.1.0","Vendor":"test"}' + exit 0 +fi +IFS= read -r input || exit 1 +printf '%s\n' "$input" +`), 0o755)) + + contextStore := store.New(filepath.Join(configDir, "contexts"), command.DefaultContextStoreConfig()) + assert.NilError(t, contextStore.CreateOrUpdate(store.Metadata{ + Name: "resolved", + Endpoints: map[string]any{contextdocker.DockerEndpoint: contextdocker.EndpointMeta{Host: "tcp://127.0.0.1:1"}}, + })) + + terminal, tty, err := pty.Open() + assert.NilError(t, err) + t.Cleanup(func() { + _ = tty.Close() + _ = terminal.Close() + }) + + const commandInput = "input for the original command\n" + var stdin *os.File + switch tc.stdinType { + case "terminal": + stdin = tty + input := commandInput + if tc.prompt { + input = "yes\n" + input + } + _, err = terminal.WriteString(input) + assert.NilError(t, err) + case "pipe": + var writer *os.File + stdin, writer, err = os.Pipe() + assert.NilError(t, err) + t.Cleanup(func() { _ = stdin.Close() }) + t.Cleanup(func() { _ = writer.Close() }) + _, err = writer.WriteString(commandInput) + assert.NilError(t, err) + assert.NilError(t, writer.Close()) + case "file": + inputPath := filepath.Join(configDir, "command-input") + assert.NilError(t, os.WriteFile(inputPath, []byte(commandInput), 0o600)) + stdin, err = os.Open(inputPath) + assert.NilError(t, err) + t.Cleanup(func() { _ = stdin.Close() }) + } + + payload, err := json.Marshal([]string{"docker", "--config=" + configDir, "--cloud", "cloudtest"}) + assert.NilError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) + defer cancel() + var stdout, stderr bytes.Buffer + cmd := exec.CommandContext(ctx, executable, "-test.run=^TestCloudCommandProcess$") + cmd.Env = append(os.Environ(), "CLOUD_TEST_COMMAND="+string(payload)) + cmd.Stdin = stdin + cmd.Stdout = &stdout + cmd.Stderr = &stderr + cmd.WaitDelay = time.Second + if tc.terminalErr { + cmd.Stderr = tty + } + assert.NilError(t, cmd.Run(), stderr.String()) + assert.Equal(t, stdout.String(), commandInput) + + reply, err := os.ReadFile(filepath.Join(configDir, "resolver-input")) + if tc.prompt { + assert.NilError(t, err) + assert.Equal(t, string(reply), "yes\n") + } else { + assert.Assert(t, os.IsNotExist(err)) + } + }) + } +} + +// Run startup in a separate process because it installs process-wide signal +// handlers that intentionally outlive an individual command. +func TestCloudCommandProcess(t *testing.T) { + payload := os.Getenv("CLOUD_TEST_COMMAND") + if payload == "" { + return + } + + assert.NilError(t, json.Unmarshal([]byte(payload), &os.Args)) + + err := dockerMain(context.Background()) + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + } + if err == nil { + os.Exit(0) + } + + os.Exit(getExitCode(err)) +} + +func TestCloudResolutionCancellation(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("fixture plugin uses a shell script") + } + + originalConfig := config.Dir() + t.Cleanup(func() { config.SetDir(originalConfig) }) + config.SetDir(t.TempDir()) + + cfg := configfile.New(filepath.Join(config.Dir(), config.ConfigFileName)) + cfg.Features = map[string]string{"cloud": "foobar"} + assert.NilError(t, cfg.Save()) + + pluginDir := filepath.Join(config.Dir(), "cli-plugins") + assert.NilError(t, os.MkdirAll(pluginDir, 0o755)) + assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-foobar"), []byte(`#!/bin/sh +if [ "$1" = docker-cli-plugin-metadata ]; then + echo '{"SchemaVersion":"0.1.0","Vendor":"test","Features":{"cloud-context-resolver":true}}' + exit 0 +fi +exec sleep 30 +`), 0o755)) + + dockerCli, err := command.NewDockerCli() + assert.NilError(t, err) + tcmd := newDockerCommand(dockerCli) + tcmd.SetArgs(strings.Fields("--cloud context show")) + cmd, _, err := tcmd.HandleGlobalFlags() + assert.NilError(t, err) + + ctx, cancel := context.WithTimeout(t.Context(), time.Second) + defer cancel() + + _, err = resolveCloudContext(ctx, dockerCli, cmd, "default") + assert.ErrorIs(t, err, context.DeadlineExceeded) +} diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index 2341570b91..47c720e941 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -178,6 +178,9 @@ func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand { _ = cmd.RegisterFlagCompletionFunc("log-level", completeLogLevels) cmd.Flags().BoolP("version", "v", false, "Print version information and quit") + cmd.Flags().String("cloud", "", "Use a cloud context, provisioning it if necessary (optionally --cloud=NAME)") + cmd.Flags().Lookup("cloud").NoOptDefVal = "default" + cmd.Flags().Lookup("cloud").Hidden = true setFlagErrorFunc(dockerCli, cmd) setupHelpCommand(dockerCli, cmd, helpCmd) @@ -250,6 +253,7 @@ func setHelpFunc(dockerCli command.Cli, cmd *cobra.Command) { ccmd.Println(err) return } + updateCloudFlagVisibility(dockerCli, ccmd.Root()) if len(args) >= 1 { err := tryRunPluginHelp(dockerCli, ccmd, args) @@ -508,7 +512,18 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { return err } - if err := tcmd.Initialize(command.WithEnableGlobalMeterProvider(), command.WithEnableGlobalTracerProvider()); err != nil { + if err := tcmd.Initialize( + command.WithEnableGlobalMeterProvider(), + command.WithEnableGlobalTracerProvider(), + command.WithContextResolver(func(cli *command.DockerCli) (string, error) { + var err error + os.Args, err = processCloud(ctx, cli, cmd, args, os.Args) + if err != nil { + return "", err + } + return cmd.Flags().GetString("context") + }), + ); err != nil { return err } @@ -538,6 +553,7 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { if err := pluginmanager.AddPluginCommandStubs(dockerCli, cmd); err != nil { return err } + updateCloudFlagVisibility(dockerCli, cmd) } var subCommand *cobra.Command diff --git a/dockerfiles/Dockerfile.dev b/dockerfiles/Dockerfile.dev index 7f02956252..c1a7d04c27 100644 --- a/dockerfiles/Dockerfile.dev +++ b/dockerfiles/Dockerfile.dev @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -ARG GO_VERSION=1.26.8 +ARG GO_VERSION=1.26.9 # ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image. # It must be a supported tag in the docker.io/library/alpine image repository diff --git a/dockerfiles/Dockerfile.lint b/dockerfiles/Dockerfile.lint index b0404ab8b8..e6acf6f718 100644 --- a/dockerfiles/Dockerfile.lint +++ b/dockerfiles/Dockerfile.lint @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -ARG GO_VERSION=1.26.8 +ARG GO_VERSION=1.26.9 # ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image. # It must be a supported tag in the docker.io/library/alpine image repository diff --git a/dockerfiles/Dockerfile.vendor b/dockerfiles/Dockerfile.vendor index d781ef9830..442e88286e 100644 --- a/dockerfiles/Dockerfile.vendor +++ b/dockerfiles/Dockerfile.vendor @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -ARG GO_VERSION=1.26.8 +ARG GO_VERSION=1.26.9 # ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image. # It must be a supported tag in the docker.io/library/alpine image repository diff --git a/e2e/compose-env.yaml b/e2e/compose-env.yaml index c4f3774319..975b1b18eb 100644 --- a/e2e/compose-env.yaml +++ b/e2e/compose-env.yaml @@ -31,6 +31,7 @@ services: dockerfile: engine/Dockerfile args: ENGINE_VERSION: ${ENGINE_VERSION:-29} + ENGINE_SOURCE: ${ENGINE_SOURCE:-dind} privileged: true command: ['--insecure-registry=registry:5000', '--insecure-registry=privateregistry:5001', '--experimental'] environment: diff --git a/e2e/container/run_test.go b/e2e/container/run_test.go index d45fe0865d..fb6c8d19c7 100644 --- a/e2e/container/run_test.go +++ b/e2e/container/run_test.go @@ -112,7 +112,7 @@ func TestRunWithCgroupNamespace(t *testing.T) { func TestRunUmask(t *testing.T) { environment.SkipIfDaemonNotLinux(t) - t.Skip("FIXME: un-skip once e2e tests v29.8.0") + skip.If(t, versions.LessThan(environment.DaemonAPIVersion(t), "1.56")) testCases := []struct { name string diff --git a/e2e/testdata/Dockerfile.connhelper-ssh b/e2e/testdata/Dockerfile.connhelper-ssh index 6f65ea7934..61cde646f1 100644 --- a/e2e/testdata/Dockerfile.connhelper-ssh +++ b/e2e/testdata/Dockerfile.connhelper-ssh @@ -3,8 +3,16 @@ # ENGINE_VERSION is the version of the (docker-in-docker) Docker Engine to # test against. ARG ENGINE_VERSION=29 +# ENGINE_SOURCE is "dind" or "moby-bin" (moby/moby-bin:master). +ARG ENGINE_SOURCE=dind -FROM docker:${ENGINE_VERSION}-dind +FROM docker:${ENGINE_VERSION}-dind AS engine-dind + +# moby/moby-bin only has the daemon binaries. +FROM docker:dind AS engine-moby-bin +COPY --link --from=moby/moby-bin:master / /usr/local/bin/ + +FROM engine-${ENGINE_SOURCE} # the openssh-client update is needed for security reasons when using docker:23.0-dind, currently maintained as an lts by mirantis RUN apk --no-cache add openssl openssh-client openssh-server shadow && \ diff --git a/e2e/testdata/engine/Dockerfile b/e2e/testdata/engine/Dockerfile index d688a20606..3dea13eabc 100644 --- a/e2e/testdata/engine/Dockerfile +++ b/e2e/testdata/engine/Dockerfile @@ -1,5 +1,14 @@ ARG ENGINE_VERSION -FROM docker:${ENGINE_VERSION}-dind +# ENGINE_SOURCE is "dind" or "moby-bin" (moby/moby-bin:master). +ARG ENGINE_SOURCE=dind + +FROM docker:${ENGINE_VERSION}-dind AS engine-dind + +# moby/moby-bin only has the daemon binaries. +FROM docker:dind AS engine-moby-bin +COPY --link --from=moby/moby-bin:master / /usr/local/bin/ + +FROM engine-${ENGINE_SOURCE} # Trust the tlsregistry CA so dockerd connects without --insecure-registry. COPY registry/certs/ca.crt /usr/local/share/ca-certificates/tlsregistry-ca.crt diff --git a/scripts/test/e2e/run b/scripts/test/e2e/run index ad6caaaa13..6f1cc1a4c9 100755 --- a/scripts/test/e2e/run +++ b/scripts/test/e2e/run @@ -42,6 +42,11 @@ setup() { sh e2e/testdata/registry/certs/gen-certs.sh fi + # ENGINE_VERSION=master tests against moby/moby-bin:master. + if [ "${ENGINE_VERSION:-}" = "master" ]; then + export ENGINE_SOURCE=moby-bin + fi + COMPOSE_PROJECT_NAME=$project COMPOSE_FILE=$file docker compose up --build -d >&2 # Ensure supporting services exist before running tests. If one fails to start, diff --git a/vendor.mod b/vendor.mod index b1bfb7897a..d6ca6bedd3 100644 --- a/vendor.mod +++ b/vendor.mod @@ -15,14 +15,14 @@ require ( dario.cat/mergo v1.0.2 github.com/containerd/errdefs v1.0.0 github.com/containerd/errdefs/pkg v0.3.0 - github.com/containerd/log v0.1.0 + github.com/containerd/log v0.2.0 github.com/containerd/platforms v1.0.0-rc.5 github.com/creack/pty v1.1.24 github.com/distribution/reference v0.6.0 github.com/docker/cli-docs-tool v0.11.0 github.com/docker/distribution v2.8.3+incompatible github.com/docker/docker-credential-helpers v0.9.9 - github.com/docker/go-connections v0.8.1 + github.com/docker/go-connections v0.8.2 github.com/docker/go-units v0.5.0 github.com/fvbommel/sortorder v1.2.0 github.com/go-jose/go-jose/v4 v4.1.5 @@ -31,10 +31,10 @@ require ( github.com/google/go-cmp v0.7.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.6.0 - github.com/mattn/go-runewidth v0.0.29 + github.com/mattn/go-runewidth v0.0.31 github.com/moby/go-archive v0.3.3 - github.com/moby/moby/api v1.56.0 - github.com/moby/moby/client v0.6.0 + github.com/moby/moby/api v1.56.1 + github.com/moby/moby/client v0.6.2 github.com/moby/patternmatcher v0.6.1 github.com/moby/swarmkit/v2 v2.1.2 github.com/moby/sys/atomicwriter v0.1.0 @@ -70,8 +70,8 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 // indirect + github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 // indirect; see https://github.com/microsoft/hcsshim/pull/2545 github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -87,7 +87,7 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.19.2 // indirect + github.com/klauspost/compress v1.20.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/user v0.4.1 // indirect github.com/moby/sys/userns v0.2.1 // indirect @@ -102,7 +102,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 // indirect go.opentelemetry.io/proto/otlp v1.11.0 // indirect golang.org/x/mod v0.41.0 // indirect - golang.org/x/net v0.59.0 // indirect + golang.org/x/net v0.60.0 // indirect golang.org/x/time v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 // indirect diff --git a/vendor.sum b/vendor.sum index 36d2533377..80f9952157 100644 --- a/vendor.sum +++ b/vendor.sum @@ -2,10 +2,10 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= -github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 h1:m2xcjRABtG288vnlV3U/PKh/HnPURxZp50RKNUwBxM8= +github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4/go.mod h1:MTUE7ZuZO89FAtAwozGg6AWD83pcdefnEq5gF82MB8s= +github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 h1:71VU8kW/LCxJkx41+YYys1EgQO+AUnPa1TrxTSyYUCU= +github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0/go.mod h1:ma0QpxizD4fyyzJ1C7MIblymTD2Nxz5Mho/3CepwIZg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -18,8 +18,8 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/log v0.2.0 h1:BewD/umNgVnoczglOpX8eRMyEy5t5iPlu5AIpnWDONc= +github.com/containerd/log v0.2.0/go.mod h1:/M7L7CXKcPTfNC74XzaK+5H5KbO5+4lJVpuVI6vRLoM= github.com/containerd/platforms v1.0.0-rc.5 h1:vXd569rDrz8LeMXzAnBsy6LADV5YtsD8oyaRarxdmSU= github.com/containerd/platforms v1.0.0-rc.5/go.mod h1:lKlMXyLybmBedS/JJm11uDofzI8L2v0J2ZbYvNsbq1A= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -37,8 +37,8 @@ github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBi github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker-credential-helpers v0.9.9 h1:BkydjIgZ46JnDbqyM2p2fc63KMw6y+KHL3Em/2AGJ7w= github.com/docker/docker-credential-helpers v0.9.9/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= -github.com/docker/go-connections v0.8.1 h1:JibmG5hULs5qXSr/cp/w3Pw5fZuStt4MOHMUExb29/M= -github.com/docker/go-connections v0.8.1/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-connections v0.8.2 h1:9d9DEokx5W7qlr0shkFXIxEA7+TTD+llwzcykSlxMNc= +github.com/docker/go-connections v0.8.2/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-events v0.1.0 h1:J8VX4H7Ta8mmBhv/K/24x1kosKOrEEnYmGjcdFHTOW0= github.com/docker/go-events v0.1.0/go.mod h1:jwVwMgySJX4PiukIIRrind1wPGU8QhPa8aTEPkreUj4= github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY= @@ -78,20 +78,20 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= -github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ= +github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mattn/go-runewidth v0.0.29 h1:3oGF3R/S2N9DQ3ptftzVIvg2eicmojCzlwBEmqEPDfQ= -github.com/mattn/go-runewidth v0.0.29/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= +github.com/mattn/go-runewidth v0.0.31 h1:1oCV4ReTlosDBc6rYRw5cL8S/4y8iv5oRl4SJ5IBgwo= +github.com/mattn/go-runewidth v0.0.31/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.3.3 h1:OxxR9paxsluYi+zDUEXTTaIxtkK3viymW+Ka7vRhhME= github.com/moby/go-archive v0.3.3/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE= -github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ= -github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= -github.com/moby/moby/client v0.6.0 h1:AJjEB21QPbXSXjDsZorFBoDZPhMrfbpaPLgSMAW9Bgs= -github.com/moby/moby/client v0.6.0/go.mod h1:OCo00wNRyA3m4lmJ228W3JbyCN4ZNNYjpOXiJydBdcQ= +github.com/moby/moby/api v1.56.1 h1:PpWkvVPB7Fr/No8w+TfyJ/I6rWZ2YPZhT3JorIg+06c= +github.com/moby/moby/api v1.56.1/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk= +github.com/moby/moby/client v0.6.2 h1:ekSPlMccrZGcw6Scb8T9D39qE0mB+XupU/yS0zNw9N4= +github.com/moby/moby/client v0.6.2/go.mod h1:DGcnO7qmPJrqobx/ggQgQ/AUk+2wgVdQv7uxB0/mEsc= github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.1.2 h1:1WDZAI6HVYNKdCG4zlXnTAPyLsLwuhRGWlHoOUf5Z6I= @@ -193,8 +193,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= -golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= +golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU= +golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -203,7 +203,6 @@ golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go index bcbe00d0c5..01c9519c3d 100644 --- a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go +++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -26,7 +26,7 @@ func (csiState csiEntryState) Handle(b byte) (s state, e error) { func (csiState csiEntryState) Transition(s state) error { csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) + _ = csiState.baseState.Transition(s) switch s { case csiState.parser.ground: @@ -34,9 +34,9 @@ func (csiState csiEntryState) Transition(s state) error { case csiState.parser.csiParam: switch { case sliceContains(csiParams, csiState.parser.context.currentChar): - csiState.parser.collectParam() + _ = csiState.parser.collectParam() case sliceContains(intermeds, csiState.parser.context.currentChar): - csiState.parser.collectInter() + _ = csiState.parser.collectInter() } } diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go index 7ed5e01c34..88146e6fe5 100644 --- a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go +++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go @@ -16,8 +16,7 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) { case sliceContains(alphabetics, b): return csiState.parser.ground, nil case sliceContains(csiCollectables, b): - csiState.parser.collectParam() - return csiState, nil + return csiState, csiState.parser.collectParam() case sliceContains(executors, b): return csiState, csiState.parser.execute() } @@ -27,7 +26,7 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) { func (csiState csiParamState) Transition(s state) error { csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) + _ = csiState.baseState.Transition(s) switch s { case csiState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go index 1c719db9e4..88429690f9 100644 --- a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go +++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -25,7 +25,7 @@ func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { func (escState escapeIntermediateState) Transition(s state) error { escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) + _ = escState.baseState.Transition(s) switch s { case escState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go index 6390abd231..854e3812a9 100644 --- a/vendor/github.com/Azure/go-ansiterm/escape_state.go +++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go @@ -29,7 +29,7 @@ func (escState escapeState) Handle(b byte) (s state, e error) { func (escState escapeState) Transition(s state) error { escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) + _ = escState.baseState.Transition(s) switch s { case escState.parser.ground: diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go index 03cec7ada6..2e8ef80fb7 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser.go +++ b/vendor/github.com/Azure/go-ansiterm/parser.go @@ -113,16 +113,13 @@ func (ap *AnsiParser) handle(b byte) error { if newState == nil { ap.logf("WARNING: newState is nil") - return errors.New("New state of 'nil' is invalid.") + return errors.New("new state of 'nil' is invalid") } - if newState != ap.currState { - if err := ap.changeState(newState); err != nil { - return err - } + if newState == ap.currState { + return nil } - - return nil + return ap.changeState(newState) } func (ap *AnsiParser) changeState(newState state) error { @@ -136,7 +133,7 @@ func (ap *AnsiParser) changeState(newState state) error { // Perform transition action if err := ap.currState.Transition(newState); err != nil { - ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) + ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name(), err) return err } diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go index de0a1f9cde..dc001532a6 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go +++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -4,9 +4,9 @@ import ( "strconv" ) -func parseParams(bytes []byte) ([]string, error) { - paramBuff := make([]byte, 0, 0) - params := []string{} +func parseParams(bytes []byte) []string { + var paramBuff []byte + var params []string for _, v := range bytes { if v == ';' { @@ -14,7 +14,7 @@ func parseParams(bytes []byte) ([]string, error) { // Completed parameter, append it to the list s := string(paramBuff) params = append(params, s) - paramBuff = make([]byte, 0, 0) + paramBuff = paramBuff[:0] } } else { paramBuff = append(paramBuff, v) @@ -27,11 +27,7 @@ func parseParams(bytes []byte) ([]string, error) { params = append(params, s) } - return params, nil -} - -func parseCmd(context ansiContext) (string, error) { - return string(context.currentChar), nil + return params } func getInt(params []string, dflt int) int { diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go index 0bb5e51e9a..2aee10159a 100644 --- a/vendor/github.com/Azure/go-ansiterm/parser_actions.go +++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go @@ -15,10 +15,9 @@ func (ap *AnsiParser) collectInter() error { } func (ap *AnsiParser) escDispatch() error { - cmd, _ := parseCmd(*ap.context) - intermeds := ap.context.interBuffer + cmd := string(ap.context.currentChar) ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) - ap.logf("escDispatch: %v(%v)", cmd, intermeds) + ap.logf("escDispatch: %s(%q)", cmd, string(ap.context.interBuffer)) switch cmd { case "D": // IND @@ -31,14 +30,14 @@ func (ap *AnsiParser) escDispatch() error { return err case "M": // RI return ap.eventHandler.RI() + default: + return nil } - - return nil } func (ap *AnsiParser) csiDispatch() error { - cmd, _ := parseCmd(*ap.context) - params, _ := parseParams(ap.context.paramBuffer) + cmd := string(ap.context.currentChar) + params := parseParams(ap.context.paramBuffer) ap.logf("Parsed params: %v with length: %d", params, len(params)) ap.logf("csiDispatch: %v(%v)", cmd, params) @@ -109,9 +108,8 @@ func (ap *AnsiParser) print() error { return ap.eventHandler.Print(ap.context.currentChar) } -func (ap *AnsiParser) clear() error { +func (ap *AnsiParser) clear() { ap.context = &ansiContext{} - return nil } func (ap *AnsiParser) execute() error { diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go index f2ea1fcd12..cf72692261 100644 --- a/vendor/github.com/Azure/go-ansiterm/states.go +++ b/vendor/github.com/Azure/go-ansiterm/states.go @@ -1,7 +1,5 @@ package ansiterm -type stateID int - type state interface { Enter() error Exit() error diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go index 392114493a..d94dd3a347 100644 --- a/vendor/github.com/Azure/go-ansiterm/utilities.go +++ b/vendor/github.com/Azure/go-ansiterm/utilities.go @@ -1,9 +1,5 @@ package ansiterm -import ( - "strconv" -) - func sliceContains(bytes []byte, b byte) bool { for _, v := range bytes { if v == b { @@ -13,9 +9,3 @@ func sliceContains(bytes []byte, b byte) bool { return false } - -func convertBytesToInteger(bytes []byte) int { - s := string(bytes) - i, _ := strconv.Atoi(s) - return i -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go index 5599082ae9..c6cc027a78 100644 --- a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go +++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -5,12 +5,9 @@ package winterm import ( "fmt" "os" - "strconv" - "strings" "syscall" - "github.com/Azure/go-ansiterm" - windows "golang.org/x/sys/windows" + "golang.org/x/sys/windows" ) // Windows keyboard constants @@ -55,100 +52,6 @@ const ( ENHANCED_KEY = 0x0100 ) -type ansiCommand struct { - CommandBytes []byte - Command string - Parameters []string - IsSpecial bool -} - -func newAnsiCommand(command []byte) *ansiCommand { - - if isCharacterSelectionCmdChar(command[1]) { - // Is Character Set Selection commands - return &ansiCommand{ - CommandBytes: command, - Command: string(command), - IsSpecial: true, - } - } - - // last char is command character - lastCharIndex := len(command) - 1 - - ac := &ansiCommand{ - CommandBytes: command, - Command: string(command[lastCharIndex]), - IsSpecial: false, - } - - // more than a single escape - if lastCharIndex != 0 { - start := 1 - // skip if double char escape sequence - if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { - start++ - } - // convert this to GetNextParam method - ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) - } - - return ac -} - -func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { - if index < 0 || index >= len(ac.Parameters) { - return defaultValue - } - - param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) - if err != nil { - return defaultValue - } - - return int16(param) -} - -func (ac *ansiCommand) String() string { - return fmt.Sprintf("0x%v \"%v\" (\"%v\")", - bytesToHex(ac.CommandBytes), - ac.Command, - strings.Join(ac.Parameters, "\",\"")) -} - -// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. -// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. -func isAnsiCommandChar(b byte) bool { - switch { - case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: - return true - case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: - // non-CSI escape sequence terminator - return true - case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: - // String escape sequence terminator - return true - } - return false -} - -func isXtermOscSequence(command []byte, current byte) bool { - return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) -} - -func isCharacterSelectionCmdChar(b byte) bool { - return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) -} - -// bytesToHex converts a slice of bytes to a human-readable string. -func bytesToHex(b []byte) string { - hex := make([]string, len(b)) - for i, ch := range b { - hex[i] = fmt.Sprintf("%X", ch) - } - return strings.Join(hex, "") -} - // ensureInRange adjusts the passed value, if necessary, to ensure it is within // the passed min / max range. func ensureInRange(n int16, min int16, max int16) int16 { diff --git a/vendor/github.com/Microsoft/go-winio/.golangci.yml b/vendor/github.com/Microsoft/go-winio/.golangci.yml index faedfe937a..07a22649a0 100644 --- a/vendor/github.com/Microsoft/go-winio/.golangci.yml +++ b/vendor/github.com/Microsoft/go-winio/.golangci.yml @@ -1,9 +1,15 @@ +version: "2" +formatters: + enable: + - gofmt # files are gofmt'ed linters: enable: # style - containedctx # struct contains a context - dupl # duplicate code - - errname # erorrs are named correctly + - dupword # duplicate words in comments + - errname # errors are named correctly + - intrange # integer ranges in for loop - nolintlint # "//nolint" directives are properly explained - revive # golint replacement - unconvert # unnecessary conversions @@ -13,135 +19,155 @@ linters: - contextcheck # function uses a non-inherited context - errorlint # errors not wrapped for 1.13 - exhaustive # check exhaustiveness of enum switch statements - - gofmt # files are gofmt'ed + - gocritic # various code quality checks - gosec # security + - mirror # avoid allocations - nilerr # returns nil even with non-nil error - thelper # test helpers without t.Helper() - unparam # unused function params -issues: - exclude-dirs: - - pkg/etw/sample - - exclude-rules: - # err is very often shadowed in nested scopes - - linters: - - govet - text: '^shadow: declaration of "err" shadows declaration' - - # ignore long lines for skip autogen directives - - linters: - - revive - text: "^line-length-limit: " - source: "^//(go:generate|sys) " - - #TODO: remove after upgrading to go1.18 - # ignore comment spacing for nolint and sys directives - - linters: - - revive - text: "^comment-spacings: no space between comment delimiter and comment text" - source: "//(cspell:|nolint:|sys |todo)" - - # not on go 1.18 yet, so no any - - linters: - - revive - text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'" - - # allow unjustified ignores of error checks in defer statements - - linters: - - nolintlint - text: "^directive `//nolint:errcheck` should provide explanation" - source: '^\s*defer ' - - # allow unjustified ignores of error lints for io.EOF - - linters: - - nolintlint - text: "^directive `//nolint:errorlint` should provide explanation" - source: '[=|!]= io.EOF' - - -linters-settings: - exhaustive: - default-signifies-exhaustive: true - govet: - enable-all: true - disable: - # struct order is often for Win32 compat - # also, ignore pointer bytes/GC issues for now until performance becomes an issue - - fieldalignment - nolintlint: - require-explanation: true - require-specific: true - revive: - # revive is more configurable than static check, so likely the preferred alternative to static-check - # (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997) - enable-all-rules: - true - # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md + exclusions: + paths: + - pkg/etw/sample + presets: + - comments + - common-false-positives + - legacy + - std-error-handling rules: - # rules with required arguments - - name: argument-limit - disabled: true - - name: banned-characters - disabled: true - - name: cognitive-complexity - disabled: true - - name: cyclomatic - disabled: true - - name: file-header - disabled: true - - name: function-length - disabled: true - - name: function-result-limit - disabled: true - - name: max-public-structs - disabled: true - # geneally annoying rules - - name: add-constant # complains about any and all strings and integers - disabled: true - - name: confusing-naming # we frequently use "Foo()" and "foo()" together - disabled: true - - name: flag-parameter # excessive, and a common idiom we use - disabled: true - - name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead - disabled: true - # general config - - name: line-length-limit - arguments: - - 140 - - name: var-naming - arguments: - - [] - - - CID - - CRI - - CTRD - - DACL - - DLL - - DOS - - ETW - - FSCTL - - GCS - - GMSA - - HCS - - HV - - IO - - LCOW - - LDAP - - LPAC - - LTSC - - MMIO - - NT - - OCI - - PMEM - - PWSH - - RX - - SACl - - SID - - SMB - - TX - - VHD - - VHDX - - VMID - - VPCI - - WCOW - - WIM + # err is very often shadowed in nested scopes + - linters: + - govet + text: '^shadow: declaration of "err" shadows declaration' + + # ignore long lines for skip autogen directives + - linters: + - revive + text: "^line-length-limit: " + source: "^//(go:generate|sys) " + + # ignore comment spacing for sys directives + - linters: + - revive + text: "^comment-spacings: no space between comment delimiter and comment text" + source: "//(cspell:|sys )" + + # allow unjustified ignores of error checks in defer statements + - linters: + - nolintlint + text: "^directive `//nolint:errcheck` should provide explanation" + source: '^\s*defer ' + + # allow unjustified ignores of error lints for io.EOF + - linters: + - nolintlint + text: "^directive `//nolint:errorlint` should provide explanation" + source: '[=|!]= io.EOF' + + - linters: + - gosec + text: "^G115: integer overflow conversion" + + + settings: + exhaustive: + default-signifies-exhaustive: true + gocritic: + disable-all: true + enabled-checks: + - nilValReturn + - sprintfQuotedString + govet: + enable-all: true + disable: + # struct order is often for Win32 compat + # also, ignore pointer bytes/GC issues for now until performance becomes an issue + - fieldalignment + nolintlint: + require-explanation: true + require-specific: true + revive: + # revive is more configurable than static check, so likely the preferred alternative to static-check + # (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997) + enable-all-rules: + true + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md + rules: + # rules with required arguments + - name: argument-limit + disabled: true + - name: banned-characters + disabled: true + - name: cognitive-complexity + disabled: true + - name: cyclomatic + disabled: true + # covered by "exhaustive" linter + - name: enforce-switch-style + disabled: true + - name: file-header + disabled: true + - name: function-length + disabled: true + - name: function-result-limit + disabled: true + - name: max-public-structs + disabled: true + # generally annoying rules + - name: add-constant # complains about any and all strings and integers + disabled: true + - name: confusing-naming # we frequently use "Foo()" and "foo()" together + disabled: true + - name: flag-parameter # excessive, and a common idiom we use + disabled: true + - name: multiline-if-init # too opinionated; see https://github.com/microsoft/go-winio/pull/325#issuecomment-5822487436 + disabled: true + - name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead + disabled: true + # general config + - name: line-length-limit + arguments: + - 140 + - name: var-naming + arguments: + - [] + - - CID + - CRI + - CTRD + - DACL + - DLL + - DOS + - ETW + - FSCTL + - GCS + - GMSA + - HCS + - HV + - IO + - LCOW + - LDAP + - LPAC + - LTSC + - MMIO + - NT + - OCI + - PMEM + - PWSH + - RX + - SACl + - SID + - SMB + - TX + - VHD + - VHDX + - VMID + - VPCI + - WCOW + - WIM + staticcheck: + # Enable all options, with some exceptions. + # For defaults, see https://golangci-lint.run/usage/linters/#staticcheck + checks: + - all + - -QF1008 # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008 + - -ST1003 # Poorly chosen identifier; https://staticcheck.dev/docs/checks/#ST1003 diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go index b54341daac..37055fa6a9 100644 --- a/vendor/github.com/Microsoft/go-winio/backup.go +++ b/vendor/github.com/Microsoft/go-winio/backup.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio @@ -36,7 +35,7 @@ const ( StreamSparseAttributes = uint32(8) ) -//nolint:revive // var-naming: ALL_CAPS +//nolint:revive,nolintlint // var-naming: ALL_CAPS const ( WRITE_DAC = windows.WRITE_DAC WRITE_OWNER = windows.WRITE_OWNER diff --git a/vendor/github.com/Microsoft/go-winio/ea.go b/vendor/github.com/Microsoft/go-winio/ea.go index e104dbdfdf..00a4bd96c8 100644 --- a/vendor/github.com/Microsoft/go-winio/ea.go +++ b/vendor/github.com/Microsoft/go-winio/ea.go @@ -95,7 +95,7 @@ func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { return err } - _, err = buf.Write([]byte(ea.Name)) + _, err = buf.WriteString(ea.Name) if err != nil { return err } diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go index fe82a180db..19c5f8940e 100644 --- a/vendor/github.com/Microsoft/go-winio/file.go +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio @@ -235,12 +234,17 @@ func (f *win32File) Read(b []byte) (int, error) { runtime.KeepAlive(b) // Handle EOF conditions. - if err == nil && n == 0 && len(b) != 0 { - return 0, io.EOF - } else if err == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno + switch err { + case windows.ERROR_BROKEN_PIPE: //nolint:errorlint // err is Errno return 0, io.EOF + case nil: + if n == 0 && len(b) != 0 { + return 0, io.EOF + } + return n, nil + default: + return n, err } - return n, err } // Write writes to a file handle. diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go index c860eb9917..01cd891e84 100644 --- a/vendor/github.com/Microsoft/go-winio/fileinfo.go +++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go index c4fdd9d4ae..d4960f5b0a 100644 --- a/vendor/github.com/Microsoft/go-winio/hvsock.go +++ b/vendor/github.com/Microsoft/go-winio/hvsock.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go index 0cd9621df7..f3bc2aeb8a 100644 --- a/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go @@ -243,7 +243,7 @@ const ( // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) { b := stringbuffer.NewWString() - //TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n? + // TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n? for { n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags)) if err != nil { diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go index a94e234c70..f7b27abfcc 100644 --- a/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go index e1504126aa..06e84da653 100644 --- a/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go index 42ebc019fc..2295408733 100644 --- a/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go +++ b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go @@ -7,7 +7,7 @@ import ( // TODO: worth exporting and using in mkwinsyscall? -// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate +// MinWStringCap is the buffer size in the pool, chosen somewhat arbitrarily to accommodate // large path strings: // MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310. const MinWStringCap = 310 @@ -16,7 +16,7 @@ const MinWStringCap = 310 // is copied to heap and then referenced via pointer in the interface header that sync.Pool // stores. var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly - New: func() interface{} { + New: func() any { b := make([]uint16, MinWStringCap) return &b }, diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go index a2da6639d0..16a42584fc 100644 --- a/vendor/github.com/Microsoft/go-winio/pipe.go +++ b/vendor/github.com/Microsoft/go-winio/pipe.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio @@ -11,6 +10,7 @@ import ( "net" "os" "runtime" + "sync" "time" "unsafe" @@ -179,14 +179,15 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) { return 0, io.EOF } n, err := f.win32File.Read(b) - if err == io.EOF { //nolint:errorlint + switch err { + case io.EOF: //nolint:errorlint // error is not wrapped. // If this was the result of a zero-byte read, then // it is possible that the read was due to a zero-size // message. Since we are simulating CloseWrite with a // zero-byte message, ensure that all future Read() calls // also return EOF. f.readEOF = true - } else if err == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno + case windows.ERROR_MORE_DATA: // ERROR_MORE_DATA indicates that the pipe's read mode is message mode // and the message still has more bytes. Treat this as a success, since // this package presents all named pipes as byte streams. @@ -316,8 +317,9 @@ type win32PipeListener struct { path string config PipeConfig acceptCh chan (chan acceptResponse) - closeCh chan int - doneCh chan int + closeOnce sync.Once + closeCh chan struct{} // closed (never sent on) to broadcast listener shutdown + doneCh chan struct{} } func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (windows.Handle, error) { @@ -344,7 +346,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (wi // The security descriptor is only needed for the first pipe. if first { if sd != nil { - //todo: does `sdb` need to be allocated on the heap, or can go allocate it? + // todo: does `sdb` need to be allocated on the heap, or can go allocate it? l := uint32(len(sd)) sdb, err := windows.LocalAlloc(0, l) if err != nil { @@ -445,13 +447,14 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { p = nil } case <-l.closeCh: - // Abort the connect request by closing the handle. - p.Close() + // Abort the connect request by closing the handle. Listener closure is + // authoritative: ConnectNamedPipe may race the handle close and report a + // connection or error (e.g. ERROR_NO_DATA) instead of ErrFileClosed, and + // that result must not be surfaced or cause listenerRoutine to retry. + _ = p.Close() p = nil - err = <-ch - if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno - err = ErrPipeListenerClosed - } + <-ch + err = ErrPipeListenerClosed } return p, err } @@ -530,8 +533,8 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { path: path, config: *c, acceptCh: make(chan (chan acceptResponse)), - closeCh: make(chan int), - doneCh: make(chan int), + closeCh: make(chan struct{}), + doneCh: make(chan struct{}), } go l.listenerRoutine() return l, nil @@ -573,11 +576,10 @@ func (l *win32PipeListener) Accept() (net.Conn, error) { } func (l *win32PipeListener) Close() error { - select { - case l.closeCh <- 1: - <-l.doneCh - case <-l.doneCh: - } + l.closeOnce.Do(func() { + close(l.closeCh) + }) + <-l.doneCh return nil } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go index 48ce4e9243..fa1bde3a90 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go @@ -14,7 +14,7 @@ import ( "strconv" ) -//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment +//go:generate go tool stringer -type=Variant -trimprefix=Variant -linecomment // Variant specifies which GUID variant (or "type") of the GUID. It determines // how the entirety of the rest of the GUID is interpreted. diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go index 805bd35484..b933821a54 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package guid diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go index 27e45ee5cc..4aa95a7068 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package guid diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go index 4076d3132f..76e387d111 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go @@ -20,8 +20,9 @@ const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture" var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33} func (i Variant) String() string { - if i >= Variant(len(_Variant_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_Variant_index)-1 { return "Variant(" + strconv.FormatInt(int64(i), 10) + ")" } - return _Variant_name[_Variant_index[i]:_Variant_index[i+1]] + return _Variant_name[_Variant_index[idx]:_Variant_index[idx+1]] } diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go index d9b90b6e86..747eefd326 100644 --- a/vendor/github.com/Microsoft/go-winio/privilege.go +++ b/vendor/github.com/Microsoft/go-winio/privilege.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio diff --git a/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/go-winio/reparse.go index 67d1a104a6..9847fbd6c5 100644 --- a/vendor/github.com/Microsoft/go-winio/reparse.go +++ b/vendor/github.com/Microsoft/go-winio/reparse.go @@ -1,11 +1,11 @@ //go:build windows -// +build windows package winio import ( "bytes" "encoding/binary" + "errors" "fmt" "strings" "unicode/utf16" @@ -15,6 +15,9 @@ import ( const ( reparseTagMountPoint = 0xA0000003 reparseTagSymlink = 0xA000000C + reparseTagLxSymlink = 0xA000001D // WSL/MSYS2 native symlinks + + lxSymlinkVersion = 2 // LX symlink format version ) type reparseDataBuffer struct { @@ -31,6 +34,7 @@ type reparseDataBuffer struct { type ReparsePoint struct { Target string IsMountPoint bool + IsLxSymlink bool // True if this is an LX symlink (WSL/MSYS2 native) } // UnsupportedReparsePointError is returned when trying to decode a non-symlink or @@ -51,14 +55,19 @@ func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { } func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { - isMountPoint := false switch tag { case reparseTagMountPoint: - isMountPoint = true + return decodeWindowsReparsePointData(b, true) case reparseTagSymlink: + return decodeWindowsReparsePointData(b, false) + case reparseTagLxSymlink: + return decodeLxReparsePointData(b) default: return nil, &UnsupportedReparsePointError{tag} } +} + +func decodeWindowsReparsePointData(b []byte, isMountPoint bool) (*ReparsePoint, error) { nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) if !isMountPoint { nameOffset += 4 @@ -69,16 +78,56 @@ func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { if err != nil { return nil, err } - return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil + return &ReparsePoint{Target: string(utf16.Decode(name)), IsMountPoint: isMountPoint, IsLxSymlink: false}, nil +} + +func decodeLxReparsePointData(b []byte) (*ReparsePoint, error) { + // LX symlinks store the target as UTF-8 after a 4-byte version field + if len(b) < 4 { + return nil, errors.New("LX symlink buffer too short") + } + targetBytes := b[4:] + for i, c := range targetBytes { + if c == 0 { + targetBytes = targetBytes[:i] + break + } + } + target := string(targetBytes) + return &ReparsePoint{Target: target, IsMountPoint: false, IsLxSymlink: true}, nil } func isDriveLetter(c byte) bool { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') } -// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or -// mount point. +// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink, +// mount point, or LX symlink. func EncodeReparsePoint(rp *ReparsePoint) []byte { + if rp == nil { + return nil + } + if rp.IsLxSymlink { + return encodeLxReparsePoint(rp) + } + return encodeWindowsReparsePoint(rp) +} + +func encodeLxReparsePoint(rp *ReparsePoint) []byte { + // LX symlink: 4-byte version + UTF-8 target + targetBytes := []byte(rp.Target) + dataLength := 4 + len(targetBytes) + + var b bytes.Buffer + _ = binary.Write(&b, binary.LittleEndian, uint32(reparseTagLxSymlink)) + _ = binary.Write(&b, binary.LittleEndian, uint16(dataLength)) + _ = binary.Write(&b, binary.LittleEndian, uint16(0)) + _ = binary.Write(&b, binary.LittleEndian, uint32(lxSymlinkVersion)) + _, _ = b.Write(targetBytes) + return b.Bytes() +} + +func encodeWindowsReparsePoint(rp *ReparsePoint) []byte { // Generate an NT path and determine if this is a relative path. var ntTarget string relative := false diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go index c3685e98e1..7834c6adcb 100644 --- a/vendor/github.com/Microsoft/go-winio/sd.go +++ b/vendor/github.com/Microsoft/go-winio/sd.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package winio diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go index 89b66eda8c..f4329bbfd6 100644 --- a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/containerd/log/.gitattributes b/vendor/github.com/containerd/log/.gitattributes new file mode 100644 index 0000000000..6313b56c57 --- /dev/null +++ b/vendor/github.com/containerd/log/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/vendor/github.com/containerd/log/.golangci.yml b/vendor/github.com/containerd/log/.golangci.yml index a695775df4..5c3bdd766c 100644 --- a/vendor/github.com/containerd/log/.golangci.yml +++ b/vendor/github.com/containerd/log/.golangci.yml @@ -1,30 +1,50 @@ +version: "2" linters: enable: - - exportloopref # Checks for pointers to enclosing loop variables - - gofmt - - goimports + - copyloopvar + - dupword - gosec + - govet - ineffassign - misspell - nolintlint - revive - staticcheck - - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17 - unconvert - unused - - vet - - dupword # Checks for duplicate words in the source code disable: - errcheck + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - api + - cluster + - design + - docs + - docs/man + - releases + - reports + - test +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - api + - cluster + - design + - docs + - docs/man + - releases + - reports + - test run: timeout: 5m - skip-dirs: - - api - - cluster - - design - - docs - - docs/man - - releases - - reports - - test # e2e scripts diff --git a/vendor/github.com/containerd/log/context.go b/vendor/github.com/containerd/log/context.go index 20153066f3..e43ca0b100 100644 --- a/vendor/github.com/containerd/log/context.go +++ b/vendor/github.com/containerd/log/context.go @@ -40,8 +40,11 @@ package log import ( "context" "fmt" + "io" + "log/slog" "github.com/sirupsen/logrus" + lslog "github.com/sirupsen/logrus/hooks/slog" ) // G is a shorthand for [GetLogger]. @@ -108,10 +111,17 @@ const ( PanicLevel Level = logrus.PanicLevel ) -// SetLevel sets log level globally. It returns an error if the given -// level is not supported. +// levelValue is a log level accepted by [SetLevel]. +type levelValue interface { + string | Level | slog.Level | lslog.Level | lslog.SlogLevel +} + +// SetLevel sets the global log level. // -// level can be one of: +// The level may be specified as a string, a [Level], a [slog.Level], an +// [lslog.Level], or an [lslog.SlogLevel]. +// +// String levels are parsed using [logrus.ParseLevel] and may be one of: // // - "trace" ([TraceLevel]) // - "debug" ([DebugLevel]) @@ -120,10 +130,34 @@ const ( // - "error" ([ErrorLevel]) // - "fatal" ([FatalLevel]) // - "panic" ([PanicLevel]) -func SetLevel(level string) error { - lvl, err := logrus.ParseLevel(level) - if err != nil { - return err +// +// slog levels are mapped to Logrus levels using the mapping defined by +// [lslog.SlogLevel]. [lslog.Level] values are accepted directly as their +// underlying Logrus level. +// +// SetLevel returns an error if a string level is not supported. +func SetLevel[T levelValue](level T) error { + var lvl Level + + switch l := any(level).(type) { + case string: + var err error + lvl, err = logrus.ParseLevel(l) + if err != nil { + return err + } + + case Level: + lvl = l + + case slog.Level: + lvl = lslog.SlogLevel(l).Level() + + case lslog.Level: + lvl = Level(l) + + case lslog.SlogLevel: + lvl = l.Level() } L.Logger.SetLevel(lvl) @@ -149,21 +183,39 @@ const ( // SetFormat sets the log output format ([TextFormat] or [JSONFormat]). func SetFormat(format OutputFormat) error { + if slogOut != nil { + var handler slog.Handler + switch format { + case TextFormat: + handler = slog.NewTextHandler(slogOut, &slog.HandlerOptions{Level: loggerLevel{}}) + case JSONFormat: + handler = slog.NewJSONHandler(slogOut, &slog.HandlerOptions{Level: loggerLevel{}}) + default: + return fmt.Errorf("unknown log format: %s", format) + } + slog.SetDefault(slog.New(handler)) + + // Keep logrus formatting and output disabled, as both are handled by slog. + L.Logger.SetFormatter(discardFormatter{}) + L.Logger.SetOutput(io.Discard) + return nil + } + switch format { case TextFormat: L.Logger.SetFormatter(&logrus.TextFormatter{ TimestampFormat: RFC3339NanoFixed, FullTimestamp: true, }) - return nil case JSONFormat: L.Logger.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: RFC3339NanoFixed, }) - return nil default: return fmt.Errorf("unknown log format: %s", format) } + + return nil } // WithLogger returns a new context with the provided logger. Use in diff --git a/vendor/github.com/containerd/log/slog.go b/vendor/github.com/containerd/log/slog.go new file mode 100644 index 0000000000..6e230ca8ef --- /dev/null +++ b/vendor/github.com/containerd/log/slog.go @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package log + +import ( + "io" + "log/slog" + "sync" + + "github.com/sirupsen/logrus" + lslog "github.com/sirupsen/logrus/hooks/slog" +) + +// slogOut is used to set the slog logger when setting output format. +var slogOut io.Writer + +// slogOnce guards UseSlog so repeated calls do not stack up hooks or +// reset slogOut to the discard writer installed on the first call. +var slogOnce sync.Once + +func UseSlog() { + slogOnce.Do(func() { + L.Logger.SetNoLock() + L.Logger.AddHook(slogHook{}) + slogOut = L.Logger.Out + + // Disable logrus formatting and output, as both are handled by slog. + L.Logger.SetFormatter(discardFormatter{}) + L.Logger.SetOutput(io.Discard) + }) +} + +type slogHook struct{} + +func (slogHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (slogHook) Fire(entry *logrus.Entry) error { + return lslog.NewHook(slog.Default(), nil).Fire(entry) +} + +// loggerLevel exposes the current Logrus logger level as a slog.Leveler. +type loggerLevel struct{} + +func (loggerLevel) Level() slog.Level { + return lslog.Level(L.Logger.GetLevel()).Level() +} + +type discardFormatter struct{} + +func (discardFormatter) Format(*logrus.Entry) ([]byte, error) { return nil, nil } diff --git a/vendor/github.com/docker/go-connections/sockets/tcp_socket.go b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go index 53cbb6c79e..3224ed97dc 100644 --- a/vendor/github.com/docker/go-connections/sockets/tcp_socket.go +++ b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go @@ -9,13 +9,17 @@ import ( // NewTCPSocket creates a TCP socket listener with the specified address and // the specified tls configuration. If TLSConfig is set, will encapsulate the // TCP listener inside a TLS one. +// If no ALPN protocols are configured, it defaults to HTTP/1.1. func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } if tlsConfig != nil { - tlsConfig.NextProtos = []string{"http/1.1"} + if len(tlsConfig.NextProtos) == 0 { + tlsConfig = tlsConfig.Clone() + tlsConfig.NextProtos = []string{"http/1.1"} + } l = tls.NewListener(l, tlsConfig) } return l, nil diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 0e9f170d01..bf31b905f8 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -6,7 +6,9 @@ This package provides various compression algorithms. * [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy. * Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). * [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams. +* [lzw](https://github.com/klauspost/compress/tree/master/lzw) is a drop-in replacement for `compress/lzw` with 1.4-4x faster decompression and 1.1-2.7x faster compression, depending on the data. * [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding. +* [Xpress](https://github.com/klauspost/compress/tree/master/xpress) decompression of the Microsoft XPRESS (MS-XCA) plain LZ77 and LZ77+Huffman formats (the LZ77+Huffman variant is the one used in WIM images and Windows Compact OS / WOF data). * [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently. * [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation. diff --git a/vendor/github.com/klauspost/compress/huff0/bitreader.go b/vendor/github.com/klauspost/compress/huff0/bitreader.go index bfc7a523de..faaa418a75 100644 --- a/vendor/github.com/klauspost/compress/huff0/bitreader.go +++ b/vendor/github.com/klauspost/compress/huff0/bitreader.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "math/bits" "github.com/klauspost/compress/internal/le" ) @@ -210,6 +211,68 @@ func (b *bitReaderShifted) remaining() uint { return b.off*8 + uint(64-b.bitsRead) } +// canUseAsm reports whether the reader has a full 8-byte window ahead of +// its read pointer, which the Decompress4X asm loops need to take over. +func (b *bitReaderShifted) canUseAsm() bool { + return b.off >= 8 +} + +// prepareForAsm establishes the invariant the Decompress4X asm loops rely +// on: value == load64(in[off:off+8]) << bitsRead with bitsRead <= 7, so +// that a full group of symbols can never shift their sentinel bit out of +// the container. init leaves bitsRead == 8 when the final byte of the +// stream is exactly 0x01; that whole byte is consumed, so the same position +// is the window one byte lower with nothing consumed. Requires canUseAsm. +func (b *bitReaderShifted) prepareForAsm() { + if b.bitsRead >= 8 { + b.off-- + b.value = le.Load64(b.in, b.off) + b.bitsRead -= 8 + } +} + +// restoreFromAsm converts the state left behind by the Decompress4X asm +// loops back to the invariant the Go code relies on: value holds the 8 +// bytes at in[off:off+8] shifted left by bitsRead, with the low bitsRead +// bits zero. +// +// The asm keeps a sentinel bit in value just below the unread bits, so its +// trailing zero count is the number of consumed bits. The sentinel is ORed +// over the lowest bit of the window, which the loop never consumes before +// re-reading memory, so the window is re-read here too rather than taken +// from value. The asm reports off as the signed distance from the start of +// the stream, and it can be negative: a reload always reads a whole 8-byte +// window, so a stream that is nearly drained ends with up to 7 bytes of the +// previous stream (or the jump table) below its start inside the window. +// Those bytes sit below the stream's own bits and count as consumed. +// Anything further below, or more bits consumed than the stream holds, is +// corruption. +func (b *bitReaderShifted) restoreFromAsm() error { + off := int(b.off) + consumed := uint(bits.TrailingZeros64(b.value)) + if off < 0 { + if off < -7 { + return errors.New("corruption detected: stream underrun") + } + consumed += uint(-off) * 8 + if consumed > 64 { + return errors.New("corruption detected: stream underrun") + } + off = 0 + } + if off+8 > len(b.in) { + return errors.New("corruption detected: stream overrun") + } + b.off = uint(off) + b.bitsRead = uint8(consumed) + if consumed >= 64 { + b.value = 0 + } else { + b.value = le.Load64(b.in, b.off) << consumed + } + return nil +} + // close the bitstream and returns an error if out-of-buffer reads occurred. func (b *bitReaderShifted) close() error { // Release reference. diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go index 7035d656d9..e651f30ecb 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go @@ -8,36 +8,99 @@ import ( ) // decompress4x_main_loop_amd64 is an x86 assembler implementation -// of Decompress4X when tablelog > 8. +// of Decompress4X when tablelog > 8, decoding fastSymbols symbols per +// stream between bit container reloads. // //go:noescape func decompress4x_main_loop_amd64(ctx *decompress4xContext) // decompress4x_8b_main_loop_amd64 is an x86 assembler implementation -// of Decompress4X when tablelog <= 8 which decodes 4 entries -// per loop. +// of Decompress4X when tablelog <= 8, decoding fast8bSymbols symbols +// per stream between bit container reloads. // //go:noescape func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) +// decompress4x_4b_main_loop_amd64 is an x86 assembler implementation +// of Decompress4X when tablelog <= 4, decoding fast4bSymbols symbols +// per stream between bit container reloads. +// +//go:noescape +func decompress4x_4b_main_loop_amd64(ctx *decompress4xContext) + +// decompress4x_4b_main_loop_bmi2 is the BMI2 twin of decompress4x_4b_main_loop_amd64. +// +//go:noescape +func decompress4x_4b_main_loop_bmi2(ctx *decompress4xContext) + +// decompress4x_main_loop_bmi2 is the BMI2 twin of decompress4x_main_loop_amd64. +// +//go:noescape +func decompress4x_main_loop_bmi2(ctx *decompress4xContext) + +// decompress4x_8b_main_loop_bmi2 is the BMI2 twin of decompress4x_8b_main_loop_amd64. +// +//go:noescape +func decompress4x_8b_main_loop_bmi2(ctx *decompress4xContext) + // decompress1x_main_loop_amd64 is an x86 assembler implementation -// of Decompress1X when tablelog > 8. +// of Decompress1X when tablelog > 8, decoding fastSymbols symbols +// between bit container reloads. // //go:noescape func decompress1x_main_loop_amd64(ctx *decompress1xContext) -// decompress1x_main_loop_bmi2 is an x86 with BMI2 assembler implementation -// of Decompress1X when tablelog > 8. +// decompress1x_8b_main_loop_amd64 is an x86 assembler implementation +// of Decompress1X when tablelog <= 8, decoding fast8bSymbols symbols +// between bit container reloads. +// +//go:noescape +func decompress1x_8b_main_loop_amd64(ctx *decompress1xContext) + +// decompress1x_4b_main_loop_amd64 is an x86 assembler implementation +// of Decompress1X when tablelog <= 4, decoding fast4bSymbols symbols +// between bit container reloads. +// +//go:noescape +func decompress1x_4b_main_loop_amd64(ctx *decompress1xContext) + +// decompress1x_main_loop_bmi2 is the BMI2 twin of decompress1x_main_loop_amd64. // //go:noescape func decompress1x_main_loop_bmi2(ctx *decompress1xContext) +// decompress1x_8b_main_loop_bmi2 is the BMI2 twin of decompress1x_8b_main_loop_amd64. +// +//go:noescape +func decompress1x_8b_main_loop_bmi2(ctx *decompress1xContext) + +// decompress1x_4b_main_loop_bmi2 is the BMI2 twin of decompress1x_4b_main_loop_amd64. +// +//go:noescape +func decompress1x_4b_main_loop_bmi2(ctx *decompress1xContext) + func decompress4x_main_loop_asm(ctx *decompress4xContext) { - decompress4x_main_loop_amd64(ctx) + if cpuinfo.HasBMI2() { + decompress4x_main_loop_bmi2(ctx) + } else { + decompress4x_main_loop_amd64(ctx) + } } func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { - decompress4x_8b_main_loop_amd64(ctx) + if cpuinfo.HasBMI2() { + decompress4x_8b_main_loop_bmi2(ctx) + } else { + decompress4x_8b_main_loop_amd64(ctx) + } +} + +func decompress4x_4b_main_loop_asm(ctx *decompress4xContext) { + if cpuinfo.HasBMI2() { + decompress4x_4b_main_loop_bmi2(ctx) + } else { + decompress4x_4b_main_loop_amd64(ctx) + } } func decompress1x_main_loop_asm(ctx *decompress1xContext) { @@ -47,3 +110,19 @@ func decompress1x_main_loop_asm(ctx *decompress1xContext) { decompress1x_main_loop_amd64(ctx) } } + +func decompress1x_8b_main_loop_asm(ctx *decompress1xContext) { + if cpuinfo.HasBMI2() { + decompress1x_8b_main_loop_bmi2(ctx) + } else { + decompress1x_8b_main_loop_amd64(ctx) + } +} + +func decompress1x_4b_main_loop_asm(ctx *decompress1xContext) { + if cpuinfo.HasBMI2() { + decompress1x_4b_main_loop_bmi2(ctx) + } else { + decompress1x_4b_main_loop_amd64(ctx) + } +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s index c5d4a710a0..f072c18f04 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s @@ -3,828 +3,3384 @@ //go:build !appengine && !noasm && gc // func decompress4x_main_loop_amd64(ctx *decompress4xContext) +// Requires: BMI, CMOV TEXT ·decompress4x_main_loop_amd64(SB), $0-8 + MOVQ ctx+0(FP), AX + // Preload values - MOVQ ctx+0(FP), AX - MOVBQZX 8(AX), DI - MOVQ 16(AX), BX - MOVQ 48(AX), SI - MOVQ 24(AX), R8 - MOVQ 32(AX), R9 - MOVQ (AX), R10 + MOVBQZX 8(AX), DX + MOVQ 32(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), CX + LEAQ (SI)(CX*1), R8 + LEAQ (SI)(CX*2), R10 + LEAQ (CX)(CX*2), R12 + ADDQ SI, R12 - // Main loop -main_loop: - XORL DX, DX - CMPQ BX, SI - SETGE DL + // Convert each bit reader to sentinel form: bits = value | 1<> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - MOVW AX, (BX) + // stream 3, symbol 1 + MOVQ DX, CX + MOVQ R13, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R13 + SHRQ $0x08, CX + MOVB CL, 1(R12) - // update the bitreader structure - MOVQ R11, 32(R10) - MOVB R12, 40(R10) + // stream 0, symbol 2 + MOVQ DX, CX + MOVQ DI, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, DI + SHRQ $0x08, CX + MOVB CL, 2(SI) - // br1.fillFast32() - MOVQ 80(R10), R11 - MOVBQZX 88(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill1 - MOVQ 72(R10), AX - SUBQ $0x20, R12 - SUBQ $0x04, AX - MOVQ 48(R10), R13 + // stream 1, symbol 2 + MOVQ DX, CX + MOVQ R9, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R9 + SHRQ $0x08, CX + MOVB CL, 2(R8) - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (AX)(R13*1), R13 - MOVQ R12, CX - SHLQ CL, R13 - MOVQ AX, 72(R10) - ORQ R13, R11 + // stream 2, symbol 2 + MOVQ DX, CX + MOVQ R11, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R11 + SHRQ $0x08, CX + MOVB CL, 2(R10) - // exhausted += (br1.off < 4) - CMPQ AX, $0x04 - ADCB $+0, DL + // stream 3, symbol 2 + MOVQ DX, CX + MOVQ R13, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R13 + SHRQ $0x08, CX + MOVB CL, 2(R12) -skip_fill1: - // val0 := br1.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 0, symbol 3 + MOVQ DX, CX + MOVQ DI, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, DI + SHRQ $0x08, CX + MOVB CL, 3(SI) - // v0 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 1, symbol 3 + MOVQ DX, CX + MOVQ R9, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R9 + SHRQ $0x08, CX + MOVB CL, 3(R8) - // br1.advance(uint8(v0.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 + // stream 2, symbol 3 + MOVQ DX, CX + MOVQ R11, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R11 + SHRQ $0x08, CX + MOVB CL, 3(R10) - // val1 := br1.peekTopBits(peekBits) - MOVQ DI, CX - MOVQ R11, R13 - SHRQ CL, R13 + // stream 3, symbol 3 + MOVQ DX, CX + MOVQ R13, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R13 + SHRQ $0x08, CX + MOVB CL, 3(R12) - // v1 := table[val1&mask] - MOVW (R9)(R13*2), CX + // stream 0, symbol 4 + MOVQ DX, CX + MOVQ DI, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, DI + SHRQ $0x08, CX + MOVB CL, 4(SI) - // br1.advance(uint8(v1.entry)) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 + // stream 1, symbol 4 + MOVQ DX, CX + MOVQ R9, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R9 + SHRQ $0x08, CX + MOVB CL, 4(R8) - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - MOVW AX, (BX)(R8*1) + // stream 2, symbol 4 + MOVQ DX, CX + MOVQ R11, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R11 + SHRQ $0x08, CX + MOVB CL, 4(R10) - // update the bitreader structure - MOVQ R11, 80(R10) - MOVB R12, 88(R10) + // stream 3, symbol 4 + MOVQ DX, CX + MOVQ R13, R14 + SHRQ CL, R14 + MOVWQZX (BX)(R14*2), CX + SHLQ CL, R13 + SHRQ $0x08, CX + MOVB CL, 4(R12) - // br2.fillFast32() - MOVQ 128(R10), R11 - MOVBQZX 136(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill2 - MOVQ 120(R10), AX - SUBQ $0x20, R12 - SUBQ $0x04, AX - MOVQ 96(R10), R13 + // Reload the four bit containers + TZCNTQ DI, R14 + MOVQ R14, CX + ANDQ $0x07, CX + SHRQ $0x03, R14 + MOVQ 64(AX), DI + SUBQ R14, DI + MOVQ DI, 64(AX) + MOVQ (DI), DI + ORQ $0x01, DI + SHLQ CL, DI + TZCNTQ R9, R14 + MOVQ R14, CX + ANDQ $0x07, CX + SHRQ $0x03, R14 + MOVQ 72(AX), R9 + SUBQ R14, R9 + MOVQ R9, 72(AX) + MOVQ (R9), R9 + ORQ $0x01, R9 + SHLQ CL, R9 + TZCNTQ R11, R14 + MOVQ R14, CX + ANDQ $0x07, CX + SHRQ $0x03, R14 + MOVQ 80(AX), R11 + SUBQ R14, R11 + MOVQ R11, 80(AX) + MOVQ (R11), R11 + ORQ $0x01, R11 + SHLQ CL, R11 + TZCNTQ R13, R14 + MOVQ R14, CX + ANDQ $0x07, CX + SHRQ $0x03, R14 + MOVQ 88(AX), R13 + SUBQ R14, R13 + MOVQ R13, 88(AX) + MOVQ (R13), R13 + ORQ $0x01, R13 + SHLQ CL, R13 + ADDQ $0x05, SI + ADDQ $0x05, R8 + ADDQ $0x05, R10 + ADDQ $0x05, R12 + CMPQ SI, 96(AX) + JB inner_loop + JMP outer_loop - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (AX)(R13*1), R13 - MOVQ R12, CX - SHLQ CL, R13 - MOVQ AX, 120(R10) - ORQ R13, R11 - - // exhausted += (br2.off < 4) - CMPQ AX, $0x04 - ADCB $+0, DL - -skip_fill2: - // val0 := br2.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 - - // v0 := table[val0&mask] - MOVW (R9)(R13*2), CX - - // br2.advance(uint8(v0.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 - - // val1 := br2.peekTopBits(peekBits) - MOVQ DI, CX - MOVQ R11, R13 - SHRQ CL, R13 - - // v1 := table[val1&mask] - MOVW (R9)(R13*2), CX - - // br2.advance(uint8(v1.entry)) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - MOVW AX, (BX)(R8*2) - - // update the bitreader structure - MOVQ R11, 128(R10) - MOVB R12, 136(R10) - - // br3.fillFast32() - MOVQ 176(R10), R11 - MOVBQZX 184(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill3 - MOVQ 168(R10), AX - SUBQ $0x20, R12 - SUBQ $0x04, AX - MOVQ 144(R10), R13 - - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (AX)(R13*1), R13 - MOVQ R12, CX - SHLQ CL, R13 - MOVQ AX, 168(R10) - ORQ R13, R11 - - // exhausted += (br3.off < 4) - CMPQ AX, $0x04 - ADCB $+0, DL - -skip_fill3: - // val0 := br3.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 - - // v0 := table[val0&mask] - MOVW (R9)(R13*2), CX - - // br3.advance(uint8(v0.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 - - // val1 := br3.peekTopBits(peekBits) - MOVQ DI, CX - MOVQ R11, R13 - SHRQ CL, R13 - - // v1 := table[val1&mask] - MOVW (R9)(R13*2), CX - - // br3.advance(uint8(v1.entry)) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - LEAQ (R8)(R8*2), CX - MOVW AX, (BX)(CX*1) - - // update the bitreader structure - MOVQ R11, 176(R10) - MOVB R12, 184(R10) - ADDQ $0x02, BX - TESTB DL, DL - JZ main_loop - MOVQ ctx+0(FP), AX - SUBQ 16(AX), BX - SHLQ $0x02, BX - MOVQ BX, 40(AX) +done: + // Hand the state back: off = ip - in (negative when the window reached below the stream start), + // value = the sentinel-form container. bitReaderShifted.restoreFromAsm normalizes both. + MOVQ (AX), CX + MOVQ 64(AX), DX + SUBQ (CX), DX + MOVQ DX, 24(CX) + MOVQ DI, 32(CX) + MOVQ 72(AX), DX + SUBQ 48(CX), DX + MOVQ DX, 72(CX) + MOVQ R9, 80(CX) + MOVQ 80(AX), DX + SUBQ 96(CX), DX + MOVQ DX, 120(CX) + MOVQ R11, 128(CX) + MOVQ 88(AX), DX + SUBQ 144(CX), DX + MOVQ DX, 168(CX) + MOVQ R13, 176(CX) + SUBQ 16(AX), SI + SHLQ $0x02, SI + MOVQ SI, 40(AX) RET // func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) +// Requires: BMI, CMOV TEXT ·decompress4x_8b_main_loop_amd64(SB), $0-8 + MOVQ ctx+0(FP), AX + // Preload values - MOVQ ctx+0(FP), CX - MOVBQZX 8(CX), DI - MOVQ 16(CX), BX - MOVQ 48(CX), SI - MOVQ 24(CX), R8 - MOVQ 32(CX), R9 - MOVQ (CX), R10 + MOVBQZX 8(AX), DX + MOVQ 32(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), CX + LEAQ (SI)(CX*1), R8 + LEAQ (SI)(CX*2), R10 + LEAQ (CX)(CX*2), R12 + ADDQ SI, R12 - // Main loop -main_loop: - XORL DX, DX - CMPQ BX, SI - SETGE DL + // Convert each bit reader to sentinel form: bits = value | 1<> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - MOVL AX, (BX) +done: + // Hand the state back: off = ip - in (negative when the window reached below the stream start), + // value = the sentinel-form container. bitReaderShifted.restoreFromAsm normalizes both. + MOVQ (AX), CX + MOVQ 64(AX), DX + SUBQ (CX), DX + MOVQ DX, 24(CX) + MOVQ DI, 32(CX) + MOVQ 72(AX), DX + SUBQ 48(CX), DX + MOVQ DX, 72(CX) + MOVQ R9, 80(CX) + MOVQ 80(AX), DX + SUBQ 96(CX), DX + MOVQ DX, 120(CX) + MOVQ R11, 128(CX) + MOVQ 88(AX), DX + SUBQ 144(CX), DX + MOVQ DX, 168(CX) + MOVQ R13, 176(CX) + SUBQ 16(AX), SI + SHLQ $0x02, SI + MOVQ SI, 40(AX) + RET - // update the bitreader structure - MOVQ R11, 32(R10) - MOVB R12, 40(R10) +// func decompress4x_main_loop_bmi2(ctx *decompress4xContext) +// Requires: BMI, BMI2, CMOV +TEXT ·decompress4x_main_loop_bmi2(SB), $0-8 + MOVQ ctx+0(FP), AX - // br1.fillFast32() - MOVQ 80(R10), R11 - MOVBQZX 88(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill1 - MOVQ 72(R10), R13 - SUBQ $0x20, R12 - SUBQ $0x04, R13 - MOVQ 48(R10), R14 + // Preload values + MOVBQZX 8(AX), CX + MOVQ 32(AX), DX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + LEAQ (BX)(SI*1), DI + LEAQ (BX)(SI*2), R9 + LEAQ (SI)(SI*2), R11 + ADDQ BX, R11 - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (R13)(R14*1), R14 - MOVQ R12, CX - SHLQ CL, R14 - MOVQ R13, 72(R10) - ORQ R14, R11 + // Convert each bit reader to sentinel form: bits = value | 1<> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - MOVL AX, (BX)(R8*1) + // stream 3, symbol 2 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 2(R11) - // update the bitreader structure - MOVQ R11, 80(R10) - MOVB R12, 88(R10) + // stream 0, symbol 3 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 3(BX) - // br2.fillFast32() - MOVQ 128(R10), R11 - MOVBQZX 136(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill2 - MOVQ 120(R10), R13 - SUBQ $0x20, R12 - SUBQ $0x04, R13 - MOVQ 96(R10), R14 + // stream 1, symbol 3 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 3(DI) - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (R13)(R14*1), R14 - MOVQ R12, CX - SHLQ CL, R14 - MOVQ R13, 120(R10) - ORQ R14, R11 + // stream 2, symbol 3 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 3(R9) - // exhausted += (br2.off < 4) - CMPQ R13, $0x04 - ADCB $+0, DL + // stream 3, symbol 3 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 3(R11) -skip_fill2: - // val0 := br2.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 0, symbol 4 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 4(BX) - // v0 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 1, symbol 4 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 4(DI) - // br2.advance(uint8(v0.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 + // stream 2, symbol 4 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 4(R9) - // val1 := br2.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 3, symbol 4 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 4(R11) - // v1 := table[val0&mask] - MOVW (R9)(R13*2), CX + // Reload the four bit containers + TZCNTQ SI, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 64(AX), SI + SUBQ R13, SI + MOVQ SI, 64(AX) + MOVQ (SI), SI + ORQ $0x01, SI + SHLXQ R14, SI, SI + TZCNTQ R8, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 72(AX), R8 + SUBQ R13, R8 + MOVQ R8, 72(AX) + MOVQ (R8), R8 + ORQ $0x01, R8 + SHLXQ R14, R8, R8 + TZCNTQ R10, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 80(AX), R10 + SUBQ R13, R10 + MOVQ R10, 80(AX) + MOVQ (R10), R10 + ORQ $0x01, R10 + SHLXQ R14, R10, R10 + TZCNTQ R12, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 88(AX), R12 + SUBQ R13, R12 + MOVQ R12, 88(AX) + MOVQ (R12), R12 + ORQ $0x01, R12 + SHLXQ R14, R12, R12 + ADDQ $0x05, BX + ADDQ $0x05, DI + ADDQ $0x05, R9 + ADDQ $0x05, R11 + CMPQ BX, 96(AX) + JB inner_loop + JMP outer_loop - // br2.advance(uint8(v1.entry) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 - BSWAPL AX +done: + // Hand the state back: off = ip - in (negative when the window reached below the stream start), + // value = the sentinel-form container. bitReaderShifted.restoreFromAsm normalizes both. + MOVQ (AX), CX + MOVQ 64(AX), DX + SUBQ (CX), DX + MOVQ DX, 24(CX) + MOVQ SI, 32(CX) + MOVQ 72(AX), DX + SUBQ 48(CX), DX + MOVQ DX, 72(CX) + MOVQ R8, 80(CX) + MOVQ 80(AX), DX + SUBQ 96(CX), DX + MOVQ DX, 120(CX) + MOVQ R10, 128(CX) + MOVQ 88(AX), DX + SUBQ 144(CX), DX + MOVQ DX, 168(CX) + MOVQ R12, 176(CX) + SUBQ 16(AX), BX + SHLQ $0x02, BX + MOVQ BX, 40(AX) + RET - // val2 := br2.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 +// func decompress4x_8b_main_loop_bmi2(ctx *decompress4xContext) +// Requires: BMI, BMI2, CMOV +TEXT ·decompress4x_8b_main_loop_bmi2(SB), $0-8 + MOVQ ctx+0(FP), AX - // v2 := table[val0&mask] - MOVW (R9)(R13*2), CX + // Preload values + MOVBQZX 8(AX), CX + MOVQ 32(AX), DX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + LEAQ (BX)(SI*1), DI + LEAQ (BX)(SI*2), R9 + LEAQ (SI)(SI*2), R11 + ADDQ BX, R11 - // br2.advance(uint8(v2.entry) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 + // Convert each bit reader to sentinel form: bits = value | 1<> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - MOVL AX, (BX)(R8*2) + // stream 1, symbol 0 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, (DI) - // update the bitreader structure - MOVQ R11, 128(R10) - MOVB R12, 136(R10) + // stream 2, symbol 0 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, (R9) - // br3.fillFast32() - MOVQ 176(R10), R11 - MOVBQZX 184(R10), R12 - CMPQ R12, $0x20 - JBE skip_fill3 - MOVQ 168(R10), R13 - SUBQ $0x20, R12 - SUBQ $0x04, R13 - MOVQ 144(R10), R14 + // stream 3, symbol 0 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, (R11) - // b.value |= uint64(low) << (b.bitsRead & 63) - MOVL (R13)(R14*1), R14 - MOVQ R12, CX - SHLQ CL, R14 - MOVQ R13, 168(R10) - ORQ R14, R11 + // stream 0, symbol 1 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 1(BX) - // exhausted += (br3.off < 4) - CMPQ R13, $0x04 - ADCB $+0, DL + // stream 1, symbol 1 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 1(DI) -skip_fill3: - // val0 := br3.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 2, symbol 1 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 1(R9) - // v0 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 3, symbol 1 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 1(R11) - // br3.advance(uint8(v0.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 + // stream 0, symbol 2 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 2(BX) - // val1 := br3.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 1, symbol 2 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 2(DI) - // v1 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 2, symbol 2 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 2(R9) - // br3.advance(uint8(v1.entry) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 - BSWAPL AX + // stream 3, symbol 2 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 2(R11) - // val2 := br3.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 0, symbol 3 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 3(BX) - // v2 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 1, symbol 3 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 3(DI) - // br3.advance(uint8(v2.entry) - MOVB CH, AH - SHLQ CL, R11 - ADDB CL, R12 + // stream 2, symbol 3 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 3(R9) - // val3 := br3.peekTopBits(peekBits) - MOVQ R11, R13 - MOVQ DI, CX - SHRQ CL, R13 + // stream 3, symbol 3 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 3(R11) - // v3 := table[val0&mask] - MOVW (R9)(R13*2), CX + // stream 0, symbol 4 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 4(BX) - // br3.advance(uint8(v3.entry) - MOVB CH, AL - SHLQ CL, R11 - ADDB CL, R12 - BSWAPL AX + // stream 1, symbol 4 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 4(DI) - // these four writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - LEAQ (R8)(R8*2), CX - MOVL AX, (BX)(CX*1) + // stream 2, symbol 4 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 4(R9) - // update the bitreader structure - MOVQ R11, 176(R10) - MOVB R12, 184(R10) - ADDQ $0x04, BX - TESTB DL, DL - JZ main_loop - MOVQ ctx+0(FP), AX - SUBQ 16(AX), BX - SHLQ $0x02, BX - MOVQ BX, 40(AX) + // stream 3, symbol 4 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 4(R11) + + // stream 0, symbol 5 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 5(BX) + + // stream 1, symbol 5 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 5(DI) + + // stream 2, symbol 5 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 5(R9) + + // stream 3, symbol 5 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 5(R11) + + // stream 0, symbol 6 + SHRXQ CX, SI, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, SI, SI + SHRQ $0x08, R13 + MOVB R13, 6(BX) + + // stream 1, symbol 6 + SHRXQ CX, R8, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R8, R8 + SHRQ $0x08, R13 + MOVB R13, 6(DI) + + // stream 2, symbol 6 + SHRXQ CX, R10, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R10, R10 + SHRQ $0x08, R13 + MOVB R13, 6(R9) + + // stream 3, symbol 6 + SHRXQ CX, R12, R13 + MOVWQZX (DX)(R13*2), R13 + SHLXQ R13, R12, R12 + SHRQ $0x08, R13 + MOVB R13, 6(R11) + + // Reload the four bit containers + TZCNTQ SI, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 64(AX), SI + SUBQ R13, SI + MOVQ SI, 64(AX) + MOVQ (SI), SI + ORQ $0x01, SI + SHLXQ R14, SI, SI + TZCNTQ R8, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 72(AX), R8 + SUBQ R13, R8 + MOVQ R8, 72(AX) + MOVQ (R8), R8 + ORQ $0x01, R8 + SHLXQ R14, R8, R8 + TZCNTQ R10, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 80(AX), R10 + SUBQ R13, R10 + MOVQ R10, 80(AX) + MOVQ (R10), R10 + ORQ $0x01, R10 + SHLXQ R14, R10, R10 + TZCNTQ R12, R13 + MOVQ R13, R14 + ANDQ $0x07, R14 + SHRQ $0x03, R13 + MOVQ 88(AX), R12 + SUBQ R13, R12 + MOVQ R12, 88(AX) + MOVQ (R12), R12 + ORQ $0x01, R12 + SHLXQ R14, R12, R12 + ADDQ $0x07, BX + ADDQ $0x07, DI + ADDQ $0x07, R9 + ADDQ $0x07, R11 + CMPQ BX, 96(AX) + JB inner_loop + JMP outer_loop + +done: + // Hand the state back: off = ip - in (negative when the window reached below the stream start), + // value = the sentinel-form container. bitReaderShifted.restoreFromAsm normalizes both. + MOVQ (AX), CX + MOVQ 64(AX), DX + SUBQ (CX), DX + MOVQ DX, 24(CX) + MOVQ SI, 32(CX) + MOVQ 72(AX), DX + SUBQ 48(CX), DX + MOVQ DX, 72(CX) + MOVQ R8, 80(CX) + MOVQ 80(AX), DX + SUBQ 96(CX), DX + MOVQ DX, 120(CX) + MOVQ R10, 128(CX) + MOVQ 88(AX), DX + SUBQ 144(CX), DX + MOVQ DX, 168(CX) + MOVQ R12, 176(CX) + SUBQ 16(AX), BX + SHLQ $0x02, BX + MOVQ BX, 40(AX) + RET + +// func decompress4x_4b_main_loop_bmi2(ctx *decompress4xContext) +// Requires: BMI, BMI2, CMOV +TEXT ·decompress4x_4b_main_loop_bmi2(SB), $0-8 + MOVQ ctx+0(FP), AX + + // Preload values + MOVBQZX 8(AX), CX + MOVQ 32(AX), DX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + LEAQ (BX)(SI*1), DI + LEAQ (BX)(SI*2), R9 + LEAQ (SI)(SI*2), R11 + ADDQ BX, R11 + + // Convert each bit reader to sentinel form: bits = value | 1< 8. +// of Decompress4X when tablelog > 8, decoding fastSymbols symbols per +// stream between bit container reloads. // //go:noescape func decompress4x_main_loop_arm64(ctx *decompress4xContext) // decompress4x_8b_main_loop_arm64 is an arm64 assembler implementation -// of Decompress4X when tablelog <= 8 which decodes 4 entries -// per loop. +// of Decompress4X when tablelog <= 8, decoding fast8bSymbols symbols +// per stream between bit container reloads. // //go:noescape func decompress4x_8b_main_loop_arm64(ctx *decompress4xContext) +// decompress4x_4b_main_loop_arm64 is an arm64 assembler implementation +// of Decompress4X when tablelog <= 4, decoding fast4bSymbols symbols +// per stream between bit container reloads. +// +//go:noescape +func decompress4x_4b_main_loop_arm64(ctx *decompress4xContext) + // decompress1x_main_loop_arm64 is an arm64 assembler implementation -// of Decompress1X when tablelog > 8. +// of Decompress1X when tablelog > 8, decoding fastSymbols symbols +// between bit container reloads. // //go:noescape func decompress1x_main_loop_arm64(ctx *decompress1xContext) +// decompress1x_8b_main_loop_arm64 is an arm64 assembler implementation +// of Decompress1X when tablelog <= 8, decoding fast8bSymbols symbols +// between bit container reloads. +// +//go:noescape +func decompress1x_8b_main_loop_arm64(ctx *decompress1xContext) + +// decompress1x_4b_main_loop_arm64 is an arm64 assembler implementation +// of Decompress1X when tablelog <= 4, decoding fast4bSymbols symbols +// between bit container reloads. +// +//go:noescape +func decompress1x_4b_main_loop_arm64(ctx *decompress1xContext) + func decompress4x_main_loop_asm(ctx *decompress4xContext) { decompress4x_main_loop_arm64(ctx) } @@ -32,6 +55,18 @@ func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { decompress4x_8b_main_loop_arm64(ctx) } +func decompress4x_4b_main_loop_asm(ctx *decompress4xContext) { + decompress4x_4b_main_loop_arm64(ctx) +} + func decompress1x_main_loop_asm(ctx *decompress1xContext) { decompress1x_main_loop_arm64(ctx) } + +func decompress1x_8b_main_loop_asm(ctx *decompress1xContext) { + decompress1x_8b_main_loop_arm64(ctx) +} + +func decompress1x_4b_main_loop_asm(ctx *decompress1xContext) { + decompress1x_4b_main_loop_arm64(ctx) +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s index e16012721a..971b8eb8bd 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s +++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s @@ -1,851 +1,1657 @@ // Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT. // EXPERIMENTAL arm64 output lowered from an amd64 avo program. -//go:build arm64 && !appengine && !noasm && gc +//go:build arm64 && (!appengine && !noasm && gc) // func decompress4x_main_loop_amd64(ctx *decompress4xContext) +// Requires: BMI, CMOV TEXT ·decompress4x_main_loop_arm64(SB), $0-8 - // Preload values - MOVD ctx+0(FP), R0 - MOVBU 8(R0), R6 - MOVD 16(R0), R3 - MOVD 48(R0), R5 - MOVD 24(R0), R7 - MOVD 32(R0), R8 - MOVD (R0), R9 - - // Main loop -main_loop: - MOVD $0, R2 - CMP R5, R3 - CSET GE, R16 - BFI $0, R16, $8, R2 - - // br0.fillFast32() - MOVD 32(R9), R10 - MOVBU 40(R9), R11 - CMP $0x20, R11 - BLS skip_fill0 - MOVD 24(R9), R0 - SUB $0x20, R11, R11 - SUB $0x04, R0, R0 - MOVD (R9), R12 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R12, R0, R15 - MOVWU (R15), R12 - MOVD R11, R1 - LSL R1, R12, R12 - MOVD R0, 24(R9) - ORR R12, R10, R10 - - // exhausted += (br0.off < 4) - CMP $0x04, R0 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill0: - // val0 := br0.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br0.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br0.peekTopBits(peekBits) - MOVD R6, R1 - MOVD R10, R12 - LSR R1, R12, R12 - - // v1 := table[val1&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br0.advance(uint8(v1.entry)) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - MOVH R0, (R3) - - // update the bitreader structure - MOVD R10, 32(R9) - MOVB R11, 40(R9) - - // br1.fillFast32() - MOVD 80(R9), R10 - MOVBU 88(R9), R11 - CMP $0x20, R11 - BLS skip_fill1 - MOVD 72(R9), R0 - SUB $0x20, R11, R11 - SUB $0x04, R0, R0 - MOVD 48(R9), R12 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R12, R0, R15 - MOVWU (R15), R12 - MOVD R11, R1 - LSL R1, R12, R12 - MOVD R0, 72(R9) - ORR R12, R10, R10 - - // exhausted += (br1.off < 4) - CMP $0x04, R0 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill1: - // val0 := br1.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br1.peekTopBits(peekBits) - MOVD R6, R1 - MOVD R10, R12 - LSR R1, R12, R12 - - // v1 := table[val1&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v1.entry)) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - ADD R7, R3, R15 - MOVH R0, (R15) - - // update the bitreader structure - MOVD R10, 80(R9) - MOVB R11, 88(R9) - - // br2.fillFast32() - MOVD 128(R9), R10 - MOVBU 136(R9), R11 - CMP $0x20, R11 - BLS skip_fill2 - MOVD 120(R9), R0 - SUB $0x20, R11, R11 - SUB $0x04, R0, R0 - MOVD 96(R9), R12 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R12, R0, R15 - MOVWU (R15), R12 - MOVD R11, R1 - LSL R1, R12, R12 - MOVD R0, 120(R9) - ORR R12, R10, R10 - - // exhausted += (br2.off < 4) - CMP $0x04, R0 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill2: - // val0 := br2.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br2.peekTopBits(peekBits) - MOVD R6, R1 - MOVD R10, R12 - LSR R1, R12, R12 - - // v1 := table[val1&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v1.entry)) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - ADD R7<<1, R3, R15 - MOVH R0, (R15) - - // update the bitreader structure - MOVD R10, 128(R9) - MOVB R11, 136(R9) - - // br3.fillFast32() - MOVD 176(R9), R10 - MOVBU 184(R9), R11 - CMP $0x20, R11 - BLS skip_fill3 - MOVD 168(R9), R0 - SUB $0x20, R11, R11 - SUB $0x04, R0, R0 - MOVD 144(R9), R12 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R12, R0, R15 - MOVWU (R15), R12 - MOVD R11, R1 - LSL R1, R12, R12 - MOVD R0, 168(R9) - ORR R12, R10, R10 - - // exhausted += (br3.off < 4) - CMP $0x04, R0 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill3: - // val0 := br3.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br3.peekTopBits(peekBits) - MOVD R6, R1 - MOVD R10, R12 - LSR R1, R12, R12 - - // v1 := table[val1&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v1.entry)) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // these two writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - ADD R7<<1, R7, R1 - ADD R1, R3, R15 - MOVH R0, (R15) - - // update the bitreader structure - MOVD R10, 176(R9) - MOVB R11, 184(R9) - ADD $0x02, R3, R3 - AND $0xff, R2, R15 - AND $0xff, R2, R16 - TST R16, R15 - BEQ main_loop MOVD ctx+0(FP), R0 + + // Preload values + MOVBU 8(R0), R2 + MOVD 32(R0), R3 + MOVD 16(R0), R5 + MOVD 24(R0), R1 + ADD R1, R5, R7 + ADD R1<<1, R5, R9 + ADD R1<<1, R1, R11 + ADD R5, R11, R11 + + // Convert each bit reader to sentinel form: bits = value | 1<> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - MOVW R0, (R3) - - // update the bitreader structure - MOVD R10, 32(R9) - MOVB R11, 40(R9) - - // br1.fillFast32() - MOVD 80(R9), R10 - MOVBU 88(R9), R11 - CMP $0x20, R11 - BLS skip_fill1 - MOVD 72(R9), R12 - SUB $0x20, R11, R11 - SUB $0x04, R12, R12 - MOVD 48(R9), R13 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R13, R12, R15 - MOVWU (R15), R13 - MOVD R11, R1 - LSL R1, R13, R13 - MOVD R12, 72(R9) - ORR R13, R10, R10 - - // exhausted += (br1.off < 4) - CMP $0x04, R12 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill1: - // val0 := br1.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br1.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v1 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v1.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // val2 := br1.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v2 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v2.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val3 := br1.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v3 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br1.advance(uint8(v3.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // these four writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - ADD R7, R3, R15 - MOVW R0, (R15) - - // update the bitreader structure - MOVD R10, 80(R9) - MOVB R11, 88(R9) - - // br2.fillFast32() - MOVD 128(R9), R10 - MOVBU 136(R9), R11 - CMP $0x20, R11 - BLS skip_fill2 - MOVD 120(R9), R12 - SUB $0x20, R11, R11 - SUB $0x04, R12, R12 - MOVD 96(R9), R13 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R13, R12, R15 - MOVWU (R15), R13 - MOVD R11, R1 - LSL R1, R13, R13 - MOVD R12, 120(R9) - ORR R13, R10, R10 - - // exhausted += (br2.off < 4) - CMP $0x04, R12 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill2: - // val0 := br2.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br2.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v1 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v1.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // val2 := br2.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v2 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v2.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val3 := br2.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v3 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br2.advance(uint8(v3.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // these four writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - ADD R7<<1, R3, R15 - MOVW R0, (R15) - - // update the bitreader structure - MOVD R10, 128(R9) - MOVB R11, 136(R9) - - // br3.fillFast32() - MOVD 176(R9), R10 - MOVBU 184(R9), R11 - CMP $0x20, R11 - BLS skip_fill3 - MOVD 168(R9), R12 - SUB $0x20, R11, R11 - SUB $0x04, R12, R12 - MOVD 144(R9), R13 - - // b.value |= uint64(low) << (b.bitsRead & 63) - ADD R13, R12, R15 - MOVWU (R15), R13 - MOVD R11, R1 - LSL R1, R13, R13 - MOVD R12, 168(R9) - ORR R13, R10, R10 - - // exhausted += (br3.off < 4) - CMP $0x04, R12 - CSINC HS, R2, R2, R16 - BFI $0, R16, $8, R2 - -skip_fill3: - // val0 := br3.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v0 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v0.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val1 := br3.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v1 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v1.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // val2 := br3.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v2 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v2.entry) - UBFX $8, R1, $8, R16 - BFI $8, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - - // val3 := br3.peekTopBits(peekBits) - MOVD R10, R12 - MOVD R6, R1 - LSR R1, R12, R12 - - // v3 := table[val0&mask] - ADD R12<<1, R8, R15 - MOVHU (R15), R1 - - // br3.advance(uint8(v3.entry) - UBFX $8, R1, $8, R16 - BFI $0, R16, $8, R0 - LSL R1, R10, R10 - ADD R1, R11, R15 - BFI $0, R15, $8, R11 - REVW R0, R0 - - // these four writes get coalesced - // out[id * dstEvery + 0] = uint8(v0.entry >> 8) - // out[id * dstEvery + 1] = uint8(v1.entry >> 8) - // out[id * dstEvery + 3] = uint8(v2.entry >> 8) - // out[id * dstEvery + 4] = uint8(v3.entry >> 8) - ADD R7<<1, R7, R1 - ADD R1, R3, R15 - MOVW R0, (R15) - - // update the bitreader structure - MOVD R10, 176(R9) - MOVB R11, 184(R9) - ADD $0x04, R3, R3 - AND $0xff, R2, R15 - AND $0xff, R2, R16 - TST R16, R15 - BEQ main_loop MOVD ctx+0(FP), R0 + + // Preload values + MOVBU 8(R0), R2 + MOVD 32(R0), R3 + MOVD 16(R0), R5 + MOVD 24(R0), R1 + ADD R1, R5, R7 + ADD R1<<1, R5, R9 + ADD R1<<1, R1, R11 + ADD R5, R11, R11 + + // Convert each bit reader to sentinel form: bits = value | 1< 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) { + nSyms := fastSymbols + if d.actualTableLog <= 4 { + nSyms = fast4bSymbols + } else if use8BitTables { + nSyms = fast8bSymbols + } + // The asm writes nSyms bytes per stream per iteration and only re-checks + // its bounds between batches of iterations (the batch size is derived + // from limit in _generate/gen.go), so stream 0 must stop early enough + // that stream 3 (which may be up to 3 bytes shorter than dstEvery) + // never writes past the end of out. Every stream needs a full 8-byte + // window ahead of its read pointer to enter the loop. + if limit := dstEvery - nSyms - 2; limit > 0 && br[0].canUseAsm() && br[1].canUseAsm() && br[2].canUseAsm() && br[3].canUseAsm() { + for i := range br { + br[i].prepareForAsm() + } ctx := decompress4xContext{ pbr: &br, peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() out: &out[0], dstEvery: dstEvery, tbl: &single[0], - limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last. + limit: &out[limit], + // The 6-byte jump table sits below stream 0 inside src, so the + // lowest window may reach into it; restoreFromAsm accounts for + // bytes below a stream's start. Bounding by src rather than by + // stream 0 keeps the asm running about six bytes longer, which + // matters for streams with very short codes. + ilowest: &src[0], } - if use8BitTables { + for i := range br { + ctx.ip[i] = &br[i].in[br[i].off] + } + switch nSyms { + case fast4bSymbols: + decompress4x_4b_main_loop_asm(&ctx) + case fast8bSymbols: decompress4x_8b_main_loop_asm(&ctx) - } else { + default: decompress4x_main_loop_asm(&ctx) } decoded = ctx.decoded out = out[decoded/4:] + for i := range br { + if err := br[i].restoreFromAsm(); err != nil { + return nil, err + } + } } // Decode remaining. @@ -128,18 +175,20 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { return dst, nil } +// decompress1xContext is the argument block of the Decompress1X asm loops. +// Go fills every field but decoded; the asm advances ip, and on return +// leaves the bit reader in the form bitReaderShifted.restoreFromAsm expects. type decompress1xContext struct { pbr *bitReaderShifted peekBits uint8 out *byte - outCap int + outCap int // no write reaches out[outCap] tbl *dEntrySingle decoded int + ilowest *byte // start of the stream; no read goes below it + ip *byte // the 8-byte input window, advanced by the asm } -// Error reported by asm implementations -const error_max_decoded_size_exeeded = -1 - // Decompress1X will decompress a 1X encoded stream. // The cap of the output buffer will be the maximum decompressed size. // The length of the supplied input must match the end of a block exactly. @@ -158,25 +207,36 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { const tlSize = 1 << tableLogMax const tlMask = tlSize - 1 - if maxDecodedSize >= 4 { + // The asm decodes whole batches of symbols and only re-checks its + // bounds between them, so it needs at least one batch of room (the + // output bound rounds nSyms up to 16, see _generate/gen.go) and a full + // 8-byte window ahead of the read pointer to enter the loop. It also + // needs at most 7 bits consumed on entry so that a batch cannot run + // the container dry, which prepareForAsm establishes. + decoded := 0 + if maxDecodedSize >= 16 && br.canUseAsm() { + br.prepareForAsm() ctx := decompress1xContext{ pbr: &br, out: &dst[0], outCap: maxDecodedSize, peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() tbl: &d.dt.single[0], + ilowest: &src[0], + ip: &br.in[br.off], } - - decompress1x_main_loop_asm(&ctx) - if ctx.decoded == error_max_decoded_size_exeeded { - return nil, ErrMaxDecodedSizeExceeded + if d.actualTableLog <= 4 { + decompress1x_4b_main_loop_asm(&ctx) + } else if d.actualTableLog <= 8 { + decompress1x_8b_main_loop_asm(&ctx) + } else { + decompress1x_main_loop_asm(&ctx) } - - dst = dst[:ctx.decoded] + decoded = ctx.decoded } + dst = dst[:decoded] - // br < 8, so uint8 is fine - bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead + bitsLeft := br.remaining() for bitsLeft > 0 { br.fill() if len(dst) >= maxDecodedSize { @@ -186,7 +246,7 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask] nBits := uint8(v.entry) br.advance(nBits) - bitsLeft -= nBits + bitsLeft -= uint(nBits) dst = append(dst, uint8(v.entry>>8)) } return dst, br.close() diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 51f9da0387..89b20d6a84 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -240,9 +240,11 @@ func (b *blockDec) decodeBuf(hist *history) error { b.dst[i] = v } hist.appendKeep(b.dst) + hist.decoders.consumeSyncLen(len(b.dst)) return nil case blockTypeRaw: hist.appendKeep(b.data) + hist.decoders.consumeSyncLen(len(b.data)) return nil case blockTypeCompressed: saved := b.dst @@ -487,6 +489,7 @@ func (b *blockDec) decodeCompressed(hist *history) error { } if hist.decoders.nSeqs == 0 { b.dst = append(b.dst, hist.decoders.literals...) + hist.decoders.consumeSyncLen(len(hist.decoders.literals)) return nil } before := len(hist.decoders.out) diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index c7e500f02a..90ef3bb03f 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -7,8 +7,11 @@ package zstd import ( "context" "encoding/binary" + "errors" "io" + "maps" "sync" + "sync/atomic" "github.com/klauspost/compress/zstd/internal/xxhash" ) @@ -20,7 +23,8 @@ import ( // A decoder can safely be re-used even if the previous stream failed. // To release the resources, you must call the Close() function on a decoder. type Decoder struct { - o decoderOptions + // publishedOptions contains the current immutable decoder options. + publishedOptions atomic.Pointer[decoderOptions] // Unreferenced decoders, ready for use. decoders chan *blockDec @@ -84,9 +88,10 @@ var ( func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) { initPredefined() var d Decoder - d.o.setDefault() - for _, o := range opts { - err := o(&d.o) + var o decoderOptions + o.setDefault() + for _, opt := range opts { + err := opt(&o) if err != nil { return nil, err } @@ -99,17 +104,19 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) { } // Initialize dict map if needed. - if d.o.dicts == nil { - d.o.dicts = make(map[uint32]*dict) + if o.dicts == nil { + o.dicts = make(map[uint32]*dict) } // Create decoders - d.decoders = make(chan *blockDec, d.o.concurrent) - for i := 0; i < d.o.concurrent; i++ { - dec := newBlockDec(d.o.lowMem) - dec.localFrame = newFrameDec(d.o) + d.decoders = make(chan *blockDec, o.concurrent) + for i := 0; i < o.concurrent; i++ { + dec := newBlockDec(o.lowMem) + dec.localFrame = newFrameDec(o) + dec.localFrame.o.dicts = nil d.decoders <- dec } + d.publishedOptions.Store(&o) if r == nil { return &d, nil @@ -171,6 +178,9 @@ func (d *Decoder) Reset(r io.Reader) error { d.drainOutput() d.syncStream.br.r = nil + if d.frame != nil { + d.frame.o.dicts = nil + } if r == nil { d.current.err = ErrDecoderNilInput if len(d.current.b) > 0 { @@ -180,8 +190,10 @@ func (d *Decoder) Reset(r io.Reader) error { return nil } + o := *d.publishedOptions.Load() + // If bytes buffer and < 5MB, do sync decoding anyway. - if bb, ok := r.(byter); ok && bb.Len() < d.o.decodeBufsBelow && !d.o.limitToCap { + if bb, ok := r.(byter); ok && bb.Len() < o.decodeBufsBelow && !o.limitToCap { bb2 := bb if debugDecoder { println("*bytes.Buffer detected, doing sync decode, len:", bb.Len()) @@ -193,18 +205,30 @@ func (d *Decoder) Reset(r io.Reader) error { } dst, err := d.DecodeAll(b, dst) - if err == nil { - err = io.EOF + if !errors.Is(err, ErrDecoderSizeExceeded) { + if err == nil { + err = io.EOF + } + // Save output buffer + d.syncStream.dstBuf = dst + d.current.b = dst + d.current.err = err + d.current.flushed = true + if debugDecoder { + println("sync decode to", len(dst), "bytes, err:", err) + } + return nil } - // Save output buffer - d.syncStream.dstBuf = dst - d.current.b = dst - d.current.err = err - d.current.flushed = true + // The output does not fit WithDecoderMaxMemory, which caps the total + // decoded size when decoding in memory. A Reader follows the + // streaming contract, where the option caps the window instead, so + // decode this input as a stream after all; the shortcut has not + // consumed the reader. Drop the oversized buffer rather than keep it + // for reuse. if debugDecoder { - println("sync decode to", len(dst), "bytes, err:", err) + println("sync decode exceeded max memory after", len(dst), "bytes; streaming instead") } - return nil + d.syncStream.dstBuf = nil } // Remove current block. d.stashDecoder() @@ -217,14 +241,16 @@ func (d *Decoder) Reset(r io.Reader) error { // Ensure no-one else is still running... d.streamWg.Wait() if d.frame == nil { - d.frame = newFrameDec(d.o) + d.frame = newFrameDec(o) + } else { + d.frame.setOptions(o) } - if d.o.concurrent == 1 { + if o.concurrent == 1 { return d.startSyncDecoder(r) } - d.current.output = make(chan decodeOutput, d.o.concurrent) + d.current.output = make(chan decodeOutput, o.concurrent) ctx, cancel := context.WithCancel(context.Background()) d.current.cancel = cancel d.streamWg.Add(1) @@ -238,13 +264,21 @@ func (d *Decoder) Reset(r io.Reader) error { // Options are applied on top of the existing options. // Some options cannot be changed on reset and will return an error. func (d *Decoder) ResetWithOptions(r io.Reader, opts ...DOption) error { - d.o.resetOpt = true - defer func() { d.o.resetOpt = false }() + if d.current.err == ErrDecoderClosed { + return d.current.err + } + next := *d.publishedOptions.Load() + next.dicts = maps.Clone(next.dicts) + next.resetOpt = true for _, o := range opts { - if err := o(&d.o); err != nil { + if err := o(&next); err != nil { + next.resetOpt = false + d.publishedOptions.Store(&next) return err } } + next.resetOpt = false + d.publishedOptions.Store(&next) return d.Reset(r) } @@ -324,6 +358,8 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { // Grab a block decoder and frame decoder. block := <-d.decoders frame := block.localFrame + o := *d.publishedOptions.Load() + frame.setOptions(o) initialSize := len(dst) defer func() { if debugDecoder { @@ -335,6 +371,7 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { frame.history.decoders.br.in = nil frame.history.decoders.br.cursor = 0 } + frame.o.dicts = nil d.decoders <- block }() frame.bBuf = input @@ -354,20 +391,20 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { if err = d.setDict(frame); err != nil { return nil, err } - if frame.WindowSize > d.o.maxWindowSize { + if frame.WindowSize > frame.o.maxWindowSize { if debugDecoder { - println("window size exceeded:", frame.WindowSize, ">", d.o.maxWindowSize) + println("window size exceeded:", frame.WindowSize, ">", frame.o.maxWindowSize) } return dst, ErrWindowSizeExceeded } if frame.FrameContentSize != fcsUnknown { - if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)-initialSize) { + if frame.FrameContentSize > frame.o.maxDecodedSize-uint64(len(dst)-initialSize) { if debugDecoder { - println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", d.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst)) + println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", frame.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst)) } return dst, ErrDecoderSizeExceeded } - if d.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) { + if frame.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) { if debugDecoder { println("decoder size exceeded; fcs:", frame.FrameContentSize, "> (cap-len)", cap(dst)-len(dst)) } @@ -380,14 +417,14 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { } } - if cap(dst) == 0 && !d.o.limitToCap { + if cap(dst) == 0 && !frame.o.limitToCap { // Allocate len(input) * 2 by default if nothing is provided // and we didn't get frame content size. size := min( // Cap to 1 MB. len(input)*2, 1<<20) - if uint64(size) > d.o.maxDecodedSize { - size = int(d.o.maxDecodedSize) + if uint64(size) > frame.o.maxDecodedSize { + size = int(frame.o.maxDecodedSize) } dst = make([]byte, 0, size) } @@ -396,7 +433,7 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { if err != nil { return dst, err } - if uint64(len(dst)-initialSize) > d.o.maxDecodedSize { + if uint64(len(dst)-initialSize) > frame.o.maxDecodedSize { return dst, ErrDecoderSizeExceeded } if len(frame.bBuf) == 0 { @@ -459,7 +496,7 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) { println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp) } - if d.o.ignoreChecksum { + if d.frame.o.ignoreChecksum { return true } @@ -497,7 +534,7 @@ func (d *Decoder) nextBlockSync() (ok bool) { if d.current.err != nil { return false } - if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize { + if d.frame.WindowSize > d.frame.o.maxDecodedSize || d.frame.WindowSize > d.frame.o.maxWindowSize { d.current.err = ErrDecoderSizeExceeded return false } @@ -546,11 +583,11 @@ func (d *Decoder) nextBlockSync() (ok bool) { // Update/Check CRC if d.frame.HasCheckSum { - if !d.o.ignoreChecksum { + if !d.frame.o.ignoreChecksum { d.frame.crc.Write(d.current.b) } if d.current.d.Last { - if !d.o.ignoreChecksum { + if !d.frame.o.ignoreChecksum { d.current.err = d.frame.checkCRC() } else { d.current.err = d.frame.consumeCRC() @@ -656,8 +693,8 @@ func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output ch defer d.streamWg.Done() br := readerWrapper{r: r} - var seqDecode = make(chan *blockDec, d.o.concurrent) - var seqExecute = make(chan *blockDec, d.o.concurrent) + var seqDecode = make(chan *blockDec, d.frame.o.concurrent) + var seqExecute = make(chan *blockDec, d.frame.o.concurrent) // Async 1: Decode sequences... go func() { @@ -858,9 +895,9 @@ decodeStream: if err == nil { err = d.setDict(frame) } - if err == nil && d.frame.WindowSize > d.o.maxWindowSize { + if err == nil && d.frame.WindowSize > d.frame.o.maxWindowSize { if debugDecoder { - println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.o.maxWindowSize) + println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.frame.o.maxWindowSize) } err = ErrDecoderSizeExceeded @@ -940,7 +977,7 @@ decodeStream: } func (d *Decoder) setDict(frame *frameDec) (err error) { - dict, ok := d.o.dicts[frame.DictionaryID] + dict, ok := frame.o.dicts[frame.DictionaryID] if ok { if debugDecoder { println("setting dict", frame.DictionaryID) diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go index d88f067e5c..81d8b9c922 100644 --- a/vendor/github.com/klauspost/compress/zstd/framedec.go +++ b/vendor/github.com/klauspost/compress/zstd/framedec.go @@ -49,13 +49,16 @@ const ( ) func newFrameDec(o decoderOptions) *frameDec { + d := frameDec{} + d.setOptions(o) + return &d +} + +func (d *frameDec) setOptions(o decoderOptions) { if o.maxWindowSize > o.maxDecodedSize { o.maxWindowSize = o.maxDecodedSize } - d := frameDec{ - o: o, - } - return &d + d.o = o } // reset will read the frame header and prepare for block decoding. diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s index 77ee3913f0..8ca913eaec 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s @@ -1,7 +1,7 @@ // Code generated by command: go run gen_fse.go -out ../fse_decoder.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. // EXPERIMENTAL arm64 output lowered from an amd64 avo program. -//go:build arm64 && !appengine && !noasm && gc && !noasm +//go:build arm64 && (!appengine && !noasm && gc && !noasm) // func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int TEXT ·buildDtable_asm(SB), $0-24 @@ -26,11 +26,10 @@ TEXT ·buildDtable_asm(SB), $0-24 JMP init_main_loop_condition init_main_loop: - ADD R8<<1, R1, R15 - MOVH (R15), R9 - AND $0xffff, R9, R15 + MOVH (R1)(R8<<1), R9 MOVD $-1, R16 AND $0xffff, R16, R16 + AND $0xffff, R9, R15 CMP R16, R15 BNE do_not_update_high_threshold ADD R7<<3, R5, R15 @@ -39,8 +38,7 @@ init_main_loop: MOVD $0x0000000000000001, R9 do_not_update_high_threshold: - ADD R8<<1, R3, R15 - MOVH R9, (R15) + MOVH R9, (R3)(R8<<1) ADD $1, R8, R8 init_main_loop_condition: @@ -49,12 +47,10 @@ init_main_loop_condition: // Spread symbols // Calculate table step - MOVD R0, R8 - LSR $0x01, R8, R8 - MOVD R0, R9 - LSR $0x03, R9, R9 - ADD R9, R8, R8 - ADD $3, R8, R8 + LSR $0x01, R0, R8 + LSR $0x03, R0, R9 + ADD R9, R8, R8 + ADD $3, R8, R8 // Fill add bits values SUB $1, R0, R9 @@ -64,8 +60,7 @@ init_main_loop_condition: spread_main_loop: MOVD $0, R12 - ADD R11<<1, R1, R15 - MOVH (R15), R13 + MOVH (R1)(R11<<1), R13 JMP spread_inner_loop_condition spread_inner_loop: @@ -102,11 +97,9 @@ spread_check_ok: build_table_main_table: ADD R6<<3, R5, R15 MOVBU 1(R15), R1 - ADD R1<<1, R3, R15 - MOVHU (R15), R7 + MOVHU (R3)(R1<<1), R7 ADD $1, R7, R8 - ADD R1<<1, R3, R15 - MOVH R8, (R15) + MOVH R8, (R3)(R1<<1) MOVD R7, R8 CLZ R8, R16 MOVD $63, R8 @@ -129,12 +122,10 @@ build_table_main_table: RET build_table_check1_ok: - AND $0xff, R1, R15 - AND $0xff, R1, R16 - TST R16, R15 + TST $0xff, R1 BNE build_table_check2_ok - AND $0xffff, R7, R15 AND $0xffff, R6, R16 + AND $0xffff, R7, R15 CMP R16, R15 BNE build_table_check2_ok MOVD ctx+8(FP), R0 diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go index fc40c82001..9c0cbc1681 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go @@ -52,6 +52,11 @@ func (d *Digest) Reset() { d.n = 0 } +// maxAsmSize bounds the input handed to a single writeBlocks call. Assembly is +// never preemptible, so an unbounded call holds every P in stop-the-world for +// its duration. Whole 32-byte blocks, so Write can feed it in pieces. +const maxAsmSize = 128 << 10 // 4096 whole 32-byte blocks + // Size always returns 8 bytes. func (d *Digest) Size() int { return 8 } @@ -83,6 +88,13 @@ func (d *Digest) Write(b []byte) (n int, err error) { d.n = 0 } + for len(b) >= maxAsmSize { + // Assembly is not preemptible, so hashing a large buffer in one call + // blocks every stop-the-world for the whole call. Feed it in chunks. + writeBlocks(d, b[:maxAsmSize]) + b = b[maxAsmSize:] + } + if len(b) >= 32 { // One or more full blocks left. nw := writeBlocks(d, b) diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s index ddb63aa91b..e4c688efd3 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s @@ -175,7 +175,11 @@ finalize: RET // func writeBlocks(d *Digest, b []byte) int -TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 +// +// Deliberately not NOSPLIT: the stack check is the preemption point that lets a +// stop-the-world proceed between chunks. The frame must be >= abi.StackSmall +// (128), or the assembler marks this leaf NOSPLIT anyway and drops that check. +TEXT ·writeBlocks(SB), $128-40 // Load fixed primes needed for round. MOVQ ·primes+0(SB), prime1 MOVQ ·primes+8(SB), prime2 diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s index ae7d4d3295..e88cc2fc91 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s @@ -163,7 +163,11 @@ finalize: RET // func writeBlocks(s *Digest, b []byte) int -TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 +// +// Deliberately not NOSPLIT: the stack check is the preemption point that lets a +// stop-the-world proceed between chunks. The frame must be >= abi.StackSmall +// (128), or the assembler marks this leaf NOSPLIT anyway and drops that check. +TEXT ·writeBlocks(SB), $128-40 LDP ·primes+0(SB), (prime1, prime2) // Load state. Assume v[1-4] are stored contiguously. diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go index 0bfb0e43c7..d1a7732fcc 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go @@ -99,6 +99,29 @@ func (s *sequenceDecs) initialize(br *bitReader, hist *history, out []byte) erro return nil } +// consumeSyncLen accounts for n bytes of frame output produced outside +// decodeSync. maxSyncLen bounds how much the frame may still produce and +// decodeSyncSimple compares it with the output buffer's slack to decide +// whether the extended 16-byte copies are safe. Blocks with sequences +// subtracted their output; raw blocks, RLE blocks and compressed blocks +// holding only literals did not, so a frame that opened with a raw block +// overstated its remaining size for every block after it and ran the +// bounds-exact copies for the rest of the frame. +// +// Zero means "no bound" and selects the conservative paths, so a block that +// meets or exceeds the bound lands there; the frame-size checks in +// runDecoder reject the excess afterwards. +func (s *sequenceDecs) consumeSyncLen(n int) { + if s.maxSyncLen == 0 { + return + } + if uint64(n) >= s.maxSyncLen { + s.maxSyncLen = 0 + return + } + s.maxSyncLen -= uint64(n) +} + func (s *sequenceDecs) freeDecoders() { if f := s.litLengths.fse; f != nil && !f.preDefined { fseDecoderPool.Put(f) diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index 4d3188ff49..798d940231 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -4,7 +4,7 @@ // func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV -TEXT ·sequenceDecs_decode_amd64(SB), $8-32 +TEXT ·sequenceDecs_decode_amd64(SB), $40-32 MOVQ br+8(FP), CX MOVQ 24(CX), DX MOVBQZX 40(CX), BX @@ -16,6 +16,14 @@ TEXT ·sequenceDecs_decode_amd64(SB), $8-32 MOVQ 72(AX), DI MOVQ 80(AX), R8 MOVQ 88(AX), R9 + MOVQ (AX), CX + MOVQ CX, 8(SP) + MOVQ 24(AX), CX + MOVQ CX, 16(SP) + MOVQ 48(AX), CX + MOVQ CX, 24(SP) + MOVQ 96(AX), CX + MOVQ CX, 32(SP) MOVQ 104(AX), R10 MOVQ s+0(FP), AX MOVQ 144(AX), R11 @@ -55,46 +63,32 @@ sequenceDecs_decode_amd64_fill_check_overread: sequenceDecs_decode_amd64_fill_end: // Update offset - MOVQ R9, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_amd64_of_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_amd64_of_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_amd64_of_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_amd64_of_update_zero: - MOVQ AX, 16(R10) + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, 16(R10) // Update match length - MOVQ R8, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_amd64_ml_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_amd64_ml_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_amd64_ml_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_amd64_ml_update_zero: - MOVQ AX, 8(R10) + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, 8(R10) // Fill bitreader to have enough for the remaining CMPQ SI, $0x08 @@ -126,90 +120,76 @@ sequenceDecs_decode_amd64_fill_2_check_overread: sequenceDecs_decode_amd64_fill_2_end: // Update literal length - MOVQ DI, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_amd64_ll_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_amd64_ll_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_amd64_ll_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_amd64_ll_update_zero: - MOVQ AX, (R10) + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, (R10) // Fill bitreader for state updates MOVQ R14, (SP) MOVQ R9, AX SHRQ $0x08, AX MOVBQZX AL, AX - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decode_amd64_skip_update // Update Literal Length State MOVBQZX DI, R14 SHRL $0x10, DI - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, DI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(DI*8), DI // Update Match Length State MOVBQZX R8, R14 SHRL $0x10, R8 - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, R8 // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(R8*8), R8 // Update Offset State MOVBQZX R9, R14 SHRL $0x10, R9 - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, R9 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R9*8), R9 sequenceDecs_decode_amd64_skip_update: @@ -290,8 +270,7 @@ sequenceDecs_decode_amd64_after_adjust: sequenceDecs_decode_amd64_match_len_ofs_ok: ADDQ $0x18, R10 - MOVQ ctx+16(FP), AX - DECQ 96(AX) + DECQ 32(SP) JNS sequenceDecs_decode_amd64_main_loop MOVQ s+0(FP), AX MOVQ R11, 144(AX) @@ -303,36 +282,54 @@ sequenceDecs_decode_amd64_match_len_ofs_ok: MOVQ SI, 32(AX) // Return success + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000000, ret+24(FP) RET // Return with match length error sequenceDecs_decode_amd64_error_match_len_ofs_mismatch: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000001, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_amd64_error_match_len_too_big: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000002, ret+24(FP) RET // Return with match offset too long error + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000003, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000004, ret+24(FP) RET // Return with overread error error_overread: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000006, ret+24(FP) RET // func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV -TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32 +TEXT ·sequenceDecs_decode_56_amd64(SB), $40-32 MOVQ br+8(FP), CX MOVQ 24(CX), DX MOVBQZX 40(CX), BX @@ -344,6 +341,14 @@ TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32 MOVQ 72(AX), DI MOVQ 80(AX), R8 MOVQ 88(AX), R9 + MOVQ (AX), CX + MOVQ CX, 8(SP) + MOVQ 24(AX), CX + MOVQ CX, 16(SP) + MOVQ 48(AX), CX + MOVQ CX, 24(SP) + MOVQ 96(AX), CX + MOVQ CX, 32(SP) MOVQ 104(AX), R10 MOVQ s+0(FP), AX MOVQ 144(AX), R11 @@ -383,132 +388,104 @@ sequenceDecs_decode_56_amd64_fill_check_overread: sequenceDecs_decode_56_amd64_fill_end: // Update offset - MOVQ R9, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_56_amd64_of_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_56_amd64_of_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_56_amd64_of_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_56_amd64_of_update_zero: - MOVQ AX, 16(R10) + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, 16(R10) // Update match length - MOVQ R8, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_56_amd64_ml_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_56_amd64_ml_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_56_amd64_ml_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_56_amd64_ml_update_zero: - MOVQ AX, 8(R10) + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, 8(R10) // Update literal length - MOVQ DI, AX - MOVQ BX, CX - MOVQ DX, R15 - SHLQ CL, R15 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decode_56_amd64_ll_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decode_56_amd64_ll_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decode_56_amd64_ll_update_zero - NEGQ CX - SHRQ CL, R15 - ADDQ R15, AX - -sequenceDecs_decode_56_amd64_ll_update_zero: - MOVQ AX, (R10) + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R15 + ADDQ R15, AX + MOVQ AX, (R10) // Fill bitreader for state updates MOVQ R14, (SP) MOVQ R9, AX SHRQ $0x08, AX MOVBQZX AL, AX - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decode_56_amd64_skip_update // Update Literal Length State MOVBQZX DI, R14 SHRL $0x10, DI - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, DI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(DI*8), DI // Update Match Length State MOVBQZX R8, R14 SHRL $0x10, R8 - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, R8 // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(R8*8), R8 // Update Offset State MOVBQZX R9, R14 SHRL $0x10, R9 - LEAQ (BX)(R14*1), CX + MOVQ BX, CX MOVQ DX, R15 - MOVQ CX, BX - ROLQ CL, R15 - MOVL $0x00000001, BP - MOVB R14, CL - SHLL CL, BP - DECL BP - ANDQ BP, R15 + SHLQ CL, R15 + SHRQ $0x01, R15 + ADDQ R14, BX + XORQ $0x3f, R14 + MOVQ R14, CX + SHRQ CL, R15 ADDQ R15, R9 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R9*8), R9 sequenceDecs_decode_56_amd64_skip_update: @@ -589,8 +566,7 @@ sequenceDecs_decode_56_amd64_after_adjust: sequenceDecs_decode_56_amd64_match_len_ofs_ok: ADDQ $0x18, R10 - MOVQ ctx+16(FP), AX - DECQ 96(AX) + DECQ 32(SP) JNS sequenceDecs_decode_56_amd64_main_loop MOVQ s+0(FP), AX MOVQ R11, 144(AX) @@ -602,36 +578,54 @@ sequenceDecs_decode_56_amd64_match_len_ofs_ok: MOVQ SI, 32(AX) // Return success + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000000, ret+24(FP) RET // Return with match length error sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000001, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_56_amd64_error_match_len_too_big: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000002, ret+24(FP) RET // Return with match offset too long error + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000003, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000004, ret+24(FP) RET // Return with overread error error_overread: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000006, ret+24(FP) RET // func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: BMI, BMI2, CMOV -TEXT ·sequenceDecs_decode_bmi2(SB), $8-32 +TEXT ·sequenceDecs_decode_bmi2(SB), $40-32 MOVQ br+8(FP), BX MOVQ 24(BX), AX MOVBQZX 40(BX), DX @@ -643,6 +637,14 @@ TEXT ·sequenceDecs_decode_bmi2(SB), $8-32 MOVQ 72(CX), SI MOVQ 80(CX), DI MOVQ 88(CX), R8 + MOVQ (CX), R9 + MOVQ R9, 8(SP) + MOVQ 24(CX), R9 + MOVQ R9, 16(SP) + MOVQ 48(CX), R9 + MOVQ R9, 24(SP) + MOVQ 96(CX), R9 + MOVQ R9, 32(SP) MOVQ 104(CX), R9 MOVQ s+0(FP), CX MOVQ 144(CX), R10 @@ -753,8 +755,7 @@ sequenceDecs_decode_bmi2_fill_2_end: MOVQ R13, (SP) MOVQ $0x00000808, CX BEXTRQ CX, R8, R13 - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decode_bmi2_skip_update LEAQ (SI)(DI*1), R14 ADDQ R8, R14 @@ -772,8 +773,7 @@ sequenceDecs_decode_bmi2_fill_2_end: ADDQ CX, R8 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R8*8), R8 // Update Match Length State @@ -783,8 +783,7 @@ sequenceDecs_decode_bmi2_fill_2_end: ADDQ CX, DI // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(DI*8), DI // Update Literal Length State @@ -793,8 +792,7 @@ sequenceDecs_decode_bmi2_fill_2_end: ADDQ CX, SI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(SI*8), SI sequenceDecs_decode_bmi2_skip_update: @@ -875,8 +873,7 @@ sequenceDecs_decode_bmi2_after_adjust: sequenceDecs_decode_bmi2_match_len_ofs_ok: ADDQ $0x18, R9 - MOVQ ctx+16(FP), CX - DECQ 96(CX) + DECQ 32(SP) JNS sequenceDecs_decode_bmi2_main_loop MOVQ s+0(FP), CX MOVQ R10, 144(CX) @@ -888,36 +885,54 @@ sequenceDecs_decode_bmi2_match_len_ofs_ok: MOVQ BX, 32(CX) // Return success + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000000, ret+24(FP) RET // Return with match length error sequenceDecs_decode_bmi2_error_match_len_ofs_mismatch: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000001, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_bmi2_error_match_len_too_big: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000002, ret+24(FP) RET // Return with match offset too long error + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000003, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000004, ret+24(FP) RET // Return with overread error error_overread: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000006, ret+24(FP) RET // func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: BMI, BMI2, CMOV -TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32 +TEXT ·sequenceDecs_decode_56_bmi2(SB), $40-32 MOVQ br+8(FP), BX MOVQ 24(BX), AX MOVBQZX 40(BX), DX @@ -929,6 +944,14 @@ TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32 MOVQ 72(CX), SI MOVQ 80(CX), DI MOVQ 88(CX), R8 + MOVQ (CX), R9 + MOVQ R9, 8(SP) + MOVQ 24(CX), R9 + MOVQ R9, 16(SP) + MOVQ 48(CX), R9 + MOVQ R9, 24(SP) + MOVQ 96(CX), R9 + MOVQ R9, 32(SP) MOVQ 104(CX), R9 MOVQ s+0(FP), CX MOVQ 144(CX), R10 @@ -1010,8 +1033,7 @@ sequenceDecs_decode_56_bmi2_fill_end: MOVQ R13, (SP) MOVQ $0x00000808, CX BEXTRQ CX, R8, R13 - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decode_56_bmi2_skip_update LEAQ (SI)(DI*1), R14 ADDQ R8, R14 @@ -1029,8 +1051,7 @@ sequenceDecs_decode_56_bmi2_fill_end: ADDQ CX, R8 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R8*8), R8 // Update Match Length State @@ -1040,8 +1061,7 @@ sequenceDecs_decode_56_bmi2_fill_end: ADDQ CX, DI // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(DI*8), DI // Update Literal Length State @@ -1050,8 +1070,7 @@ sequenceDecs_decode_56_bmi2_fill_end: ADDQ CX, SI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(SI*8), SI sequenceDecs_decode_56_bmi2_skip_update: @@ -1132,8 +1151,7 @@ sequenceDecs_decode_56_bmi2_after_adjust: sequenceDecs_decode_56_bmi2_match_len_ofs_ok: ADDQ $0x18, R9 - MOVQ ctx+16(FP), CX - DECQ 96(CX) + DECQ 32(SP) JNS sequenceDecs_decode_56_bmi2_main_loop MOVQ s+0(FP), CX MOVQ R10, 144(CX) @@ -1145,30 +1163,48 @@ sequenceDecs_decode_56_bmi2_match_len_ofs_ok: MOVQ BX, 32(CX) // Return success + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000000, ret+24(FP) RET // Return with match length error sequenceDecs_decode_56_bmi2_error_match_len_ofs_mismatch: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000001, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_56_bmi2_error_match_len_too_big: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000002, ret+24(FP) RET // Return with match offset too long error + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000003, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000004, ret+24(FP) RET // Return with overread error error_overread: + MOVQ 32(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 96(CX) MOVQ $0x00000006, ret+24(FP) RET @@ -1203,9 +1239,11 @@ main_loop: MOVQ 8(AX), R13 // Copy literals - TESTQ R11, R11 - JZ check_offset - XORQ R14, R14 + MOVUPS (SI), X0 + MOVUPS X0, (BX) + CMPQ R11, $0x10 + JBE copy_1_end + MOVQ $0x00000010, R14 copy_1: MOVUPS (SI)(R14*1), X0 @@ -1213,12 +1251,13 @@ copy_1: ADDQ $0x10, R14 CMPQ R14, R11 JB copy_1 - ADDQ R11, SI - ADDQ R11, BX - ADDQ R11, DI + +copy_1_end: + ADDQ R11, SI + ADDQ R11, BX + ADDQ R11, DI // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) -check_offset: LEAQ (DI)(R10*1), R11 CMPQ R12, R11 JG error_match_off_too_big @@ -1258,13 +1297,13 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), R11 - MOVB 2(R14), R12 - MOVW R11, (BX) - MOVB R12, 2(BX) - ADDQ R13, R14 - ADDQ R13, BX - JMP copy_4_end + MOVWQZX (R14), R11 + MOVB 2(R14), R12 + MOVW R11, (BX) + MOVB R12, 2(BX) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end copy_4_move_4through7: MOVL (R14), R11 @@ -1327,13 +1366,13 @@ copy_5_move_1or2: JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (BX) - MOVB BP, 2(BX) - ADDQ R11, R14 - ADDQ R11, BX - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (BX) + MOVB BP, 2(BX) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 @@ -1366,9 +1405,19 @@ copy_match: JA copy_overlapping_match // Copy non-overlapping match - ADDQ R13, DI - MOVQ BX, R12 + ADDQ R13, DI + MOVUPS (R11), X0 + MOVUPS X0, (BX) + CMPQ R13, $0x10 + JA copy_2_long + ADDQ R13, BX + JMP handle_loop + +copy_2_long: + LEAQ 16(BX), R12 ADDQ R13, BX + ADDQ $0x10, R11 + SUBQ $0x10, R13 copy_2: MOVUPS (R11), X0 @@ -1384,12 +1433,12 @@ copy_overlapping_match: ADDQ R13, DI copy_slow_3: - MOVB (R11), R12 - MOVB R12, (BX) - INCQ R11 - INCQ BX - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (R11), R12 + MOVB R12, (BX) + INCQ R11 + INCQ BX + DECQ R13 + JNZ copy_slow_3 handle_loop: ADDQ $0x18, AX @@ -1494,13 +1543,13 @@ copy_1_move_1or2: JMP copy_1_end copy_1_move_3: - MOVW (SI), R14 - MOVB 2(SI), R15 - MOVW R14, (BX) - MOVB R15, 2(BX) - ADDQ R11, SI - ADDQ R11, BX - JMP copy_1_end + MOVWQZX (SI), R14 + MOVB 2(SI), R15 + MOVW R14, (BX) + MOVB R15, 2(BX) + ADDQ R11, SI + ADDQ R11, BX + JMP copy_1_end copy_1_move_4through7: MOVL (SI), R14 @@ -1563,13 +1612,13 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), R11 - MOVB 2(R14), R12 - MOVW R11, (BX) - MOVB R12, 2(BX) - ADDQ R13, R14 - ADDQ R13, BX - JMP copy_4_end + MOVWQZX (R14), R11 + MOVB 2(R14), R12 + MOVW R11, (BX) + MOVB R12, 2(BX) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end copy_4_move_4through7: MOVL (R14), R11 @@ -1632,13 +1681,13 @@ copy_5_move_1or2: JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (BX) - MOVB BP, 2(BX) - ADDQ R11, R14 - ADDQ R11, BX - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (BX) + MOVB BP, 2(BX) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 @@ -1707,13 +1756,13 @@ copy_2_move_1or2: JMP copy_2_end copy_2_move_3: - MOVW (R11), R12 - MOVB 2(R11), R14 - MOVW R12, (BX) - MOVB R14, 2(BX) - ADDQ R13, R11 - ADDQ R13, BX - JMP copy_2_end + MOVWQZX (R11), R12 + MOVB 2(R11), R14 + MOVW R12, (BX) + MOVB R14, 2(BX) + ADDQ R13, R11 + ADDQ R13, BX + JMP copy_2_end copy_2_move_4through7: MOVL (R11), R12 @@ -1740,12 +1789,12 @@ copy_overlapping_match: ADDQ R13, DI copy_slow_3: - MOVB (R11), R12 - MOVB R12, (BX) - INCQ R11 - INCQ BX - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (R11), R12 + MOVB R12, (BX) + INCQ R11 + INCQ BX + DECQ R13 + JNZ copy_slow_3 handle_loop: ADDQ $0x18, AX @@ -1784,7 +1833,7 @@ empty_seqs: // func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: CMOV, SSE -TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_amd64(SB), $96-32 MOVQ br+8(FP), CX MOVQ 24(CX), DX MOVBQZX 40(CX), BX @@ -1796,26 +1845,34 @@ TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32 MOVQ 72(AX), DI MOVQ 80(AX), R8 MOVQ 88(AX), R9 - XORQ CX, CX + MOVQ (AX), CX MOVQ CX, 8(SP) + MOVQ 24(AX), CX MOVQ CX, 16(SP) + MOVQ 48(AX), CX MOVQ CX, 24(SP) + MOVQ 96(AX), CX + MOVQ CX, 32(SP) + XORQ CX, CX + MOVQ CX, 40(SP) + MOVQ CX, 48(SP) + MOVQ CX, 56(SP) MOVQ 112(AX), R10 MOVQ 128(AX), CX - MOVQ CX, 32(SP) + MOVQ CX, 64(SP) MOVQ 144(AX), R11 MOVQ 136(AX), R12 MOVQ 200(AX), CX - MOVQ CX, 56(SP) + MOVQ CX, 88(SP) MOVQ 176(AX), CX - MOVQ CX, 48(SP) + MOVQ CX, 80(SP) MOVQ 184(AX), AX - MOVQ AX, 40(SP) - MOVQ 40(SP), AX - ADDQ AX, 48(SP) + MOVQ AX, 72(SP) + MOVQ 72(SP), AX + ADDQ AX, 80(SP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - ADDQ R10, 32(SP) + ADDQ R10, 64(SP) // outBase += outPosition ADDQ R12, R10 @@ -1853,46 +1910,32 @@ sequenceDecs_decodeSync_amd64_fill_check_overread: sequenceDecs_decodeSync_amd64_fill_end: // Update offset - MOVQ R9, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_amd64_of_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_amd64_of_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_amd64_of_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_amd64_of_update_zero: - MOVQ AX, 8(SP) + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 40(SP) // Update match length - MOVQ R8, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_amd64_ml_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_amd64_ml_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_amd64_ml_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_amd64_ml_update_zero: - MOVQ AX, 16(SP) + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 48(SP) // Fill bitreader to have enough for the remaining CMPQ SI, $0x08 @@ -1924,96 +1967,82 @@ sequenceDecs_decodeSync_amd64_fill_2_check_overread: sequenceDecs_decodeSync_amd64_fill_2_end: // Update literal length - MOVQ DI, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_amd64_ll_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_amd64_ll_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_amd64_ll_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_amd64_ll_update_zero: - MOVQ AX, 24(SP) + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 56(SP) // Fill bitreader for state updates MOVQ R13, (SP) MOVQ R9, AX SHRQ $0x08, AX MOVBQZX AL, AX - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decodeSync_amd64_skip_update // Update Literal Length State MOVBQZX DI, R13 SHRL $0x10, DI - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, DI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(DI*8), DI // Update Match Length State MOVBQZX R8, R13 SHRL $0x10, R8 - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, R8 // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(R8*8), R8 // Update Offset State MOVBQZX R9, R13 SHRL $0x10, R9 - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, R9 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R9*8), R9 sequenceDecs_decodeSync_amd64_skip_update: // Adjust offset MOVQ s+0(FP), CX - MOVQ 8(SP), R13 + MOVQ 40(SP), R13 CMPQ AX, $0x01 JBE sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 MOVUPS 144(CX), X0 @@ -2022,7 +2051,7 @@ sequenceDecs_decodeSync_amd64_skip_update: JMP sequenceDecs_decodeSync_amd64_after_adjust sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0: - CMPQ 24(SP), $0x00000000 + CMPQ 56(SP), $0x00000000 JNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero INCQ R13 JMP sequenceDecs_decodeSync_amd64_adjust_offset_nonzero @@ -2057,14 +2086,11 @@ sequenceDecs_decodeSync_amd64_adjust_skip: MOVQ R14, R13 sequenceDecs_decodeSync_amd64_after_adjust: - MOVQ R13, 8(SP) + MOVQ R13, 40(SP) // Check values - MOVQ 16(SP), AX - MOVQ 24(SP), CX - LEAQ (AX)(CX*1), R14 - MOVQ s+0(FP), R15 - ADDQ R14, 256(R15) + MOVQ 48(SP), AX + MOVQ 56(SP), CX MOVQ ctx+16(FP), R14 SUBQ CX, 104(R14) JS error_not_enough_literals @@ -2076,50 +2102,49 @@ sequenceDecs_decodeSync_amd64_after_adjust: JNZ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_amd64_match_len_ofs_ok: - MOVQ 24(SP), AX - MOVQ 8(SP), CX - MOVQ 16(SP), R13 - // Check if we have enough space in s.out - LEAQ 16(AX)(R13*1), R14 + LEAQ 16(CX)(AX*1), R14 ADDQ R10, R14 - CMPQ R14, 32(SP) + CMPQ R14, 64(SP) JA error_not_enough_space // Copy literals - TESTQ AX, AX - JZ check_offset - XORQ R14, R14 + MOVUPS (R11), X0 + MOVUPS X0, (R10) + CMPQ CX, $0x10 + JBE copy_1_end + MOVQ $0x00000010, R14 copy_1: MOVUPS (R11)(R14*1), X0 MOVUPS X0, (R10)(R14*1) ADDQ $0x10, R14 - CMPQ R14, AX + CMPQ R14, CX JB copy_1 - ADDQ AX, R11 - ADDQ AX, R10 - ADDQ AX, R12 + +copy_1_end: + ADDQ CX, R11 + ADDQ CX, R10 + ADDQ CX, R12 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) -check_offset: - MOVQ R12, AX - ADDQ 40(SP), AX - CMPQ CX, AX + MOVQ R12, CX + ADDQ 72(SP), CX + CMPQ R13, CX JG error_match_off_too_big - CMPQ CX, 56(SP) + CMPQ R13, 88(SP) JG error_match_off_too_big // Copy match from history - MOVQ CX, AX - SUBQ R12, AX + MOVQ R13, CX + SUBQ R12, CX JLS copy_match - MOVQ 48(SP), R14 - SUBQ AX, R14 - CMPQ R13, AX + MOVQ 80(SP), R14 + SUBQ CX, R14 + CMPQ AX, CX JG copy_all_from_history - MOVQ R13, AX - SUBQ $0x10, AX + MOVQ AX, CX + SUBQ $0x10, CX JB copy_4_small copy_4_loop: @@ -2127,54 +2152,54 @@ copy_4_loop: MOVUPS X0, (R10) ADDQ $0x10, R14 ADDQ $0x10, R10 - SUBQ $0x10, AX + SUBQ $0x10, CX JAE copy_4_loop - LEAQ 16(R14)(AX*1), R14 - LEAQ 16(R10)(AX*1), R10 + LEAQ 16(R14)(CX*1), R14 + LEAQ 16(R10)(CX*1), R10 MOVUPS -16(R14), X0 MOVUPS X0, -16(R10) JMP copy_4_end copy_4_small: - CMPQ R13, $0x03 + CMPQ AX, $0x03 JE copy_4_move_3 - CMPQ R13, $0x08 + CMPQ AX, $0x08 JB copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), AX - MOVB 2(R14), CL - MOVW AX, (R10) - MOVB CL, 2(R10) - ADDQ R13, R14 - ADDQ R13, R10 - JMP copy_4_end + MOVWQZX (R14), CX + MOVB 2(R14), R13 + MOVW CX, (R10) + MOVB R13, 2(R10) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_4_end copy_4_move_4through7: - MOVL (R14), AX - MOVL -4(R14)(R13*1), CX - MOVL AX, (R10) - MOVL CX, -4(R10)(R13*1) - ADDQ R13, R14 - ADDQ R13, R10 + MOVL (R14), CX + MOVL -4(R14)(AX*1), R13 + MOVL CX, (R10) + MOVL R13, -4(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 JMP copy_4_end copy_4_move_8through16: - MOVQ (R14), AX - MOVQ -8(R14)(R13*1), CX - MOVQ AX, (R10) - MOVQ CX, -8(R10)(R13*1) - ADDQ R13, R14 - ADDQ R13, R10 + MOVQ (R14), CX + MOVQ -8(R14)(AX*1), R13 + MOVQ CX, (R10) + MOVQ R13, -8(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 copy_4_end: - ADDQ R13, R12 + ADDQ AX, R12 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVQ AX, R15 + MOVQ CX, R15 SUBQ $0x10, R15 JB copy_5_small @@ -2192,90 +2217,99 @@ copy_5_loop: JMP copy_5_end copy_5_small: - CMPQ AX, $0x03 + CMPQ CX, $0x03 JE copy_5_move_3 JB copy_5_move_1or2 - CMPQ AX, $0x08 + CMPQ CX, $0x08 JB copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVB (R14), R15 - MOVB -1(R14)(AX*1), BP + MOVB -1(R14)(CX*1), BP MOVB R15, (R10) - MOVB BP, -1(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVB BP, -1(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (R10) - MOVB BP, 2(R10) - ADDQ AX, R14 - ADDQ AX, R10 - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R10) + MOVB BP, 2(R10) + ADDQ CX, R14 + ADDQ CX, R10 + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 - MOVL -4(R14)(AX*1), BP + MOVL -4(R14)(CX*1), BP MOVL R15, (R10) - MOVL BP, -4(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVL BP, -4(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 JMP copy_5_end copy_5_move_8through16: MOVQ (R14), R15 - MOVQ -8(R14)(AX*1), BP + MOVQ -8(R14)(CX*1), BP MOVQ R15, (R10) - MOVQ BP, -8(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVQ BP, -8(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 copy_5_end: - ADDQ AX, R12 - SUBQ AX, R13 + ADDQ CX, R12 + SUBQ CX, AX // Copy match from the current buffer copy_match: - MOVQ R10, AX - SUBQ CX, AX + MOVQ R10, CX + SUBQ R13, CX // ml <= mo - CMPQ R13, CX + CMPQ AX, R13 JA copy_overlapping_match // Copy non-overlapping match - ADDQ R13, R12 - MOVQ R10, CX - ADDQ R13, R10 + ADDQ AX, R12 + MOVUPS (CX), X0 + MOVUPS X0, (R10) + CMPQ AX, $0x10 + JA copy_2_long + ADDQ AX, R10 + JMP handle_loop + +copy_2_long: + LEAQ 16(R10), R13 + ADDQ AX, R10 + ADDQ $0x10, CX + SUBQ $0x10, AX copy_2: - MOVUPS (AX), X0 - MOVUPS X0, (CX) - ADDQ $0x10, AX + MOVUPS (CX), X0 + MOVUPS X0, (R13) ADDQ $0x10, CX - SUBQ $0x10, R13 + ADDQ $0x10, R13 + SUBQ $0x10, AX JHI copy_2 JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADDQ R13, R12 + ADDQ AX, R12 copy_slow_3: - MOVB (AX), CL - MOVB CL, (R10) - INCQ AX - INCQ R10 - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (CX), R13 + MOVB R13, (R10) + INCQ CX + INCQ R10 + DECQ AX + JNZ copy_slow_3 handle_loop: - MOVQ ctx+16(FP), AX - DECQ 96(AX) + DECQ 32(SP) JNS sequenceDecs_decodeSync_amd64_main_loop loop_finished: @@ -2284,6 +2318,13 @@ loop_finished: MOVB BL, 40(AX) MOVQ SI, 32(AX) + // s.seqSize += outPosition - ctx.outPosition + MOVQ ctx+16(FP), AX + MOVQ s+0(FP), CX + MOVQ R12, DX + SUBQ 136(AX), DX + ADDQ DX, 256(CX) + // Update the context MOVQ ctx+16(FP), AX MOVQ R12, 136(AX) @@ -2297,7 +2338,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: - MOVQ 16(SP), AX + MOVQ 48(SP), AX MOVQ ctx+16(FP), CX MOVQ AX, 216(CX) MOVQ $0x00000001, ret+24(FP) @@ -2306,7 +2347,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_amd64_error_match_len_too_big: MOVQ ctx+16(FP), AX - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ $0x00000002, ret+24(FP) RET @@ -2314,7 +2355,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVQ ctx+16(FP), AX - MOVQ 8(SP), CX + MOVQ 40(SP), CX MOVQ CX, 224(AX) MOVQ R12, 136(AX) MOVQ $0x00000003, ret+24(FP) @@ -2323,7 +2364,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) MOVQ $0x00000004, ret+24(FP) RET @@ -2336,9 +2377,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ R12, 136(AX) MOVQ $0x00000005, ret+24(FP) @@ -2346,7 +2387,7 @@ error_not_enough_space: // func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: BMI, BMI2, CMOV, SSE -TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_bmi2(SB), $96-32 MOVQ br+8(FP), BX MOVQ 24(BX), AX MOVBQZX 40(BX), DX @@ -2358,26 +2399,34 @@ TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32 MOVQ 72(CX), SI MOVQ 80(CX), DI MOVQ 88(CX), R8 - XORQ R9, R9 + MOVQ (CX), R9 MOVQ R9, 8(SP) + MOVQ 24(CX), R9 MOVQ R9, 16(SP) + MOVQ 48(CX), R9 MOVQ R9, 24(SP) + MOVQ 96(CX), R9 + MOVQ R9, 32(SP) + XORQ R9, R9 + MOVQ R9, 40(SP) + MOVQ R9, 48(SP) + MOVQ R9, 56(SP) MOVQ 112(CX), R9 MOVQ 128(CX), R10 - MOVQ R10, 32(SP) + MOVQ R10, 64(SP) MOVQ 144(CX), R10 MOVQ 136(CX), R11 MOVQ 200(CX), R12 - MOVQ R12, 56(SP) + MOVQ R12, 88(SP) MOVQ 176(CX), R12 - MOVQ R12, 48(SP) + MOVQ R12, 80(SP) MOVQ 184(CX), CX - MOVQ CX, 40(SP) - MOVQ 40(SP), CX - ADDQ CX, 48(SP) + MOVQ CX, 72(SP) + MOVQ 72(SP), CX + ADDQ CX, 80(SP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - ADDQ R9, 32(SP) + ADDQ R9, 64(SP) // outBase += outPosition ADDQ R11, R9 @@ -2425,7 +2474,7 @@ sequenceDecs_decodeSync_bmi2_fill_end: MOVQ R8, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 8(SP) + MOVQ CX, 40(SP) // Update match length MOVQ $0x00000808, CX @@ -2438,7 +2487,7 @@ sequenceDecs_decodeSync_bmi2_fill_end: MOVQ DI, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 16(SP) + MOVQ CX, 48(SP) // Fill bitreader to have enough for the remaining CMPQ BX, $0x08 @@ -2480,14 +2529,13 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: MOVQ SI, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 24(SP) + MOVQ CX, 56(SP) // Fill bitreader for state updates MOVQ R12, (SP) MOVQ $0x00000808, CX BEXTRQ CX, R8, R12 - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decodeSync_bmi2_skip_update LEAQ (SI)(DI*1), R13 ADDQ R8, R13 @@ -2505,8 +2553,7 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: ADDQ CX, R8 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R8*8), R8 // Update Match Length State @@ -2516,8 +2563,7 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: ADDQ CX, DI // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(DI*8), DI // Update Literal Length State @@ -2526,14 +2572,13 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: ADDQ CX, SI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(SI*8), SI sequenceDecs_decodeSync_bmi2_skip_update: // Adjust offset MOVQ s+0(FP), CX - MOVQ 8(SP), R13 + MOVQ 40(SP), R13 CMPQ R12, $0x01 JBE sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0 MOVUPS 144(CX), X0 @@ -2542,7 +2587,7 @@ sequenceDecs_decodeSync_bmi2_skip_update: JMP sequenceDecs_decodeSync_bmi2_after_adjust sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0: - CMPQ 24(SP), $0x00000000 + CMPQ 56(SP), $0x00000000 JNE sequenceDecs_decodeSync_bmi2_adjust_offset_maybezero INCQ R13 JMP sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero @@ -2577,14 +2622,11 @@ sequenceDecs_decodeSync_bmi2_adjust_skip: MOVQ R14, R13 sequenceDecs_decodeSync_bmi2_after_adjust: - MOVQ R13, 8(SP) + MOVQ R13, 40(SP) // Check values - MOVQ 16(SP), CX - MOVQ 24(SP), R12 - LEAQ (CX)(R12*1), R14 - MOVQ s+0(FP), R15 - ADDQ R14, 256(R15) + MOVQ 48(SP), CX + MOVQ 56(SP), R12 MOVQ ctx+16(FP), R14 SUBQ R12, 104(R14) JS error_not_enough_literals @@ -2596,50 +2638,49 @@ sequenceDecs_decodeSync_bmi2_after_adjust: JNZ sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch sequenceDecs_decodeSync_bmi2_match_len_ofs_ok: - MOVQ 24(SP), CX - MOVQ 8(SP), R12 - MOVQ 16(SP), R13 - // Check if we have enough space in s.out - LEAQ 16(CX)(R13*1), R14 + LEAQ 16(R12)(CX*1), R14 ADDQ R9, R14 - CMPQ R14, 32(SP) + CMPQ R14, 64(SP) JA error_not_enough_space // Copy literals - TESTQ CX, CX - JZ check_offset - XORQ R14, R14 + MOVUPS (R10), X0 + MOVUPS X0, (R9) + CMPQ R12, $0x10 + JBE copy_1_end + MOVQ $0x00000010, R14 copy_1: MOVUPS (R10)(R14*1), X0 MOVUPS X0, (R9)(R14*1) ADDQ $0x10, R14 - CMPQ R14, CX + CMPQ R14, R12 JB copy_1 - ADDQ CX, R10 - ADDQ CX, R9 - ADDQ CX, R11 + +copy_1_end: + ADDQ R12, R10 + ADDQ R12, R9 + ADDQ R12, R11 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) -check_offset: - MOVQ R11, CX - ADDQ 40(SP), CX - CMPQ R12, CX + MOVQ R11, R12 + ADDQ 72(SP), R12 + CMPQ R13, R12 JG error_match_off_too_big - CMPQ R12, 56(SP) + CMPQ R13, 88(SP) JG error_match_off_too_big // Copy match from history - MOVQ R12, CX - SUBQ R11, CX + MOVQ R13, R12 + SUBQ R11, R12 JLS copy_match - MOVQ 48(SP), R14 - SUBQ CX, R14 - CMPQ R13, CX + MOVQ 80(SP), R14 + SUBQ R12, R14 + CMPQ CX, R12 JG copy_all_from_history - MOVQ R13, CX - SUBQ $0x10, CX + MOVQ CX, R12 + SUBQ $0x10, R12 JB copy_4_small copy_4_loop: @@ -2647,54 +2688,54 @@ copy_4_loop: MOVUPS X0, (R9) ADDQ $0x10, R14 ADDQ $0x10, R9 - SUBQ $0x10, CX + SUBQ $0x10, R12 JAE copy_4_loop - LEAQ 16(R14)(CX*1), R14 - LEAQ 16(R9)(CX*1), R9 + LEAQ 16(R14)(R12*1), R14 + LEAQ 16(R9)(R12*1), R9 MOVUPS -16(R14), X0 MOVUPS X0, -16(R9) JMP copy_4_end copy_4_small: - CMPQ R13, $0x03 + CMPQ CX, $0x03 JE copy_4_move_3 - CMPQ R13, $0x08 + CMPQ CX, $0x08 JB copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), CX - MOVB 2(R14), R12 - MOVW CX, (R9) - MOVB R12, 2(R9) - ADDQ R13, R14 - ADDQ R13, R9 - JMP copy_4_end + MOVWQZX (R14), R12 + MOVB 2(R14), R13 + MOVW R12, (R9) + MOVB R13, 2(R9) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_4_end copy_4_move_4through7: - MOVL (R14), CX - MOVL -4(R14)(R13*1), R12 - MOVL CX, (R9) - MOVL R12, -4(R9)(R13*1) - ADDQ R13, R14 - ADDQ R13, R9 + MOVL (R14), R12 + MOVL -4(R14)(CX*1), R13 + MOVL R12, (R9) + MOVL R13, -4(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 JMP copy_4_end copy_4_move_8through16: - MOVQ (R14), CX - MOVQ -8(R14)(R13*1), R12 - MOVQ CX, (R9) - MOVQ R12, -8(R9)(R13*1) - ADDQ R13, R14 - ADDQ R13, R9 + MOVQ (R14), R12 + MOVQ -8(R14)(CX*1), R13 + MOVQ R12, (R9) + MOVQ R13, -8(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 copy_4_end: - ADDQ R13, R11 + ADDQ CX, R11 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVQ CX, R15 + MOVQ R12, R15 SUBQ $0x10, R15 JB copy_5_small @@ -2712,90 +2753,99 @@ copy_5_loop: JMP copy_5_end copy_5_small: - CMPQ CX, $0x03 + CMPQ R12, $0x03 JE copy_5_move_3 JB copy_5_move_1or2 - CMPQ CX, $0x08 + CMPQ R12, $0x08 JB copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVB (R14), R15 - MOVB -1(R14)(CX*1), BP + MOVB -1(R14)(R12*1), BP MOVB R15, (R9) - MOVB BP, -1(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVB BP, -1(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (R9) - MOVB BP, 2(R9) - ADDQ CX, R14 - ADDQ CX, R9 - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R9) + MOVB BP, 2(R9) + ADDQ R12, R14 + ADDQ R12, R9 + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 - MOVL -4(R14)(CX*1), BP + MOVL -4(R14)(R12*1), BP MOVL R15, (R9) - MOVL BP, -4(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVL BP, -4(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 JMP copy_5_end copy_5_move_8through16: MOVQ (R14), R15 - MOVQ -8(R14)(CX*1), BP + MOVQ -8(R14)(R12*1), BP MOVQ R15, (R9) - MOVQ BP, -8(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVQ BP, -8(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 copy_5_end: - ADDQ CX, R11 - SUBQ CX, R13 + ADDQ R12, R11 + SUBQ R12, CX // Copy match from the current buffer copy_match: - MOVQ R9, CX - SUBQ R12, CX + MOVQ R9, R12 + SUBQ R13, R12 // ml <= mo - CMPQ R13, R12 + CMPQ CX, R13 JA copy_overlapping_match // Copy non-overlapping match - ADDQ R13, R11 - MOVQ R9, R12 - ADDQ R13, R9 + ADDQ CX, R11 + MOVUPS (R12), X0 + MOVUPS X0, (R9) + CMPQ CX, $0x10 + JA copy_2_long + ADDQ CX, R9 + JMP handle_loop + +copy_2_long: + LEAQ 16(R9), R13 + ADDQ CX, R9 + ADDQ $0x10, R12 + SUBQ $0x10, CX copy_2: - MOVUPS (CX), X0 - MOVUPS X0, (R12) - ADDQ $0x10, CX + MOVUPS (R12), X0 + MOVUPS X0, (R13) ADDQ $0x10, R12 - SUBQ $0x10, R13 + ADDQ $0x10, R13 + SUBQ $0x10, CX JHI copy_2 JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADDQ R13, R11 + ADDQ CX, R11 copy_slow_3: - MOVB (CX), R12 - MOVB R12, (R9) - INCQ CX - INCQ R9 - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (R12), R13 + MOVB R13, (R9) + INCQ R12 + INCQ R9 + DECQ CX + JNZ copy_slow_3 handle_loop: - MOVQ ctx+16(FP), CX - DECQ 96(CX) + DECQ 32(SP) JNS sequenceDecs_decodeSync_bmi2_main_loop loop_finished: @@ -2804,6 +2854,13 @@ loop_finished: MOVB DL, 40(CX) MOVQ BX, 32(CX) + // s.seqSize += outPosition - ctx.outPosition + MOVQ ctx+16(FP), AX + MOVQ s+0(FP), CX + MOVQ R11, DX + SUBQ 136(AX), DX + ADDQ DX, 256(CX) + // Update the context MOVQ ctx+16(FP), AX MOVQ R11, 136(AX) @@ -2817,7 +2874,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch: - MOVQ 16(SP), AX + MOVQ 48(SP), AX MOVQ ctx+16(FP), CX MOVQ AX, 216(CX) MOVQ $0x00000001, ret+24(FP) @@ -2826,7 +2883,7 @@ sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_bmi2_error_match_len_too_big: MOVQ ctx+16(FP), AX - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ $0x00000002, ret+24(FP) RET @@ -2834,7 +2891,7 @@ sequenceDecs_decodeSync_bmi2_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVQ ctx+16(FP), AX - MOVQ 8(SP), CX + MOVQ 40(SP), CX MOVQ CX, 224(AX) MOVQ R11, 136(AX) MOVQ $0x00000003, ret+24(FP) @@ -2843,7 +2900,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) MOVQ $0x00000004, ret+24(FP) RET @@ -2856,9 +2913,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ R11, 136(AX) MOVQ $0x00000005, ret+24(FP) @@ -2866,7 +2923,7 @@ error_not_enough_space: // func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: CMOV, SSE -TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $96-32 MOVQ br+8(FP), CX MOVQ 24(CX), DX MOVBQZX 40(CX), BX @@ -2878,26 +2935,34 @@ TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32 MOVQ 72(AX), DI MOVQ 80(AX), R8 MOVQ 88(AX), R9 - XORQ CX, CX + MOVQ (AX), CX MOVQ CX, 8(SP) + MOVQ 24(AX), CX MOVQ CX, 16(SP) + MOVQ 48(AX), CX MOVQ CX, 24(SP) + MOVQ 96(AX), CX + MOVQ CX, 32(SP) + XORQ CX, CX + MOVQ CX, 40(SP) + MOVQ CX, 48(SP) + MOVQ CX, 56(SP) MOVQ 112(AX), R10 MOVQ 128(AX), CX - MOVQ CX, 32(SP) + MOVQ CX, 64(SP) MOVQ 144(AX), R11 MOVQ 136(AX), R12 MOVQ 200(AX), CX - MOVQ CX, 56(SP) + MOVQ CX, 88(SP) MOVQ 176(AX), CX - MOVQ CX, 48(SP) + MOVQ CX, 80(SP) MOVQ 184(AX), AX - MOVQ AX, 40(SP) - MOVQ 40(SP), AX - ADDQ AX, 48(SP) + MOVQ AX, 72(SP) + MOVQ 72(SP), AX + ADDQ AX, 80(SP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - ADDQ R10, 32(SP) + ADDQ R10, 64(SP) // outBase += outPosition ADDQ R12, R10 @@ -2935,46 +3000,32 @@ sequenceDecs_decodeSync_safe_amd64_fill_check_overread: sequenceDecs_decodeSync_safe_amd64_fill_end: // Update offset - MOVQ R9, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_safe_amd64_of_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_safe_amd64_of_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_safe_amd64_of_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_safe_amd64_of_update_zero: - MOVQ AX, 8(SP) + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 40(SP) // Update match length - MOVQ R8, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_safe_amd64_ml_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_safe_amd64_ml_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_safe_amd64_ml_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_safe_amd64_ml_update_zero: - MOVQ AX, 16(SP) + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 48(SP) // Fill bitreader to have enough for the remaining CMPQ SI, $0x08 @@ -3006,96 +3057,82 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread: sequenceDecs_decodeSync_safe_amd64_fill_2_end: // Update literal length - MOVQ DI, AX - MOVQ BX, CX - MOVQ DX, R14 - SHLQ CL, R14 - MOVB AH, CL - SHRQ $0x20, AX - TESTQ CX, CX - JZ sequenceDecs_decodeSync_safe_amd64_ll_update_zero - ADDQ CX, BX - CMPQ BX, $0x40 - JA sequenceDecs_decodeSync_safe_amd64_ll_update_zero - CMPQ CX, $0x40 - JAE sequenceDecs_decodeSync_safe_amd64_ll_update_zero - NEGQ CX - SHRQ CL, R14 - ADDQ R14, AX - -sequenceDecs_decodeSync_safe_amd64_ll_update_zero: - MOVQ AX, 24(SP) + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + MOVBLZX AH, CX + SHRQ $0x20, AX + ADDQ CX, BX + XORQ $0x3f, CX + SHRQ CL, R14 + ADDQ R14, AX + MOVQ AX, 56(SP) // Fill bitreader for state updates MOVQ R13, (SP) MOVQ R9, AX SHRQ $0x08, AX MOVBQZX AL, AX - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decodeSync_safe_amd64_skip_update // Update Literal Length State MOVBQZX DI, R13 SHRL $0x10, DI - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, DI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(DI*8), DI // Update Match Length State MOVBQZX R8, R13 SHRL $0x10, R8 - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, R8 // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(R8*8), R8 // Update Offset State MOVBQZX R9, R13 SHRL $0x10, R9 - LEAQ (BX)(R13*1), CX + MOVQ BX, CX MOVQ DX, R14 - MOVQ CX, BX - ROLQ CL, R14 - MOVL $0x00000001, R15 - MOVB R13, CL - SHLL CL, R15 - DECL R15 - ANDQ R15, R14 + SHLQ CL, R14 + SHRQ $0x01, R14 + ADDQ R13, BX + XORQ $0x3f, R13 + MOVQ R13, CX + SHRQ CL, R14 ADDQ R14, R9 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R9*8), R9 sequenceDecs_decodeSync_safe_amd64_skip_update: // Adjust offset MOVQ s+0(FP), CX - MOVQ 8(SP), R13 + MOVQ 40(SP), R13 CMPQ AX, $0x01 JBE sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 MOVUPS 144(CX), X0 @@ -3104,7 +3141,7 @@ sequenceDecs_decodeSync_safe_amd64_skip_update: JMP sequenceDecs_decodeSync_safe_amd64_after_adjust sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0: - CMPQ 24(SP), $0x00000000 + CMPQ 56(SP), $0x00000000 JNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero INCQ R13 JMP sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero @@ -3139,14 +3176,11 @@ sequenceDecs_decodeSync_safe_amd64_adjust_skip: MOVQ R14, R13 sequenceDecs_decodeSync_safe_amd64_after_adjust: - MOVQ R13, 8(SP) + MOVQ R13, 40(SP) // Check values - MOVQ 16(SP), AX - MOVQ 24(SP), CX - LEAQ (AX)(CX*1), R14 - MOVQ s+0(FP), R15 - ADDQ R14, 256(R15) + MOVQ 48(SP), AX + MOVQ 56(SP), CX MOVQ ctx+16(FP), R14 SUBQ CX, 104(R14) JS error_not_enough_literals @@ -3158,20 +3192,16 @@ sequenceDecs_decodeSync_safe_amd64_after_adjust: JNZ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok: - MOVQ 24(SP), AX - MOVQ 8(SP), CX - MOVQ 16(SP), R13 - // Check if we have enough space in s.out - LEAQ (AX)(R13*1), R14 + LEAQ (CX)(AX*1), R14 ADDQ R10, R14 - CMPQ R14, 32(SP) + CMPQ R14, 64(SP) JA error_not_enough_space // Copy literals - TESTQ AX, AX + TESTQ CX, CX JZ check_offset - MOVQ AX, R14 + MOVQ CX, R14 SUBQ $0x10, R14 JB copy_1_small @@ -3189,70 +3219,70 @@ copy_1_loop: JMP copy_1_end copy_1_small: - CMPQ AX, $0x03 + CMPQ CX, $0x03 JE copy_1_move_3 JB copy_1_move_1or2 - CMPQ AX, $0x08 + CMPQ CX, $0x08 JB copy_1_move_4through7 JMP copy_1_move_8through16 copy_1_move_1or2: MOVB (R11), R14 - MOVB -1(R11)(AX*1), R15 + MOVB -1(R11)(CX*1), R15 MOVB R14, (R10) - MOVB R15, -1(R10)(AX*1) - ADDQ AX, R11 - ADDQ AX, R10 + MOVB R15, -1(R10)(CX*1) + ADDQ CX, R11 + ADDQ CX, R10 JMP copy_1_end copy_1_move_3: - MOVW (R11), R14 - MOVB 2(R11), R15 - MOVW R14, (R10) - MOVB R15, 2(R10) - ADDQ AX, R11 - ADDQ AX, R10 - JMP copy_1_end + MOVWQZX (R11), R14 + MOVB 2(R11), R15 + MOVW R14, (R10) + MOVB R15, 2(R10) + ADDQ CX, R11 + ADDQ CX, R10 + JMP copy_1_end copy_1_move_4through7: MOVL (R11), R14 - MOVL -4(R11)(AX*1), R15 + MOVL -4(R11)(CX*1), R15 MOVL R14, (R10) - MOVL R15, -4(R10)(AX*1) - ADDQ AX, R11 - ADDQ AX, R10 + MOVL R15, -4(R10)(CX*1) + ADDQ CX, R11 + ADDQ CX, R10 JMP copy_1_end copy_1_move_8through16: MOVQ (R11), R14 - MOVQ -8(R11)(AX*1), R15 + MOVQ -8(R11)(CX*1), R15 MOVQ R14, (R10) - MOVQ R15, -8(R10)(AX*1) - ADDQ AX, R11 - ADDQ AX, R10 + MOVQ R15, -8(R10)(CX*1) + ADDQ CX, R11 + ADDQ CX, R10 copy_1_end: - ADDQ AX, R12 + ADDQ CX, R12 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) check_offset: - MOVQ R12, AX - ADDQ 40(SP), AX - CMPQ CX, AX + MOVQ R12, CX + ADDQ 72(SP), CX + CMPQ R13, CX JG error_match_off_too_big - CMPQ CX, 56(SP) + CMPQ R13, 88(SP) JG error_match_off_too_big // Copy match from history - MOVQ CX, AX - SUBQ R12, AX + MOVQ R13, CX + SUBQ R12, CX JLS copy_match - MOVQ 48(SP), R14 - SUBQ AX, R14 - CMPQ R13, AX + MOVQ 80(SP), R14 + SUBQ CX, R14 + CMPQ AX, CX JG copy_all_from_history - MOVQ R13, AX - SUBQ $0x10, AX + MOVQ AX, CX + SUBQ $0x10, CX JB copy_4_small copy_4_loop: @@ -3260,54 +3290,54 @@ copy_4_loop: MOVUPS X0, (R10) ADDQ $0x10, R14 ADDQ $0x10, R10 - SUBQ $0x10, AX + SUBQ $0x10, CX JAE copy_4_loop - LEAQ 16(R14)(AX*1), R14 - LEAQ 16(R10)(AX*1), R10 + LEAQ 16(R14)(CX*1), R14 + LEAQ 16(R10)(CX*1), R10 MOVUPS -16(R14), X0 MOVUPS X0, -16(R10) JMP copy_4_end copy_4_small: - CMPQ R13, $0x03 + CMPQ AX, $0x03 JE copy_4_move_3 - CMPQ R13, $0x08 + CMPQ AX, $0x08 JB copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), AX - MOVB 2(R14), CL - MOVW AX, (R10) - MOVB CL, 2(R10) - ADDQ R13, R14 - ADDQ R13, R10 - JMP copy_4_end + MOVWQZX (R14), CX + MOVB 2(R14), R13 + MOVW CX, (R10) + MOVB R13, 2(R10) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_4_end copy_4_move_4through7: - MOVL (R14), AX - MOVL -4(R14)(R13*1), CX - MOVL AX, (R10) - MOVL CX, -4(R10)(R13*1) - ADDQ R13, R14 - ADDQ R13, R10 + MOVL (R14), CX + MOVL -4(R14)(AX*1), R13 + MOVL CX, (R10) + MOVL R13, -4(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 JMP copy_4_end copy_4_move_8through16: - MOVQ (R14), AX - MOVQ -8(R14)(R13*1), CX - MOVQ AX, (R10) - MOVQ CX, -8(R10)(R13*1) - ADDQ R13, R14 - ADDQ R13, R10 + MOVQ (R14), CX + MOVQ -8(R14)(AX*1), R13 + MOVQ CX, (R10) + MOVQ R13, -8(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 copy_4_end: - ADDQ R13, R12 + ADDQ AX, R12 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVQ AX, R15 + MOVQ CX, R15 SUBQ $0x10, R15 JB copy_5_small @@ -3325,141 +3355,140 @@ copy_5_loop: JMP copy_5_end copy_5_small: - CMPQ AX, $0x03 + CMPQ CX, $0x03 JE copy_5_move_3 JB copy_5_move_1or2 - CMPQ AX, $0x08 + CMPQ CX, $0x08 JB copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVB (R14), R15 - MOVB -1(R14)(AX*1), BP + MOVB -1(R14)(CX*1), BP MOVB R15, (R10) - MOVB BP, -1(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVB BP, -1(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (R10) - MOVB BP, 2(R10) - ADDQ AX, R14 - ADDQ AX, R10 - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R10) + MOVB BP, 2(R10) + ADDQ CX, R14 + ADDQ CX, R10 + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 - MOVL -4(R14)(AX*1), BP + MOVL -4(R14)(CX*1), BP MOVL R15, (R10) - MOVL BP, -4(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVL BP, -4(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 JMP copy_5_end copy_5_move_8through16: MOVQ (R14), R15 - MOVQ -8(R14)(AX*1), BP + MOVQ -8(R14)(CX*1), BP MOVQ R15, (R10) - MOVQ BP, -8(R10)(AX*1) - ADDQ AX, R14 - ADDQ AX, R10 + MOVQ BP, -8(R10)(CX*1) + ADDQ CX, R14 + ADDQ CX, R10 copy_5_end: - ADDQ AX, R12 - SUBQ AX, R13 + ADDQ CX, R12 + SUBQ CX, AX // Copy match from the current buffer copy_match: - MOVQ R10, AX - SUBQ CX, AX + MOVQ R10, CX + SUBQ R13, CX // ml <= mo - CMPQ R13, CX + CMPQ AX, R13 JA copy_overlapping_match // Copy non-overlapping match - ADDQ R13, R12 - MOVQ R13, CX - SUBQ $0x10, CX + ADDQ AX, R12 + MOVQ AX, R13 + SUBQ $0x10, R13 JB copy_2_small copy_2_loop: - MOVUPS (AX), X0 + MOVUPS (CX), X0 MOVUPS X0, (R10) - ADDQ $0x10, AX + ADDQ $0x10, CX ADDQ $0x10, R10 - SUBQ $0x10, CX + SUBQ $0x10, R13 JAE copy_2_loop - LEAQ 16(AX)(CX*1), AX - LEAQ 16(R10)(CX*1), R10 - MOVUPS -16(AX), X0 + LEAQ 16(CX)(R13*1), CX + LEAQ 16(R10)(R13*1), R10 + MOVUPS -16(CX), X0 MOVUPS X0, -16(R10) JMP copy_2_end copy_2_small: - CMPQ R13, $0x03 + CMPQ AX, $0x03 JE copy_2_move_3 JB copy_2_move_1or2 - CMPQ R13, $0x08 + CMPQ AX, $0x08 JB copy_2_move_4through7 JMP copy_2_move_8through16 copy_2_move_1or2: - MOVB (AX), CL - MOVB -1(AX)(R13*1), R14 - MOVB CL, (R10) - MOVB R14, -1(R10)(R13*1) - ADDQ R13, AX - ADDQ R13, R10 + MOVB (CX), R13 + MOVB -1(CX)(AX*1), R14 + MOVB R13, (R10) + MOVB R14, -1(R10)(AX*1) + ADDQ AX, CX + ADDQ AX, R10 JMP copy_2_end copy_2_move_3: - MOVW (AX), CX - MOVB 2(AX), R14 - MOVW CX, (R10) - MOVB R14, 2(R10) - ADDQ R13, AX - ADDQ R13, R10 - JMP copy_2_end + MOVWQZX (CX), R13 + MOVB 2(CX), R14 + MOVW R13, (R10) + MOVB R14, 2(R10) + ADDQ AX, CX + ADDQ AX, R10 + JMP copy_2_end copy_2_move_4through7: - MOVL (AX), CX - MOVL -4(AX)(R13*1), R14 - MOVL CX, (R10) - MOVL R14, -4(R10)(R13*1) - ADDQ R13, AX - ADDQ R13, R10 + MOVL (CX), R13 + MOVL -4(CX)(AX*1), R14 + MOVL R13, (R10) + MOVL R14, -4(R10)(AX*1) + ADDQ AX, CX + ADDQ AX, R10 JMP copy_2_end copy_2_move_8through16: - MOVQ (AX), CX - MOVQ -8(AX)(R13*1), R14 - MOVQ CX, (R10) - MOVQ R14, -8(R10)(R13*1) - ADDQ R13, AX - ADDQ R13, R10 + MOVQ (CX), R13 + MOVQ -8(CX)(AX*1), R14 + MOVQ R13, (R10) + MOVQ R14, -8(R10)(AX*1) + ADDQ AX, CX + ADDQ AX, R10 copy_2_end: JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADDQ R13, R12 + ADDQ AX, R12 copy_slow_3: - MOVB (AX), CL - MOVB CL, (R10) - INCQ AX - INCQ R10 - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (CX), R13 + MOVB R13, (R10) + INCQ CX + INCQ R10 + DECQ AX + JNZ copy_slow_3 handle_loop: - MOVQ ctx+16(FP), AX - DECQ 96(AX) + DECQ 32(SP) JNS sequenceDecs_decodeSync_safe_amd64_main_loop loop_finished: @@ -3468,6 +3497,13 @@ loop_finished: MOVB BL, 40(AX) MOVQ SI, 32(AX) + // s.seqSize += outPosition - ctx.outPosition + MOVQ ctx+16(FP), AX + MOVQ s+0(FP), CX + MOVQ R12, DX + SUBQ 136(AX), DX + ADDQ DX, 256(CX) + // Update the context MOVQ ctx+16(FP), AX MOVQ R12, 136(AX) @@ -3481,7 +3517,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: - MOVQ 16(SP), AX + MOVQ 48(SP), AX MOVQ ctx+16(FP), CX MOVQ AX, 216(CX) MOVQ $0x00000001, ret+24(FP) @@ -3490,7 +3526,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: MOVQ ctx+16(FP), AX - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ $0x00000002, ret+24(FP) RET @@ -3498,7 +3534,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVQ ctx+16(FP), AX - MOVQ 8(SP), CX + MOVQ 40(SP), CX MOVQ CX, 224(AX) MOVQ R12, 136(AX) MOVQ $0x00000003, ret+24(FP) @@ -3507,7 +3543,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) MOVQ $0x00000004, ret+24(FP) RET @@ -3520,9 +3556,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ R12, 136(AX) MOVQ $0x00000005, ret+24(FP) @@ -3530,7 +3566,7 @@ error_not_enough_space: // func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: BMI, BMI2, CMOV, SSE -TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $96-32 MOVQ br+8(FP), BX MOVQ 24(BX), AX MOVBQZX 40(BX), DX @@ -3542,26 +3578,34 @@ TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32 MOVQ 72(CX), SI MOVQ 80(CX), DI MOVQ 88(CX), R8 - XORQ R9, R9 + MOVQ (CX), R9 MOVQ R9, 8(SP) + MOVQ 24(CX), R9 MOVQ R9, 16(SP) + MOVQ 48(CX), R9 MOVQ R9, 24(SP) + MOVQ 96(CX), R9 + MOVQ R9, 32(SP) + XORQ R9, R9 + MOVQ R9, 40(SP) + MOVQ R9, 48(SP) + MOVQ R9, 56(SP) MOVQ 112(CX), R9 MOVQ 128(CX), R10 - MOVQ R10, 32(SP) + MOVQ R10, 64(SP) MOVQ 144(CX), R10 MOVQ 136(CX), R11 MOVQ 200(CX), R12 - MOVQ R12, 56(SP) + MOVQ R12, 88(SP) MOVQ 176(CX), R12 - MOVQ R12, 48(SP) + MOVQ R12, 80(SP) MOVQ 184(CX), CX - MOVQ CX, 40(SP) - MOVQ 40(SP), CX - ADDQ CX, 48(SP) + MOVQ CX, 72(SP) + MOVQ 72(SP), CX + ADDQ CX, 80(SP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - ADDQ R9, 32(SP) + ADDQ R9, 64(SP) // outBase += outPosition ADDQ R11, R9 @@ -3609,7 +3653,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_end: MOVQ R8, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 8(SP) + MOVQ CX, 40(SP) // Update match length MOVQ $0x00000808, CX @@ -3622,7 +3666,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_end: MOVQ DI, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 16(SP) + MOVQ CX, 48(SP) // Fill bitreader to have enough for the remaining CMPQ BX, $0x08 @@ -3664,14 +3708,13 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: MOVQ SI, CX SHRQ $0x20, CX ADDQ R14, CX - MOVQ CX, 24(SP) + MOVQ CX, 56(SP) // Fill bitreader for state updates MOVQ R12, (SP) MOVQ $0x00000808, CX BEXTRQ CX, R8, R12 - MOVQ ctx+16(FP), CX - CMPQ 96(CX), $0x00 + CMPQ 32(SP), $0x00 JZ sequenceDecs_decodeSync_safe_bmi2_skip_update LEAQ (SI)(DI*1), R13 ADDQ R8, R13 @@ -3689,8 +3732,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: ADDQ CX, R8 // Load ctx.ofTable - MOVQ ctx+16(FP), CX - MOVQ 48(CX), CX + MOVQ 24(SP), CX MOVQ (CX)(R8*8), R8 // Update Match Length State @@ -3700,8 +3742,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: ADDQ CX, DI // Load ctx.mlTable - MOVQ ctx+16(FP), CX - MOVQ 24(CX), CX + MOVQ 16(SP), CX MOVQ (CX)(DI*8), DI // Update Literal Length State @@ -3710,14 +3751,13 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: ADDQ CX, SI // Load ctx.llTable - MOVQ ctx+16(FP), CX - MOVQ (CX), CX + MOVQ 8(SP), CX MOVQ (CX)(SI*8), SI sequenceDecs_decodeSync_safe_bmi2_skip_update: // Adjust offset MOVQ s+0(FP), CX - MOVQ 8(SP), R13 + MOVQ 40(SP), R13 CMPQ R12, $0x01 JBE sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0 MOVUPS 144(CX), X0 @@ -3726,7 +3766,7 @@ sequenceDecs_decodeSync_safe_bmi2_skip_update: JMP sequenceDecs_decodeSync_safe_bmi2_after_adjust sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0: - CMPQ 24(SP), $0x00000000 + CMPQ 56(SP), $0x00000000 JNE sequenceDecs_decodeSync_safe_bmi2_adjust_offset_maybezero INCQ R13 JMP sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero @@ -3761,14 +3801,11 @@ sequenceDecs_decodeSync_safe_bmi2_adjust_skip: MOVQ R14, R13 sequenceDecs_decodeSync_safe_bmi2_after_adjust: - MOVQ R13, 8(SP) + MOVQ R13, 40(SP) // Check values - MOVQ 16(SP), CX - MOVQ 24(SP), R12 - LEAQ (CX)(R12*1), R14 - MOVQ s+0(FP), R15 - ADDQ R14, 256(R15) + MOVQ 48(SP), CX + MOVQ 56(SP), R12 MOVQ ctx+16(FP), R14 SUBQ R12, 104(R14) JS error_not_enough_literals @@ -3780,20 +3817,16 @@ sequenceDecs_decodeSync_safe_bmi2_after_adjust: JNZ sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch sequenceDecs_decodeSync_safe_bmi2_match_len_ofs_ok: - MOVQ 24(SP), CX - MOVQ 8(SP), R12 - MOVQ 16(SP), R13 - // Check if we have enough space in s.out - LEAQ (CX)(R13*1), R14 + LEAQ (R12)(CX*1), R14 ADDQ R9, R14 - CMPQ R14, 32(SP) + CMPQ R14, 64(SP) JA error_not_enough_space // Copy literals - TESTQ CX, CX + TESTQ R12, R12 JZ check_offset - MOVQ CX, R14 + MOVQ R12, R14 SUBQ $0x10, R14 JB copy_1_small @@ -3811,70 +3844,70 @@ copy_1_loop: JMP copy_1_end copy_1_small: - CMPQ CX, $0x03 + CMPQ R12, $0x03 JE copy_1_move_3 JB copy_1_move_1or2 - CMPQ CX, $0x08 + CMPQ R12, $0x08 JB copy_1_move_4through7 JMP copy_1_move_8through16 copy_1_move_1or2: MOVB (R10), R14 - MOVB -1(R10)(CX*1), R15 + MOVB -1(R10)(R12*1), R15 MOVB R14, (R9) - MOVB R15, -1(R9)(CX*1) - ADDQ CX, R10 - ADDQ CX, R9 + MOVB R15, -1(R9)(R12*1) + ADDQ R12, R10 + ADDQ R12, R9 JMP copy_1_end copy_1_move_3: - MOVW (R10), R14 - MOVB 2(R10), R15 - MOVW R14, (R9) - MOVB R15, 2(R9) - ADDQ CX, R10 - ADDQ CX, R9 - JMP copy_1_end + MOVWQZX (R10), R14 + MOVB 2(R10), R15 + MOVW R14, (R9) + MOVB R15, 2(R9) + ADDQ R12, R10 + ADDQ R12, R9 + JMP copy_1_end copy_1_move_4through7: MOVL (R10), R14 - MOVL -4(R10)(CX*1), R15 + MOVL -4(R10)(R12*1), R15 MOVL R14, (R9) - MOVL R15, -4(R9)(CX*1) - ADDQ CX, R10 - ADDQ CX, R9 + MOVL R15, -4(R9)(R12*1) + ADDQ R12, R10 + ADDQ R12, R9 JMP copy_1_end copy_1_move_8through16: MOVQ (R10), R14 - MOVQ -8(R10)(CX*1), R15 + MOVQ -8(R10)(R12*1), R15 MOVQ R14, (R9) - MOVQ R15, -8(R9)(CX*1) - ADDQ CX, R10 - ADDQ CX, R9 + MOVQ R15, -8(R9)(R12*1) + ADDQ R12, R10 + ADDQ R12, R9 copy_1_end: - ADDQ CX, R11 + ADDQ R12, R11 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) check_offset: - MOVQ R11, CX - ADDQ 40(SP), CX - CMPQ R12, CX + MOVQ R11, R12 + ADDQ 72(SP), R12 + CMPQ R13, R12 JG error_match_off_too_big - CMPQ R12, 56(SP) + CMPQ R13, 88(SP) JG error_match_off_too_big // Copy match from history - MOVQ R12, CX - SUBQ R11, CX + MOVQ R13, R12 + SUBQ R11, R12 JLS copy_match - MOVQ 48(SP), R14 - SUBQ CX, R14 - CMPQ R13, CX + MOVQ 80(SP), R14 + SUBQ R12, R14 + CMPQ CX, R12 JG copy_all_from_history - MOVQ R13, CX - SUBQ $0x10, CX + MOVQ CX, R12 + SUBQ $0x10, R12 JB copy_4_small copy_4_loop: @@ -3882,54 +3915,54 @@ copy_4_loop: MOVUPS X0, (R9) ADDQ $0x10, R14 ADDQ $0x10, R9 - SUBQ $0x10, CX + SUBQ $0x10, R12 JAE copy_4_loop - LEAQ 16(R14)(CX*1), R14 - LEAQ 16(R9)(CX*1), R9 + LEAQ 16(R14)(R12*1), R14 + LEAQ 16(R9)(R12*1), R9 MOVUPS -16(R14), X0 MOVUPS X0, -16(R9) JMP copy_4_end copy_4_small: - CMPQ R13, $0x03 + CMPQ CX, $0x03 JE copy_4_move_3 - CMPQ R13, $0x08 + CMPQ CX, $0x08 JB copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVW (R14), CX - MOVB 2(R14), R12 - MOVW CX, (R9) - MOVB R12, 2(R9) - ADDQ R13, R14 - ADDQ R13, R9 - JMP copy_4_end + MOVWQZX (R14), R12 + MOVB 2(R14), R13 + MOVW R12, (R9) + MOVB R13, 2(R9) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_4_end copy_4_move_4through7: - MOVL (R14), CX - MOVL -4(R14)(R13*1), R12 - MOVL CX, (R9) - MOVL R12, -4(R9)(R13*1) - ADDQ R13, R14 - ADDQ R13, R9 + MOVL (R14), R12 + MOVL -4(R14)(CX*1), R13 + MOVL R12, (R9) + MOVL R13, -4(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 JMP copy_4_end copy_4_move_8through16: - MOVQ (R14), CX - MOVQ -8(R14)(R13*1), R12 - MOVQ CX, (R9) - MOVQ R12, -8(R9)(R13*1) - ADDQ R13, R14 - ADDQ R13, R9 + MOVQ (R14), R12 + MOVQ -8(R14)(CX*1), R13 + MOVQ R12, (R9) + MOVQ R13, -8(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 copy_4_end: - ADDQ R13, R11 + ADDQ CX, R11 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVQ CX, R15 + MOVQ R12, R15 SUBQ $0x10, R15 JB copy_5_small @@ -3947,141 +3980,140 @@ copy_5_loop: JMP copy_5_end copy_5_small: - CMPQ CX, $0x03 + CMPQ R12, $0x03 JE copy_5_move_3 JB copy_5_move_1or2 - CMPQ CX, $0x08 + CMPQ R12, $0x08 JB copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVB (R14), R15 - MOVB -1(R14)(CX*1), BP + MOVB -1(R14)(R12*1), BP MOVB R15, (R9) - MOVB BP, -1(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVB BP, -1(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 JMP copy_5_end copy_5_move_3: - MOVW (R14), R15 - MOVB 2(R14), BP - MOVW R15, (R9) - MOVB BP, 2(R9) - ADDQ CX, R14 - ADDQ CX, R9 - JMP copy_5_end + MOVWQZX (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R9) + MOVB BP, 2(R9) + ADDQ R12, R14 + ADDQ R12, R9 + JMP copy_5_end copy_5_move_4through7: MOVL (R14), R15 - MOVL -4(R14)(CX*1), BP + MOVL -4(R14)(R12*1), BP MOVL R15, (R9) - MOVL BP, -4(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVL BP, -4(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 JMP copy_5_end copy_5_move_8through16: MOVQ (R14), R15 - MOVQ -8(R14)(CX*1), BP + MOVQ -8(R14)(R12*1), BP MOVQ R15, (R9) - MOVQ BP, -8(R9)(CX*1) - ADDQ CX, R14 - ADDQ CX, R9 + MOVQ BP, -8(R9)(R12*1) + ADDQ R12, R14 + ADDQ R12, R9 copy_5_end: - ADDQ CX, R11 - SUBQ CX, R13 + ADDQ R12, R11 + SUBQ R12, CX // Copy match from the current buffer copy_match: - MOVQ R9, CX - SUBQ R12, CX + MOVQ R9, R12 + SUBQ R13, R12 // ml <= mo - CMPQ R13, R12 + CMPQ CX, R13 JA copy_overlapping_match // Copy non-overlapping match - ADDQ R13, R11 - MOVQ R13, R12 - SUBQ $0x10, R12 + ADDQ CX, R11 + MOVQ CX, R13 + SUBQ $0x10, R13 JB copy_2_small copy_2_loop: - MOVUPS (CX), X0 + MOVUPS (R12), X0 MOVUPS X0, (R9) - ADDQ $0x10, CX + ADDQ $0x10, R12 ADDQ $0x10, R9 - SUBQ $0x10, R12 + SUBQ $0x10, R13 JAE copy_2_loop - LEAQ 16(CX)(R12*1), CX - LEAQ 16(R9)(R12*1), R9 - MOVUPS -16(CX), X0 + LEAQ 16(R12)(R13*1), R12 + LEAQ 16(R9)(R13*1), R9 + MOVUPS -16(R12), X0 MOVUPS X0, -16(R9) JMP copy_2_end copy_2_small: - CMPQ R13, $0x03 + CMPQ CX, $0x03 JE copy_2_move_3 JB copy_2_move_1or2 - CMPQ R13, $0x08 + CMPQ CX, $0x08 JB copy_2_move_4through7 JMP copy_2_move_8through16 copy_2_move_1or2: - MOVB (CX), R12 - MOVB -1(CX)(R13*1), R14 - MOVB R12, (R9) - MOVB R14, -1(R9)(R13*1) - ADDQ R13, CX - ADDQ R13, R9 + MOVB (R12), R13 + MOVB -1(R12)(CX*1), R14 + MOVB R13, (R9) + MOVB R14, -1(R9)(CX*1) + ADDQ CX, R12 + ADDQ CX, R9 JMP copy_2_end copy_2_move_3: - MOVW (CX), R12 - MOVB 2(CX), R14 - MOVW R12, (R9) - MOVB R14, 2(R9) - ADDQ R13, CX - ADDQ R13, R9 - JMP copy_2_end + MOVWQZX (R12), R13 + MOVB 2(R12), R14 + MOVW R13, (R9) + MOVB R14, 2(R9) + ADDQ CX, R12 + ADDQ CX, R9 + JMP copy_2_end copy_2_move_4through7: - MOVL (CX), R12 - MOVL -4(CX)(R13*1), R14 - MOVL R12, (R9) - MOVL R14, -4(R9)(R13*1) - ADDQ R13, CX - ADDQ R13, R9 + MOVL (R12), R13 + MOVL -4(R12)(CX*1), R14 + MOVL R13, (R9) + MOVL R14, -4(R9)(CX*1) + ADDQ CX, R12 + ADDQ CX, R9 JMP copy_2_end copy_2_move_8through16: - MOVQ (CX), R12 - MOVQ -8(CX)(R13*1), R14 - MOVQ R12, (R9) - MOVQ R14, -8(R9)(R13*1) - ADDQ R13, CX - ADDQ R13, R9 + MOVQ (R12), R13 + MOVQ -8(R12)(CX*1), R14 + MOVQ R13, (R9) + MOVQ R14, -8(R9)(CX*1) + ADDQ CX, R12 + ADDQ CX, R9 copy_2_end: JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADDQ R13, R11 + ADDQ CX, R11 copy_slow_3: - MOVB (CX), R12 - MOVB R12, (R9) - INCQ CX - INCQ R9 - DECQ R13 - JNZ copy_slow_3 + MOVBQZX (R12), R13 + MOVB R13, (R9) + INCQ R12 + INCQ R9 + DECQ CX + JNZ copy_slow_3 handle_loop: - MOVQ ctx+16(FP), CX - DECQ 96(CX) + DECQ 32(SP) JNS sequenceDecs_decodeSync_safe_bmi2_main_loop loop_finished: @@ -4090,6 +4122,13 @@ loop_finished: MOVB DL, 40(CX) MOVQ BX, 32(CX) + // s.seqSize += outPosition - ctx.outPosition + MOVQ ctx+16(FP), AX + MOVQ s+0(FP), CX + MOVQ R11, DX + SUBQ 136(AX), DX + ADDQ DX, 256(CX) + // Update the context MOVQ ctx+16(FP), AX MOVQ R11, 136(AX) @@ -4103,7 +4142,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch: - MOVQ 16(SP), AX + MOVQ 48(SP), AX MOVQ ctx+16(FP), CX MOVQ AX, 216(CX) MOVQ $0x00000001, ret+24(FP) @@ -4112,7 +4151,7 @@ sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big: MOVQ ctx+16(FP), AX - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ $0x00000002, ret+24(FP) RET @@ -4120,7 +4159,7 @@ sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVQ ctx+16(FP), AX - MOVQ 8(SP), CX + MOVQ 40(SP), CX MOVQ CX, 224(AX) MOVQ R11, 136(AX) MOVQ $0x00000003, ret+24(FP) @@ -4129,7 +4168,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) MOVQ $0x00000004, ret+24(FP) RET @@ -4142,9 +4181,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX - MOVQ 24(SP), CX + MOVQ 56(SP), CX MOVQ CX, 208(AX) - MOVQ 16(SP), CX + MOVQ 48(SP), CX MOVQ CX, 216(AX) MOVQ R11, 136(AX) MOVQ $0x00000005, ret+24(FP) diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s index 6f54ef21ba..56391bfc18 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s @@ -1,11 +1,11 @@ // Code generated by command: go run gen.go -out ../seqdec.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. // EXPERIMENTAL arm64 output lowered from an amd64 avo program. -//go:build arm64 && !appengine && !noasm && gc && !noasm +//go:build arm64 && (!appengine && !noasm && gc && !noasm) // func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV -TEXT ·sequenceDecs_decode_arm64(SB), $8-32 +TEXT ·sequenceDecs_decode_arm64(SB), $40-32 MOVD br+8(FP), R1 MOVD 24(R1), R2 MOVBU 40(R1), R3 @@ -17,6 +17,14 @@ TEXT ·sequenceDecs_decode_arm64(SB), $8-32 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 + MOVD (R0), R1 + MOVD R1, 16(RSP) + MOVD 24(R0), R1 + MOVD R1, 24(RSP) + MOVD 48(R0), R1 + MOVD R1, 32(RSP) + MOVD 96(R0), R1 + MOVD R1, 40(RSP) MOVD 104(R0), R9 MOVD s+0(FP), R0 MOVD 144(R0), R10 @@ -29,8 +37,7 @@ sequenceDecs_decode_amd64_main_loop: // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 BLT sequenceDecs_decode_amd64_fill_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R13, R13 MOVD (R13), R2 SUB R0, R5, R5 @@ -57,53 +64,32 @@ sequenceDecs_decode_amd64_fill_check_overread: sequenceDecs_decode_amd64_fill_end: // Update offset MOVD R8, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_amd64_of_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_amd64_of_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_amd64_of_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_amd64_of_update_zero: MOVD R0, 16(R9) // Update match length MOVD R7, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_amd64_ml_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_amd64_ml_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_amd64_ml_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_amd64_ml_update_zero: MOVD R0, 8(R9) // Fill bitreader to have enough for the remaining CMP $0x08, R5 BLT sequenceDecs_decode_amd64_fill_2_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R13, R13 MOVD (R13), R2 SUB R0, R5, R5 @@ -130,98 +116,64 @@ sequenceDecs_decode_amd64_fill_2_check_overread: sequenceDecs_decode_amd64_fill_2_end: // Update literal length MOVD R6, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_amd64_ll_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_amd64_ll_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_amd64_ll_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_amd64_ll_update_zero: MOVD R0, (R9) // Fill bitreader for state updates - MOVD R13, 8(RSP) - MOVD R8, R0 - LSR $0x08, R0, R0 - MOVBU R0, R0 - MOVD ctx+16(FP), R1 - MOVD 96(R1), R16 - CMP $0x00, R16 - BEQ sequenceDecs_decode_amd64_skip_update + MOVD R13, 8(RSP) + UBFX $8, R8, $8, R0 + MOVD 40(RSP), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decode_amd64_skip_update // Update Literal Length State MOVBU R6, R13 LSRW $0x10, R6, R6 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R6, R6 // Load ctx.llTable - MOVD ctx+16(FP), R1 - MOVD (R1), R1 - ADD R6<<3, R1, R15 - MOVD (R15), R6 + MOVD 16(RSP), R1 + MOVD (R1)(R6<<3), R6 // Update Match Length State MOVBU R7, R13 LSRW $0x10, R7, R7 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R7, R7 // Load ctx.mlTable - MOVD ctx+16(FP), R1 - MOVD 24(R1), R1 - ADD R7<<3, R1, R15 - MOVD (R15), R7 + MOVD 24(RSP), R1 + MOVD (R1)(R7<<3), R7 // Update Offset State MOVBU R8, R13 LSRW $0x10, R8, R8 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R8, R8 // Load ctx.ofTable - MOVD ctx+16(FP), R1 - MOVD 48(R1), R1 - ADD R8<<3, R1, R15 - MOVD (R15), R8 + MOVD 32(RSP), R1 + MOVD (R1)(R8<<3), R8 sequenceDecs_decode_amd64_skip_update: // Adjust offset @@ -306,10 +258,9 @@ sequenceDecs_decode_amd64_after_adjust: sequenceDecs_decode_amd64_match_len_ofs_ok: ADD $0x18, R9, R9 - MOVD ctx+16(FP), R0 - MOVD 96(R0), R16 + MOVD 40(RSP), R16 SUBS $1, R16, R16 - MOVD R16, 96(R0) + MOVD R16, 40(RSP) BPL sequenceDecs_decode_amd64_main_loop MOVD s+0(FP), R0 MOVD R10, 144(R0) @@ -321,42 +272,60 @@ sequenceDecs_decode_amd64_match_len_ofs_ok: MOVD R5, 32(R0) // Return success + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000000, R16 MOVD R16, ret+24(FP) RET // Return with match length error sequenceDecs_decode_amd64_error_match_len_ofs_mismatch: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000001, R16 MOVD R16, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_amd64_error_match_len_too_big: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) RET // Return with match offset too long error + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000003, R16 MOVD R16, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) RET // Return with overread error error_overread: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000006, R16 MOVD R16, ret+24(FP) RET // func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV -TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32 +TEXT ·sequenceDecs_decode_56_arm64(SB), $40-32 MOVD br+8(FP), R1 MOVD 24(R1), R2 MOVBU 40(R1), R3 @@ -368,6 +337,14 @@ TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 + MOVD (R0), R1 + MOVD R1, 16(RSP) + MOVD 24(R0), R1 + MOVD R1, 24(RSP) + MOVD 48(R0), R1 + MOVD R1, 32(RSP) + MOVD 96(R0), R1 + MOVD R1, 40(RSP) MOVD 104(R0), R9 MOVD s+0(FP), R0 MOVD 144(R0), R10 @@ -380,8 +357,7 @@ sequenceDecs_decode_56_amd64_main_loop: // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 BLT sequenceDecs_decode_56_amd64_fill_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R13, R13 MOVD (R13), R2 SUB R0, R5, R5 @@ -408,142 +384,88 @@ sequenceDecs_decode_56_amd64_fill_check_overread: sequenceDecs_decode_56_amd64_fill_end: // Update offset MOVD R8, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_56_amd64_of_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_56_amd64_of_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_56_amd64_of_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_56_amd64_of_update_zero: MOVD R0, 16(R9) // Update match length MOVD R7, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_56_amd64_ml_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_56_amd64_ml_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_56_amd64_ml_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_56_amd64_ml_update_zero: MOVD R0, 8(R9) // Update literal length MOVD R6, R0 - MOVD R3, R1 - MOVD R2, R14 - LSL R1, R14, R14 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decode_56_amd64_ll_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decode_56_amd64_ll_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decode_56_amd64_ll_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R14, R14 ADD R14, R0, R0 - -sequenceDecs_decode_56_amd64_ll_update_zero: MOVD R0, (R9) // Fill bitreader for state updates - MOVD R13, 8(RSP) - MOVD R8, R0 - LSR $0x08, R0, R0 - MOVBU R0, R0 - MOVD ctx+16(FP), R1 - MOVD 96(R1), R16 - CMP $0x00, R16 - BEQ sequenceDecs_decode_56_amd64_skip_update + MOVD R13, 8(RSP) + UBFX $8, R8, $8, R0 + MOVD 40(RSP), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decode_56_amd64_skip_update // Update Literal Length State MOVBU R6, R13 LSRW $0x10, R6, R6 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R6, R6 // Load ctx.llTable - MOVD ctx+16(FP), R1 - MOVD (R1), R1 - ADD R6<<3, R1, R15 - MOVD (R15), R6 + MOVD 16(RSP), R1 + MOVD (R1)(R6<<3), R6 // Update Match Length State MOVBU R7, R13 LSRW $0x10, R7, R7 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R7, R7 // Load ctx.mlTable - MOVD ctx+16(FP), R1 - MOVD 24(R1), R1 - ADD R7<<3, R1, R15 - MOVD (R15), R7 + MOVD 24(RSP), R1 + MOVD (R1)(R7<<3), R7 // Update Offset State MOVBU R8, R13 LSRW $0x10, R8, R8 - ADD R13, R3, R1 - MOVD R2, R14 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R14, R14 - MOVD $0x00000001, R4 - BFI $0, R13, $8, R1 - LSLW R1, R4, R4 - SUBW $1, R4, R4 - AND R4, R14, R14 + LSL R3, R2, R14 + LSR $0x01, R14, R14 + ADD R13, R3, R3 + EOR $0x3f, R13, R13 + LSR R13, R14, R14 ADD R14, R8, R8 // Load ctx.ofTable - MOVD ctx+16(FP), R1 - MOVD 48(R1), R1 - ADD R8<<3, R1, R15 - MOVD (R15), R8 + MOVD 32(RSP), R1 + MOVD (R1)(R8<<3), R8 sequenceDecs_decode_56_amd64_skip_update: // Adjust offset @@ -628,10 +550,9 @@ sequenceDecs_decode_56_amd64_after_adjust: sequenceDecs_decode_56_amd64_match_len_ofs_ok: ADD $0x18, R9, R9 - MOVD ctx+16(FP), R0 - MOVD 96(R0), R16 + MOVD 40(RSP), R16 SUBS $1, R16, R16 - MOVD R16, 96(R0) + MOVD R16, 40(RSP) BPL sequenceDecs_decode_56_amd64_main_loop MOVD s+0(FP), R0 MOVD R10, 144(R0) @@ -643,35 +564,53 @@ sequenceDecs_decode_56_amd64_match_len_ofs_ok: MOVD R5, 32(R0) // Return success + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000000, R16 MOVD R16, ret+24(FP) RET // Return with match length error sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000001, R16 MOVD R16, ret+24(FP) RET // Return with match too long error sequenceDecs_decode_56_amd64_error_match_len_too_big: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) RET // Return with match offset too long error + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000003, R16 MOVD R16, ret+24(FP) RET // Return with not enough literals error error_not_enough_literals: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) RET // Return with overread error error_overread: + MOVD 40(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 96(R1) MOVD $0x00000006, R16 MOVD R16, ret+24(FP) RET @@ -711,24 +650,27 @@ main_loop: MOVD 8(R0), R12 // Copy literals - TST R10, R10 - BEQ check_offset - MOVD $0, R13 + FMOVQ (R5), F0 + FMOVQ F0, (R3) + CMP $0x10, R10 + BLS copy_1_end + MOVD $0x00000010, R13 copy_1: - ADD R13, R5, R15 - VLD1 (R15), [V0.B16] - ADD R13, R3, R15 - VST1 [V0.B16], (R15) - ADD $0x10, R13, R13 - CMP R10, R13 - BLO copy_1 - ADD R10, R5, R5 - ADD R10, R3, R3 - ADD R10, R6, R6 + ADD R13, R5, R15 + FMOVQ (R15), F0 + ADD R13, R3, R15 + FMOVQ F0, (R15) + ADD $0x10, R13, R13 + CMP R10, R13 + BLO copy_1 + +copy_1_end: + ADD R10, R5, R5 + ADD R10, R3, R3 + ADD R10, R6, R6 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) -check_offset: ADD R9, R6, R10 CMP R10, R11 BGT error_match_off_too_big @@ -748,21 +690,19 @@ check_offset: BLO copy_4_small copy_4_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R13, R13 - ADD $0x10, R3, R3 - SUBS $0x10, R10, R10 - BHS copy_4_loop - ADD R10, R13, R13 - ADD $16, R13, R13 - ADD R10, R3, R3 - ADD $16, R3, R3 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_4_end + FMOVQ (R13), F0 + FMOVQ F0, (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R10, R10 + BHS copy_4_loop + ADD R10, R13, R13 + ADD $16, R13, R13 + ADD R10, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R3) + JMP copy_4_end copy_4_small: CMP $0x03, R12 @@ -816,21 +756,19 @@ copy_all_from_history: BLO copy_5_small copy_5_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R13, R13 - ADD $0x10, R3, R3 - SUBS $0x10, R14, R14 - BHS copy_5_loop - ADD R14, R13, R13 - ADD $16, R13, R13 - ADD R14, R3, R3 - ADD $16, R3, R3 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_5_end + FMOVQ (R13), F0 + FMOVQ F0, (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R3) + JMP copy_5_end copy_5_small: CMP $0x03, R10 @@ -898,26 +836,35 @@ copy_match: BHI copy_overlapping_match // Copy non-overlapping match - ADD R12, R6, R6 - MOVD R3, R11 - ADD R12, R3, R3 + ADD R12, R6, R6 + FMOVQ (R10), F0 + FMOVQ F0, (R3) + CMP $0x10, R12 + BHI copy_2_long + ADD R12, R3, R3 + JMP handle_loop + +copy_2_long: + ADD $16, R3, R11 + ADD R12, R3, R3 + ADD $0x10, R10, R10 + SUB $0x10, R12, R12 copy_2: - VLD1 (R10), [V0.B16] - VST1 [V0.B16], (R11) - ADD $0x10, R10, R10 - ADD $0x10, R11, R11 - SUBS $0x10, R12, R12 - BHI copy_2 - JMP handle_loop + FMOVQ (R10), F0 + FMOVQ F0, (R11) + ADD $0x10, R10, R10 + ADD $0x10, R11, R11 + SUBS $0x10, R12, R12 + BHI copy_2 + JMP handle_loop // Copy overlapping match copy_overlapping_match: ADD R12, R6, R6 copy_slow_3: - MOVBU (R10), R16 - BFI $0, R16, $8, R11 + MOVBU (R10), R11 MOVB R11, (R3) ADD $1, R10, R10 ADD $1, R3, R3 @@ -1002,21 +949,19 @@ main_loop: BLO copy_1_small copy_1_loop: - VLD1 (R5), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R5, R5 - ADD $0x10, R3, R3 - SUBS $0x10, R13, R13 - BHS copy_1_loop - ADD R13, R5, R5 - ADD $16, R5, R5 - ADD R13, R3, R3 - ADD $16, R3, R3 - ADD $-16, R5, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_1_end + FMOVQ (R5), F0 + FMOVQ F0, (R3) + ADD $0x10, R5, R5 + ADD $0x10, R3, R3 + SUBS $0x10, R13, R13 + BHS copy_1_loop + ADD R13, R5, R5 + ADD $16, R5, R5 + ADD R13, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R5), F0 + FMOVQ F0, -16(R3) + JMP copy_1_end copy_1_small: CMP $0x03, R10 @@ -1094,21 +1039,19 @@ check_offset: BLO copy_4_small copy_4_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R13, R13 - ADD $0x10, R3, R3 - SUBS $0x10, R10, R10 - BHS copy_4_loop - ADD R10, R13, R13 - ADD $16, R13, R13 - ADD R10, R3, R3 - ADD $16, R3, R3 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_4_end + FMOVQ (R13), F0 + FMOVQ F0, (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R10, R10 + BHS copy_4_loop + ADD R10, R13, R13 + ADD $16, R13, R13 + ADD R10, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R3) + JMP copy_4_end copy_4_small: CMP $0x03, R12 @@ -1162,21 +1105,19 @@ copy_all_from_history: BLO copy_5_small copy_5_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R13, R13 - ADD $0x10, R3, R3 - SUBS $0x10, R14, R14 - BHS copy_5_loop - ADD R14, R13, R13 - ADD $16, R13, R13 - ADD R14, R3, R3 - ADD $16, R3, R3 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_5_end + FMOVQ (R13), F0 + FMOVQ F0, (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R3) + JMP copy_5_end copy_5_small: CMP $0x03, R10 @@ -1250,21 +1191,19 @@ copy_match: BLO copy_2_small copy_2_loop: - VLD1 (R10), [V0.B16] - VST1 [V0.B16], (R3) - ADD $0x10, R10, R10 - ADD $0x10, R3, R3 - SUBS $0x10, R11, R11 - BHS copy_2_loop - ADD R11, R10, R10 - ADD $16, R10, R10 - ADD R11, R3, R3 - ADD $16, R3, R3 - ADD $-16, R10, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R3, R15 - VST1 [V0.B16], (R15) - JMP copy_2_end + FMOVQ (R10), F0 + FMOVQ F0, (R3) + ADD $0x10, R10, R10 + ADD $0x10, R3, R3 + SUBS $0x10, R11, R11 + BHS copy_2_loop + ADD R11, R10, R10 + ADD $16, R10, R10 + ADD R11, R3, R3 + ADD $16, R3, R3 + FMOVQ -16(R10), F0 + FMOVQ F0, -16(R3) + JMP copy_2_end copy_2_small: CMP $0x03, R12 @@ -1326,8 +1265,7 @@ copy_overlapping_match: ADD R12, R6, R6 copy_slow_3: - MOVBU (R10), R16 - BFI $0, R16, $8, R11 + MOVBU (R10), R11 MOVB R11, (R3) ADD $1, R10, R10 ADD $1, R3, R3 @@ -1376,7 +1314,7 @@ empty_seqs: // func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: CMOV, SSE -TEXT ·sequenceDecs_decodeSync_arm64(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_arm64(SB), $96-32 MOVD br+8(FP), R1 MOVD 24(R1), R2 MOVBU 40(R1), R3 @@ -1388,30 +1326,38 @@ TEXT ·sequenceDecs_decodeSync_arm64(SB), $64-32 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 - MOVD $0, R1 + MOVD (R0), R1 MOVD R1, 16(RSP) + MOVD 24(R0), R1 MOVD R1, 24(RSP) + MOVD 48(R0), R1 MOVD R1, 32(RSP) + MOVD 96(R0), R1 + MOVD R1, 40(RSP) + MOVD $0, R1 + MOVD R1, 48(RSP) + MOVD R1, 56(RSP) + MOVD R1, 64(RSP) MOVD 112(R0), R9 MOVD 128(R0), R1 - MOVD R1, 40(RSP) + MOVD R1, 72(RSP) MOVD 144(R0), R10 MOVD 136(R0), R11 MOVD 200(R0), R1 - MOVD R1, 64(RSP) + MOVD R1, 96(RSP) MOVD 176(R0), R1 - MOVD R1, 56(RSP) + MOVD R1, 88(RSP) MOVD 184(R0), R0 - MOVD R0, 48(RSP) - MOVD 48(RSP), R0 - MOVD 56(RSP), R16 + MOVD R0, 80(RSP) + MOVD 80(RSP), R0 + MOVD 88(RSP), R16 ADD R0, R16, R16 - MOVD R16, 56(RSP) + MOVD R16, 88(RSP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - MOVD 40(RSP), R16 + MOVD 72(RSP), R16 ADD R9, R16, R16 - MOVD R16, 40(RSP) + MOVD R16, 72(RSP) // outBase += outPosition ADD R11, R9, R9 @@ -1422,8 +1368,7 @@ sequenceDecs_decodeSync_amd64_main_loop: // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 BLT sequenceDecs_decodeSync_amd64_fill_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R12, R12 MOVD (R12), R2 SUB R0, R5, R5 @@ -1450,53 +1395,32 @@ sequenceDecs_decodeSync_amd64_fill_check_overread: sequenceDecs_decodeSync_amd64_fill_end: // Update offset MOVD R8, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_amd64_of_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_amd64_of_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_amd64_of_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_amd64_of_update_zero: - MOVD R0, 16(RSP) + MOVD R0, 48(RSP) // Update match length MOVD R7, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_amd64_ml_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_amd64_ml_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_amd64_ml_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_amd64_ml_update_zero: - MOVD R0, 24(RSP) + MOVD R0, 56(RSP) // Fill bitreader to have enough for the remaining CMP $0x08, R5 BLT sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R12, R12 MOVD (R12), R2 SUB R0, R5, R5 @@ -1523,114 +1447,78 @@ sequenceDecs_decodeSync_amd64_fill_2_check_overread: sequenceDecs_decodeSync_amd64_fill_2_end: // Update literal length MOVD R6, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_amd64_ll_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_amd64_ll_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_amd64_ll_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_amd64_ll_update_zero: - MOVD R0, 32(RSP) + MOVD R0, 64(RSP) // Fill bitreader for state updates - MOVD R12, 8(RSP) - MOVD R8, R0 - LSR $0x08, R0, R0 - MOVBU R0, R0 - MOVD ctx+16(FP), R1 - MOVD 96(R1), R16 - CMP $0x00, R16 - BEQ sequenceDecs_decodeSync_amd64_skip_update + MOVD R12, 8(RSP) + UBFX $8, R8, $8, R0 + MOVD 40(RSP), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decodeSync_amd64_skip_update // Update Literal Length State MOVBU R6, R12 LSRW $0x10, R6, R6 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R6, R6 // Load ctx.llTable - MOVD ctx+16(FP), R1 - MOVD (R1), R1 - ADD R6<<3, R1, R15 - MOVD (R15), R6 + MOVD 16(RSP), R1 + MOVD (R1)(R6<<3), R6 // Update Match Length State MOVBU R7, R12 LSRW $0x10, R7, R7 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R7, R7 // Load ctx.mlTable - MOVD ctx+16(FP), R1 - MOVD 24(R1), R1 - ADD R7<<3, R1, R15 - MOVD (R15), R7 + MOVD 24(RSP), R1 + MOVD (R1)(R7<<3), R7 // Update Offset State MOVBU R8, R12 LSRW $0x10, R8, R8 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R8, R8 // Load ctx.ofTable - MOVD ctx+16(FP), R1 - MOVD 48(R1), R1 - ADD R8<<3, R1, R15 - MOVD (R15), R8 + MOVD 32(RSP), R1 + MOVD (R1)(R8<<3), R8 sequenceDecs_decodeSync_amd64_skip_update: // Adjust offset - MOVD s+0(FP), R1 - MOVD 16(RSP), R12 - CMP $0x01, R0 - BLS sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 - ADD $144, R1, R15 - VLD1 (R15), [V0.B16] - MOVD R12, 144(R1) - ADD $152, R1, R15 - VST1 [V0.B16], (R15) - JMP sequenceDecs_decodeSync_amd64_after_adjust + MOVD s+0(FP), R1 + MOVD 48(RSP), R12 + CMP $0x01, R0 + BLS sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 + FMOVQ 144(R1), F0 + MOVD R12, 144(R1) + FMOVQ F0, 152(R1) + JMP sequenceDecs_decodeSync_amd64_after_adjust sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0: - MOVD 32(RSP), R16 + MOVD 64(RSP), R16 CMP $0x00000000, R16 BNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero ADD $1, R12, R12 @@ -1668,16 +1556,11 @@ sequenceDecs_decodeSync_amd64_adjust_skip: MOVD R13, R12 sequenceDecs_decodeSync_amd64_after_adjust: - MOVD R12, 16(RSP) + MOVD R12, 48(RSP) // Check values - MOVD 24(RSP), R0 - MOVD 32(RSP), R1 - ADD R1, R0, R13 - MOVD s+0(FP), R14 - MOVD 256(R14), R16 - ADD R13, R16, R16 - MOVD R16, 256(R14) + MOVD 56(RSP), R0 + MOVD 64(RSP), R1 MOVD ctx+16(FP), R13 MOVD 104(R13), R16 SUBS R1, R16, R16 @@ -1691,159 +1574,154 @@ sequenceDecs_decodeSync_amd64_after_adjust: BNE sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_amd64_match_len_ofs_ok: - MOVD 32(RSP), R0 - MOVD 16(RSP), R1 - MOVD 24(RSP), R12 - // Check if we have enough space in s.out - ADD R12, R0, R13 + ADD R0, R1, R13 ADD $16, R13, R13 ADD R9, R13, R13 - MOVD 40(RSP), R16 + MOVD 72(RSP), R16 CMP R16, R13 BHI error_not_enough_space // Copy literals - TST R0, R0 - BEQ check_offset - MOVD $0, R13 + FMOVQ (R10), F0 + FMOVQ F0, (R9) + CMP $0x10, R1 + BLS copy_1_end + MOVD $0x00000010, R13 copy_1: - ADD R13, R10, R15 - VLD1 (R15), [V0.B16] - ADD R13, R9, R15 - VST1 [V0.B16], (R15) - ADD $0x10, R13, R13 - CMP R0, R13 - BLO copy_1 - ADD R0, R10, R10 - ADD R0, R9, R9 - ADD R0, R11, R11 + ADD R13, R10, R15 + FMOVQ (R15), F0 + ADD R13, R9, R15 + FMOVQ F0, (R15) + ADD $0x10, R13, R13 + CMP R1, R13 + BLO copy_1 + +copy_1_end: + ADD R1, R10, R10 + ADD R1, R9, R9 + ADD R1, R11, R11 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) -check_offset: - MOVD R11, R0 - MOVD 48(RSP), R16 - ADD R16, R0, R0 - CMP R0, R1 + MOVD R11, R1 + MOVD 80(RSP), R16 + ADD R16, R1, R1 + CMP R1, R12 BGT error_match_off_too_big - MOVD 64(RSP), R16 - CMP R16, R1 + MOVD 96(RSP), R16 + CMP R16, R12 BGT error_match_off_too_big // Copy match from history - MOVD R1, R0 - SUBS R11, R0, R0 + MOVD R12, R1 + SUBS R11, R1, R1 BLS copy_match - MOVD 56(RSP), R13 - SUB R0, R13, R13 - CMP R0, R12 + MOVD 88(RSP), R13 + SUB R1, R13, R13 + CMP R1, R0 BGT copy_all_from_history - MOVD R12, R0 - SUBS $0x10, R0, R0 + MOVD R0, R1 + SUBS $0x10, R1, R1 BLO copy_4_small copy_4_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R13, R13 - ADD $0x10, R9, R9 - SUBS $0x10, R0, R0 - BHS copy_4_loop - ADD R0, R13, R13 - ADD $16, R13, R13 - ADD R0, R9, R9 - ADD $16, R9, R9 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_4_end + FMOVQ (R13), F0 + FMOVQ F0, (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R1, R1 + BHS copy_4_loop + ADD R1, R13, R13 + ADD $16, R13, R13 + ADD R1, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R9) + JMP copy_4_end copy_4_small: - CMP $0x03, R12 + CMP $0x03, R0 BEQ copy_4_move_3 - CMP $0x08, R12 + CMP $0x08, R0 BLO copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVHU (R13), R0 + MOVHU (R13), R1 MOVBU 2(R13), R16 - BFI $0, R16, $8, R1 - MOVH R0, (R9) - MOVB R1, 2(R9) - ADD R12, R13, R13 - ADD R12, R9, R9 + BFI $0, R16, $8, R12 + MOVH R1, (R9) + MOVB R12, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 JMP copy_4_end copy_4_move_4through7: - MOVWU (R13), R0 - ADD R12, R13, R15 - MOVWU -4(R15), R1 - MOVW R0, (R9) - ADD R12, R9, R15 - MOVW R1, -4(R15) - ADD R12, R13, R13 - ADD R12, R9, R9 + MOVWU (R13), R1 + ADD R0, R13, R15 + MOVWU -4(R15), R12 + MOVW R1, (R9) + ADD R0, R9, R15 + MOVW R12, -4(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 JMP copy_4_end copy_4_move_8through16: - MOVD (R13), R0 - ADD R12, R13, R15 - MOVD -8(R15), R1 - MOVD R0, (R9) - ADD R12, R9, R15 - MOVD R1, -8(R15) - ADD R12, R13, R13 - ADD R12, R9, R9 + MOVD (R13), R1 + ADD R0, R13, R15 + MOVD -8(R15), R12 + MOVD R1, (R9) + ADD R0, R9, R15 + MOVD R12, -8(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 copy_4_end: - ADD R12, R11, R11 + ADD R0, R11, R11 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVD R0, R14 + MOVD R1, R14 SUBS $0x10, R14, R14 BLO copy_5_small copy_5_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R13, R13 - ADD $0x10, R9, R9 - SUBS $0x10, R14, R14 - BHS copy_5_loop - ADD R14, R13, R13 - ADD $16, R13, R13 - ADD R14, R9, R9 - ADD $16, R9, R9 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_5_end + FMOVQ (R13), F0 + FMOVQ F0, (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R9) + JMP copy_5_end copy_5_small: - CMP $0x03, R0 + CMP $0x03, R1 BEQ copy_5_move_3 BLO copy_5_move_1or2 - CMP $0x08, R0 + CMP $0x08, R1 BLO copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVBU (R13), R16 BFI $0, R16, $8, R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVBU -1(R15), R16 BFI $0, R16, $8, R4 MOVB R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVB R4, -1(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_3: @@ -1852,76 +1730,84 @@ copy_5_move_3: BFI $0, R16, $8, R4 MOVH R14, (R9) MOVB R4, 2(R9) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVWU -4(R15), R4 MOVW R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVW R4, -4(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_8through16: MOVD (R13), R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVD -8(R15), R4 MOVD R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVD R4, -8(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 copy_5_end: - ADD R0, R11, R11 - SUB R0, R12, R12 + ADD R1, R11, R11 + SUB R1, R0, R0 // Copy match from the current buffer copy_match: - MOVD R9, R0 - SUB R1, R0, R0 + MOVD R9, R1 + SUB R12, R1, R1 // ml <= mo - CMP R1, R12 + CMP R12, R0 BHI copy_overlapping_match // Copy non-overlapping match - ADD R12, R11, R11 - MOVD R9, R1 - ADD R12, R9, R9 + ADD R0, R11, R11 + FMOVQ (R1), F0 + FMOVQ F0, (R9) + CMP $0x10, R0 + BHI copy_2_long + ADD R0, R9, R9 + JMP handle_loop + +copy_2_long: + ADD $16, R9, R12 + ADD R0, R9, R9 + ADD $0x10, R1, R1 + SUB $0x10, R0, R0 copy_2: - VLD1 (R0), [V0.B16] - VST1 [V0.B16], (R1) - ADD $0x10, R0, R0 - ADD $0x10, R1, R1 - SUBS $0x10, R12, R12 - BHI copy_2 - JMP handle_loop + FMOVQ (R1), F0 + FMOVQ F0, (R12) + ADD $0x10, R1, R1 + ADD $0x10, R12, R12 + SUBS $0x10, R0, R0 + BHI copy_2 + JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADD R12, R11, R11 + ADD R0, R11, R11 copy_slow_3: - MOVBU (R0), R16 - BFI $0, R16, $8, R1 - MOVB R1, (R9) - ADD $1, R0, R0 + MOVBU (R1), R12 + MOVB R12, (R9) + ADD $1, R1, R1 ADD $1, R9, R9 - SUBS $1, R12, R12 + SUBS $1, R0, R0 BNE copy_slow_3 handle_loop: - MOVD ctx+16(FP), R0 - MOVD 96(R0), R16 + MOVD 40(RSP), R16 SUBS $1, R16, R16 - MOVD R16, 96(R0) + MOVD R16, 40(RSP) BPL sequenceDecs_decodeSync_amd64_main_loop loop_finished: @@ -1930,6 +1816,16 @@ loop_finished: MOVB R3, 40(R0) MOVD R5, 32(R0) + // s.seqSize += outPosition - ctx.outPosition + MOVD ctx+16(FP), R0 + MOVD s+0(FP), R1 + MOVD R11, R2 + MOVD 136(R0), R16 + SUB R16, R2, R2 + MOVD 256(R1), R16 + ADD R2, R16, R16 + MOVD R16, 256(R1) + // Update the context MOVD ctx+16(FP), R0 MOVD R11, 136(R0) @@ -1944,7 +1840,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: - MOVD 24(RSP), R0 + MOVD 56(RSP), R0 MOVD ctx+16(FP), R1 MOVD R0, 216(R1) MOVD $0x00000001, R16 @@ -1954,7 +1850,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_amd64_error_match_len_too_big: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 56(RSP), R1 MOVD R1, 216(R0) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) @@ -1963,7 +1859,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVD ctx+16(FP), R0 - MOVD 16(RSP), R1 + MOVD 48(RSP), R1 MOVD R1, 224(R0) MOVD R11, 136(R0) MOVD $0x00000003, R16 @@ -1973,7 +1869,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVD ctx+16(FP), R0 - MOVD 32(RSP), R1 + MOVD 64(RSP), R1 MOVD R1, 208(R0) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) @@ -1988,9 +1884,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVD ctx+16(FP), R0 - MOVD 32(RSP), R1 + MOVD 64(RSP), R1 MOVD R1, 208(R0) - MOVD 24(RSP), R1 + MOVD 56(RSP), R1 MOVD R1, 216(R0) MOVD R11, 136(R0) MOVD $0x00000005, R16 @@ -2001,7 +1897,7 @@ error_not_enough_space: // func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // Requires: CMOV, SSE -TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $64-32 +TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $96-32 MOVD br+8(FP), R1 MOVD 24(R1), R2 MOVBU 40(R1), R3 @@ -2013,30 +1909,38 @@ TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $64-32 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 - MOVD $0, R1 + MOVD (R0), R1 MOVD R1, 16(RSP) + MOVD 24(R0), R1 MOVD R1, 24(RSP) + MOVD 48(R0), R1 MOVD R1, 32(RSP) + MOVD 96(R0), R1 + MOVD R1, 40(RSP) + MOVD $0, R1 + MOVD R1, 48(RSP) + MOVD R1, 56(RSP) + MOVD R1, 64(RSP) MOVD 112(R0), R9 MOVD 128(R0), R1 - MOVD R1, 40(RSP) + MOVD R1, 72(RSP) MOVD 144(R0), R10 MOVD 136(R0), R11 MOVD 200(R0), R1 - MOVD R1, 64(RSP) + MOVD R1, 96(RSP) MOVD 176(R0), R1 - MOVD R1, 56(RSP) + MOVD R1, 88(RSP) MOVD 184(R0), R0 - MOVD R0, 48(RSP) - MOVD 48(RSP), R0 - MOVD 56(RSP), R16 + MOVD R0, 80(RSP) + MOVD 80(RSP), R0 + MOVD 88(RSP), R16 ADD R0, R16, R16 - MOVD R16, 56(RSP) + MOVD R16, 88(RSP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - MOVD 40(RSP), R16 + MOVD 72(RSP), R16 ADD R9, R16, R16 - MOVD R16, 40(RSP) + MOVD R16, 72(RSP) // outBase += outPosition ADD R11, R9, R9 @@ -2047,8 +1951,7 @@ sequenceDecs_decodeSync_safe_amd64_main_loop: // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 BLT sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R12, R12 MOVD (R12), R2 SUB R0, R5, R5 @@ -2075,53 +1978,32 @@ sequenceDecs_decodeSync_safe_amd64_fill_check_overread: sequenceDecs_decodeSync_safe_amd64_fill_end: // Update offset MOVD R8, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_safe_amd64_of_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_safe_amd64_of_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_safe_amd64_of_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_safe_amd64_of_update_zero: - MOVD R0, 16(RSP) + MOVD R0, 48(RSP) // Update match length MOVD R7, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_safe_amd64_ml_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_safe_amd64_ml_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_safe_amd64_ml_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_safe_amd64_ml_update_zero: - MOVD R0, 24(RSP) + MOVD R0, 56(RSP) // Fill bitreader to have enough for the remaining CMP $0x08, R5 BLT sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte - MOVD R3, R0 - LSR $0x03, R0, R0 + LSR $0x03, R3, R0 SUB R0, R12, R12 MOVD (R12), R2 SUB R0, R5, R5 @@ -2148,114 +2030,78 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread: sequenceDecs_decodeSync_safe_amd64_fill_2_end: // Update literal length MOVD R6, R0 - MOVD R3, R1 - MOVD R2, R13 - LSL R1, R13, R13 - UBFX $8, R0, $8, R16 - BFI $0, R16, $8, R1 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + UBFX $8, R0, $8, R1 LSR $0x20, R0, R0 - TST R1, R1 - BEQ sequenceDecs_decodeSync_safe_amd64_ll_update_zero ADD R1, R3, R3 - CMP $0x40, R3 - BHI sequenceDecs_decodeSync_safe_amd64_ll_update_zero - CMP $0x40, R1 - BHS sequenceDecs_decodeSync_safe_amd64_ll_update_zero - NEG R1, R1 + EOR $0x3f, R1, R1 LSR R1, R13, R13 ADD R13, R0, R0 - -sequenceDecs_decodeSync_safe_amd64_ll_update_zero: - MOVD R0, 32(RSP) + MOVD R0, 64(RSP) // Fill bitreader for state updates - MOVD R12, 8(RSP) - MOVD R8, R0 - LSR $0x08, R0, R0 - MOVBU R0, R0 - MOVD ctx+16(FP), R1 - MOVD 96(R1), R16 - CMP $0x00, R16 - BEQ sequenceDecs_decodeSync_safe_amd64_skip_update + MOVD R12, 8(RSP) + UBFX $8, R8, $8, R0 + MOVD 40(RSP), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decodeSync_safe_amd64_skip_update // Update Literal Length State MOVBU R6, R12 LSRW $0x10, R6, R6 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R6, R6 // Load ctx.llTable - MOVD ctx+16(FP), R1 - MOVD (R1), R1 - ADD R6<<3, R1, R15 - MOVD (R15), R6 + MOVD 16(RSP), R1 + MOVD (R1)(R6<<3), R6 // Update Match Length State MOVBU R7, R12 LSRW $0x10, R7, R7 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R7, R7 // Load ctx.mlTable - MOVD ctx+16(FP), R1 - MOVD 24(R1), R1 - ADD R7<<3, R1, R15 - MOVD (R15), R7 + MOVD 24(RSP), R1 + MOVD (R1)(R7<<3), R7 // Update Offset State MOVBU R8, R12 LSRW $0x10, R8, R8 - ADD R12, R3, R1 - MOVD R2, R13 - MOVD R1, R3 - NEG R1, R16 - ROR R16, R13, R13 - MOVD $0x00000001, R14 - BFI $0, R12, $8, R1 - LSLW R1, R14, R14 - SUBW $1, R14, R14 - AND R14, R13, R13 + LSL R3, R2, R13 + LSR $0x01, R13, R13 + ADD R12, R3, R3 + EOR $0x3f, R12, R12 + LSR R12, R13, R13 ADD R13, R8, R8 // Load ctx.ofTable - MOVD ctx+16(FP), R1 - MOVD 48(R1), R1 - ADD R8<<3, R1, R15 - MOVD (R15), R8 + MOVD 32(RSP), R1 + MOVD (R1)(R8<<3), R8 sequenceDecs_decodeSync_safe_amd64_skip_update: // Adjust offset - MOVD s+0(FP), R1 - MOVD 16(RSP), R12 - CMP $0x01, R0 - BLS sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 - ADD $144, R1, R15 - VLD1 (R15), [V0.B16] - MOVD R12, 144(R1) - ADD $152, R1, R15 - VST1 [V0.B16], (R15) - JMP sequenceDecs_decodeSync_safe_amd64_after_adjust + MOVD s+0(FP), R1 + MOVD 48(RSP), R12 + CMP $0x01, R0 + BLS sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 + FMOVQ 144(R1), F0 + MOVD R12, 144(R1) + FMOVQ F0, 152(R1) + JMP sequenceDecs_decodeSync_safe_amd64_after_adjust sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0: - MOVD 32(RSP), R16 + MOVD 64(RSP), R16 CMP $0x00000000, R16 BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero ADD $1, R12, R12 @@ -2293,16 +2139,11 @@ sequenceDecs_decodeSync_safe_amd64_adjust_skip: MOVD R13, R12 sequenceDecs_decodeSync_safe_amd64_after_adjust: - MOVD R12, 16(RSP) + MOVD R12, 48(RSP) // Check values - MOVD 24(RSP), R0 - MOVD 32(RSP), R1 - ADD R1, R0, R13 - MOVD s+0(FP), R14 - MOVD 256(R14), R16 - ADD R13, R16, R16 - MOVD R16, 256(R14) + MOVD 56(RSP), R0 + MOVD 64(RSP), R1 MOVD ctx+16(FP), R13 MOVD 104(R13), R16 SUBS R1, R16, R16 @@ -2316,60 +2157,54 @@ sequenceDecs_decodeSync_safe_amd64_after_adjust: BNE sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok: - MOVD 32(RSP), R0 - MOVD 16(RSP), R1 - MOVD 24(RSP), R12 - // Check if we have enough space in s.out - ADD R12, R0, R13 + ADD R0, R1, R13 ADD R9, R13, R13 - MOVD 40(RSP), R16 + MOVD 72(RSP), R16 CMP R16, R13 BHI error_not_enough_space // Copy literals - TST R0, R0 + TST R1, R1 BEQ check_offset - MOVD R0, R13 + MOVD R1, R13 SUBS $0x10, R13, R13 BLO copy_1_small copy_1_loop: - VLD1 (R10), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R10, R10 - ADD $0x10, R9, R9 - SUBS $0x10, R13, R13 - BHS copy_1_loop - ADD R13, R10, R10 - ADD $16, R10, R10 - ADD R13, R9, R9 - ADD $16, R9, R9 - ADD $-16, R10, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_1_end + FMOVQ (R10), F0 + FMOVQ F0, (R9) + ADD $0x10, R10, R10 + ADD $0x10, R9, R9 + SUBS $0x10, R13, R13 + BHS copy_1_loop + ADD R13, R10, R10 + ADD $16, R10, R10 + ADD R13, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R10), F0 + FMOVQ F0, -16(R9) + JMP copy_1_end copy_1_small: - CMP $0x03, R0 + CMP $0x03, R1 BEQ copy_1_move_3 BLO copy_1_move_1or2 - CMP $0x08, R0 + CMP $0x08, R1 BLO copy_1_move_4through7 JMP copy_1_move_8through16 copy_1_move_1or2: MOVBU (R10), R16 BFI $0, R16, $8, R13 - ADD R0, R10, R15 + ADD R1, R10, R15 MOVBU -1(R15), R16 BFI $0, R16, $8, R14 MOVB R13, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVB R14, -1(R15) - ADD R0, R10, R10 - ADD R0, R9, R9 + ADD R1, R10, R10 + ADD R1, R9, R9 JMP copy_1_end copy_1_move_3: @@ -2378,158 +2213,154 @@ copy_1_move_3: BFI $0, R16, $8, R14 MOVH R13, (R9) MOVB R14, 2(R9) - ADD R0, R10, R10 - ADD R0, R9, R9 + ADD R1, R10, R10 + ADD R1, R9, R9 JMP copy_1_end copy_1_move_4through7: MOVWU (R10), R13 - ADD R0, R10, R15 + ADD R1, R10, R15 MOVWU -4(R15), R14 MOVW R13, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVW R14, -4(R15) - ADD R0, R10, R10 - ADD R0, R9, R9 + ADD R1, R10, R10 + ADD R1, R9, R9 JMP copy_1_end copy_1_move_8through16: MOVD (R10), R13 - ADD R0, R10, R15 + ADD R1, R10, R15 MOVD -8(R15), R14 MOVD R13, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVD R14, -8(R15) - ADD R0, R10, R10 - ADD R0, R9, R9 + ADD R1, R10, R10 + ADD R1, R9, R9 copy_1_end: - ADD R0, R11, R11 + ADD R1, R11, R11 // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) check_offset: - MOVD R11, R0 - MOVD 48(RSP), R16 - ADD R16, R0, R0 - CMP R0, R1 + MOVD R11, R1 + MOVD 80(RSP), R16 + ADD R16, R1, R1 + CMP R1, R12 BGT error_match_off_too_big - MOVD 64(RSP), R16 - CMP R16, R1 + MOVD 96(RSP), R16 + CMP R16, R12 BGT error_match_off_too_big // Copy match from history - MOVD R1, R0 - SUBS R11, R0, R0 + MOVD R12, R1 + SUBS R11, R1, R1 BLS copy_match - MOVD 56(RSP), R13 - SUB R0, R13, R13 - CMP R0, R12 + MOVD 88(RSP), R13 + SUB R1, R13, R13 + CMP R1, R0 BGT copy_all_from_history - MOVD R12, R0 - SUBS $0x10, R0, R0 + MOVD R0, R1 + SUBS $0x10, R1, R1 BLO copy_4_small copy_4_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R13, R13 - ADD $0x10, R9, R9 - SUBS $0x10, R0, R0 - BHS copy_4_loop - ADD R0, R13, R13 - ADD $16, R13, R13 - ADD R0, R9, R9 - ADD $16, R9, R9 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_4_end + FMOVQ (R13), F0 + FMOVQ F0, (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R1, R1 + BHS copy_4_loop + ADD R1, R13, R13 + ADD $16, R13, R13 + ADD R1, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R9) + JMP copy_4_end copy_4_small: - CMP $0x03, R12 + CMP $0x03, R0 BEQ copy_4_move_3 - CMP $0x08, R12 + CMP $0x08, R0 BLO copy_4_move_4through7 JMP copy_4_move_8through16 copy_4_move_3: - MOVHU (R13), R0 + MOVHU (R13), R1 MOVBU 2(R13), R16 - BFI $0, R16, $8, R1 - MOVH R0, (R9) - MOVB R1, 2(R9) - ADD R12, R13, R13 - ADD R12, R9, R9 + BFI $0, R16, $8, R12 + MOVH R1, (R9) + MOVB R12, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 JMP copy_4_end copy_4_move_4through7: - MOVWU (R13), R0 - ADD R12, R13, R15 - MOVWU -4(R15), R1 - MOVW R0, (R9) - ADD R12, R9, R15 - MOVW R1, -4(R15) - ADD R12, R13, R13 - ADD R12, R9, R9 + MOVWU (R13), R1 + ADD R0, R13, R15 + MOVWU -4(R15), R12 + MOVW R1, (R9) + ADD R0, R9, R15 + MOVW R12, -4(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 JMP copy_4_end copy_4_move_8through16: - MOVD (R13), R0 - ADD R12, R13, R15 - MOVD -8(R15), R1 - MOVD R0, (R9) - ADD R12, R9, R15 - MOVD R1, -8(R15) - ADD R12, R13, R13 - ADD R12, R9, R9 + MOVD (R13), R1 + ADD R0, R13, R15 + MOVD -8(R15), R12 + MOVD R1, (R9) + ADD R0, R9, R15 + MOVD R12, -8(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 copy_4_end: - ADD R12, R11, R11 + ADD R0, R11, R11 JMP handle_loop JMP loop_finished copy_all_from_history: - MOVD R0, R14 + MOVD R1, R14 SUBS $0x10, R14, R14 BLO copy_5_small copy_5_loop: - VLD1 (R13), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R13, R13 - ADD $0x10, R9, R9 - SUBS $0x10, R14, R14 - BHS copy_5_loop - ADD R14, R13, R13 - ADD $16, R13, R13 - ADD R14, R9, R9 - ADD $16, R9, R9 - ADD $-16, R13, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_5_end + FMOVQ (R13), F0 + FMOVQ F0, (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R13), F0 + FMOVQ F0, -16(R9) + JMP copy_5_end copy_5_small: - CMP $0x03, R0 + CMP $0x03, R1 BEQ copy_5_move_3 BLO copy_5_move_1or2 - CMP $0x08, R0 + CMP $0x08, R1 BLO copy_5_move_4through7 JMP copy_5_move_8through16 copy_5_move_1or2: MOVBU (R13), R16 BFI $0, R16, $8, R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVBU -1(R15), R16 BFI $0, R16, $8, R4 MOVB R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVB R4, -1(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_3: @@ -2538,140 +2369,136 @@ copy_5_move_3: BFI $0, R16, $8, R4 MOVH R14, (R9) MOVB R4, 2(R9) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVWU -4(R15), R4 MOVW R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVW R4, -4(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 JMP copy_5_end copy_5_move_8through16: MOVD (R13), R14 - ADD R0, R13, R15 + ADD R1, R13, R15 MOVD -8(R15), R4 MOVD R14, (R9) - ADD R0, R9, R15 + ADD R1, R9, R15 MOVD R4, -8(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 + ADD R1, R13, R13 + ADD R1, R9, R9 copy_5_end: - ADD R0, R11, R11 - SUB R0, R12, R12 + ADD R1, R11, R11 + SUB R1, R0, R0 // Copy match from the current buffer copy_match: - MOVD R9, R0 - SUB R1, R0, R0 + MOVD R9, R1 + SUB R12, R1, R1 // ml <= mo - CMP R1, R12 + CMP R12, R0 BHI copy_overlapping_match // Copy non-overlapping match - ADD R12, R11, R11 - MOVD R12, R1 - SUBS $0x10, R1, R1 + ADD R0, R11, R11 + MOVD R0, R12 + SUBS $0x10, R12, R12 BLO copy_2_small copy_2_loop: - VLD1 (R0), [V0.B16] - VST1 [V0.B16], (R9) - ADD $0x10, R0, R0 - ADD $0x10, R9, R9 - SUBS $0x10, R1, R1 - BHS copy_2_loop - ADD R1, R0, R0 - ADD $16, R0, R0 - ADD R1, R9, R9 - ADD $16, R9, R9 - ADD $-16, R0, R15 - VLD1 (R15), [V0.B16] - ADD $-16, R9, R15 - VST1 [V0.B16], (R15) - JMP copy_2_end + FMOVQ (R1), F0 + FMOVQ F0, (R9) + ADD $0x10, R1, R1 + ADD $0x10, R9, R9 + SUBS $0x10, R12, R12 + BHS copy_2_loop + ADD R12, R1, R1 + ADD $16, R1, R1 + ADD R12, R9, R9 + ADD $16, R9, R9 + FMOVQ -16(R1), F0 + FMOVQ F0, -16(R9) + JMP copy_2_end copy_2_small: - CMP $0x03, R12 + CMP $0x03, R0 BEQ copy_2_move_3 BLO copy_2_move_1or2 - CMP $0x08, R12 + CMP $0x08, R0 BLO copy_2_move_4through7 JMP copy_2_move_8through16 copy_2_move_1or2: - MOVBU (R0), R16 - BFI $0, R16, $8, R1 - ADD R12, R0, R15 + MOVBU (R1), R16 + BFI $0, R16, $8, R12 + ADD R0, R1, R15 MOVBU -1(R15), R16 BFI $0, R16, $8, R13 - MOVB R1, (R9) - ADD R12, R9, R15 + MOVB R12, (R9) + ADD R0, R9, R15 MOVB R13, -1(R15) - ADD R12, R0, R0 - ADD R12, R9, R9 + ADD R0, R1, R1 + ADD R0, R9, R9 JMP copy_2_end copy_2_move_3: - MOVHU (R0), R1 - MOVBU 2(R0), R16 + MOVHU (R1), R12 + MOVBU 2(R1), R16 BFI $0, R16, $8, R13 - MOVH R1, (R9) + MOVH R12, (R9) MOVB R13, 2(R9) - ADD R12, R0, R0 - ADD R12, R9, R9 + ADD R0, R1, R1 + ADD R0, R9, R9 JMP copy_2_end copy_2_move_4through7: - MOVWU (R0), R1 - ADD R12, R0, R15 + MOVWU (R1), R12 + ADD R0, R1, R15 MOVWU -4(R15), R13 - MOVW R1, (R9) - ADD R12, R9, R15 + MOVW R12, (R9) + ADD R0, R9, R15 MOVW R13, -4(R15) - ADD R12, R0, R0 - ADD R12, R9, R9 + ADD R0, R1, R1 + ADD R0, R9, R9 JMP copy_2_end copy_2_move_8through16: - MOVD (R0), R1 - ADD R12, R0, R15 + MOVD (R1), R12 + ADD R0, R1, R15 MOVD -8(R15), R13 - MOVD R1, (R9) - ADD R12, R9, R15 + MOVD R12, (R9) + ADD R0, R9, R15 MOVD R13, -8(R15) - ADD R12, R0, R0 - ADD R12, R9, R9 + ADD R0, R1, R1 + ADD R0, R9, R9 copy_2_end: JMP handle_loop // Copy overlapping match copy_overlapping_match: - ADD R12, R11, R11 + ADD R0, R11, R11 copy_slow_3: - MOVBU (R0), R16 - BFI $0, R16, $8, R1 - MOVB R1, (R9) - ADD $1, R0, R0 + MOVBU (R1), R12 + MOVB R12, (R9) + ADD $1, R1, R1 ADD $1, R9, R9 - SUBS $1, R12, R12 + SUBS $1, R0, R0 BNE copy_slow_3 handle_loop: - MOVD ctx+16(FP), R0 - MOVD 96(R0), R16 + MOVD 40(RSP), R16 SUBS $1, R16, R16 - MOVD R16, 96(R0) + MOVD R16, 40(RSP) BPL sequenceDecs_decodeSync_safe_amd64_main_loop loop_finished: @@ -2680,6 +2507,16 @@ loop_finished: MOVB R3, 40(R0) MOVD R5, 32(R0) + // s.seqSize += outPosition - ctx.outPosition + MOVD ctx+16(FP), R0 + MOVD s+0(FP), R1 + MOVD R11, R2 + MOVD 136(R0), R16 + SUB R16, R2, R2 + MOVD 256(R1), R16 + ADD R2, R16, R16 + MOVD R16, 256(R1) + // Update the context MOVD ctx+16(FP), R0 MOVD R11, 136(R0) @@ -2694,7 +2531,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: - MOVD 24(RSP), R0 + MOVD 56(RSP), R0 MOVD ctx+16(FP), R1 MOVD R0, 216(R1) MOVD $0x00000001, R16 @@ -2704,7 +2541,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 56(RSP), R1 MOVD R1, 216(R0) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) @@ -2713,7 +2550,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVD ctx+16(FP), R0 - MOVD 16(RSP), R1 + MOVD 48(RSP), R1 MOVD R1, 224(R0) MOVD R11, 136(R0) MOVD $0x00000003, R16 @@ -2723,7 +2560,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVD ctx+16(FP), R0 - MOVD 32(RSP), R1 + MOVD 64(RSP), R1 MOVD R1, 208(R0) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) @@ -2738,9 +2575,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVD ctx+16(FP), R0 - MOVD 32(RSP), R1 + MOVD 64(RSP), R1 MOVD R1, 208(R0) - MOVD 24(RSP), R1 + MOVD 56(RSP), R1 MOVD R1, 216(R0) MOVD R11, 136(R0) MOVD $0x00000005, R16 diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go index 42ce5de716..94559c459a 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go @@ -83,9 +83,10 @@ const errorOverread = 6 // When the output and literal buffers have compressedBlockOverAlloc (16) // bytes of slack past their logical use, the assembly may use extended // memory copies that read and write in 16-byte blocks, overrunning the end -// of a literal run or match by up to 15 bytes. Otherwise it must use the -// bounds-exact ("safe") copies. This mirrors the analogous, always-dynamic -// selection in executeSimple below. +// of a literal run or match by up to 15 bytes; an empty literal run still +// copies one block, reading and writing the full 16 bytes of slack past +// its position. Otherwise it must use the bounds-exact ("safe") copies. +// This mirrors the analogous, always-dynamic selection in executeSimple below. // // The unsafe copies were disabled in #644 (2022) as a mitigation for a // crash, but that crash's root cause — an unguarded bitReader overread that diff --git a/vendor/github.com/mattn/go-runewidth/README.md b/vendor/github.com/mattn/go-runewidth/README.md index 5e2cfd98cb..ecbaed99ca 100644 --- a/vendor/github.com/mattn/go-runewidth/README.md +++ b/vendor/github.com/mattn/go-runewidth/README.md @@ -15,6 +15,11 @@ Usage runewidth.StringWidth("つのだ☆HIRO") == 12 ``` +NOTE: Latin letters that Unicode gives ambiguous East Asian width, such as +`ü`, `é` and `ß`, are measured as one cell even when `EastAsianWidth` is +set, as terminals draw them in CJK locales too. Other ambiguous characters +such as `±`, `×` and `○` still take two cells there. + Author ------ diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go index af03e996e9..95d9ba548f 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth.go @@ -54,10 +54,24 @@ var ( strictWidthLUT [2][0x110000]byte strictWidthLUTLimit atomic.Int32 strictWidthLUTOnce sync.Once + + // joinerBits is the joiner table as a bitmap over + // [joinerBase, 0x10000), the range where the per-rune test has to be + // cheap for the fast paths in StringWidth and Wrap to pay off. It is + // 7.6 KB and init fills it in a few microseconds. Runes above it stay + // on the interval search: they are rare in the text these fast paths + // are for, and the emoji that are common there leave the fast path at + // their first joiner anyway. + joinerBits [(0x10000 - joinerBase) / 8]byte ) +// joinerBase is the lowest rune in the joiner table. CR is the only rune +// below it that can form a multi-rune cluster, by pairing with LF. +const joinerBase = 0x300 + func init() { initStrictWidthLUTLow() + fillJoinerBits() strictWidthLUTLimit.Store(0x300) handleEnv() } @@ -347,9 +361,11 @@ var private = table{ var nonprint = table{ {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD}, - {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F}, - {0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF}, - {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, + {0x061C, 0x061C}, {0x070F, 0x070F}, {0x180B, 0x180E}, + {0x200B, 0x200F}, {0x2028, 0x202E}, {0x2060, 0x2064}, + {0x2066, 0x206F}, {0xD800, 0xDFFF}, {0xFEFF, 0xFEFF}, + {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, {0x13430, 0x1343F}, + {0x1BCA0, 0x1BCA3}, {0x1D173, 0x1D17A}, {0xE0001, 0xE0001}, } // Condition have flag EastAsianWidth whether the current locale is CJK or not. @@ -446,19 +462,131 @@ func (c *Condition) CreateLUT() { c.lutStrictEmojiNeutral = c.StrictEmojiNeutral } +// isASCII reports whether s has no byte above 0x7F, in which case every +// grapheme cluster in s is a single byte apart from CRLF. +func isASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= 0x80 { + return false + } + } + return true +} + +// fillJoinerBits paints joinerBits from the joiner table. +func fillJoinerBits() { + for _, iv := range joiner { + if iv.first >= 0x10000 { + break // the table is sorted, the rest is astral + } + lo, hi := int(iv.first)-joinerBase, int(iv.last)-joinerBase + if hi >= len(joinerBits)*8 { + hi = len(joinerBits)*8 - 1 + } + for lo <= hi { + if lo&7 == 0 && lo+7 <= hi { + joinerBits[lo>>3] = 0xFF + lo += 8 + continue + } + joinerBits[lo>>3] |= 1 << uint(lo&7) + lo++ + } + } + // A byte that is not valid UTF-8 decodes to U+FFFD, and the segmenter + // can gather a run of such bytes into one cluster, which a rune loop + // has no way to see. Marking U+FFFD keeps those strings on the + // segmenter, and the only string it holds back needlessly is one that + // really contains U+FFFD. + i := int(utf8.RuneError) - joinerBase + joinerBits[i>>3] |= 1 << uint(i&7) +} + +// isJoiner reports whether r can join with a neighbour into a multi-rune +// grapheme cluster. A string of runes for which it reports false has one +// rune per cluster, so measuring it needs no grapheme segmentation. +func isJoiner(r rune) bool { + if r < joinerBase { + return r == '\r' + } + if r < 0x10000 { + i := r - joinerBase + return joinerBits[i>>3]&(1<<(uint(i)&7)) != 0 + } + return inTable(r, joiner) +} + +// clusterText returns s to segment in place of s. When s ends in a lead +// byte short of the bytes it promises, the segmenter gives up there and +// glues everything from it onto the cluster before, where the two-cell cap +// hides it, although the same bytes followed by anything else form +// clusters of their own. Such a string gets NULs after it, enough for any +// lead byte to be decoded; as controls they are clusters of their own, and +// the loops over the clusters stop at len(s) before reaching them. +func clusterText(s string) string { + if endsShort(s) { + return s + "\x00\x00\x00" + } + return s +} + +// endsShort reports whether one of the last three bytes of s is a lead +// byte that needs more bytes than are left, which is where the segmenter +// stops decoding. It only looks at the length the lead byte announces, not +// at whether the bytes after it could continue it, as the segmenter does. +func endsShort(s string) bool { + for i := max(len(s)-3, 0); i < len(s); i++ { + b, left := s[i], len(s)-i + if b >= 0xC2 && b < 0xE0 && left < 2 || + b >= 0xE0 && b < 0xF0 && left < 3 || + b >= 0xF0 && b < 0xF8 && left < 4 { + return true + } + } + return false +} + // graphemeWidth returns the width of a single grapheme cluster: the sum of -// the widths of its runes, capped at 2 cells. The cap keeps multi-rune -// sequences that render as a single glyph (ZWJ emoji, flags, Hangul jamo) -// from being counted wider than the two cells terminals give them. +// the widths of its runes, with the part from the first rune that starts a +// single glyph (an emoji, a regional indicator, a Hangul jamo or syllable) +// capped at 2 cells. The cap keeps multi-rune sequences that render as one +// glyph (ZWJ emoji, skin tones, flags, Hangul jamo) from being counted +// wider than the two cells terminals give them. What comes before it, such +// as a Prepend rune, and a cluster with no such rune, like a letter with a +// skin tone modifier after it, are shown rune by rune and summed. func (c *Condition) graphemeWidth(cluster string) int { - width := 0 + if r, size := utf8.DecodeRuneInString(cluster); size == len(cluster) { + return c.RuneWidth(r) // one rune, never over the cap + } + width, glyph := 0, -1 for _, r := range cluster { - width += c.RuneWidth(r) + w := c.RuneWidth(r) + if glyph < 0 && r >= 0x1100 && startsGlyph(r) { + glyph = 0 + } + if glyph >= 0 { + glyph += w + } else { + width += w + } } - if width > 2 { - width = 2 + return width + min(max(glyph, 0), 2) +} + +// startsGlyph reports whether r begins a sequence that a terminal draws as +// a single glyph however many runes it has. +func startsGlyph(r rune) bool { + switch { + case 0x1100 <= r && r <= 0x11FF, // Hangul jamo + 0xA960 <= r && r <= 0xA97F, // Hangul jamo extended-A + 0xAC00 <= r && r <= 0xD7FF, // Hangul syllables, jamo extended-B + 0x1F1E6 <= r && r <= 0x1F1FF: // regional indicators + return true + case r < 0x203C, 0x3299 < r && r < 0x1F004: + // Outside the emoji table: spares CJK text the search. + return false } - return width + return inTable(r, emoji) } // StringWidth return width as you can see @@ -468,6 +596,11 @@ func (c *Condition) StringWidth(s string) (width int) { if b < 0x20 || b == 0x7F { return 0 } + if b >= 0x80 { + // Not UTF-8 on its own: measure it as the U+FFFD every other + // path decodes it to, which is ambiguous width. + return c.RuneWidth(utf8.RuneError) + } return 1 } if len(s) > 0 && len(s) <= utf8.UTFMax { @@ -489,24 +622,48 @@ func (c *Condition) StringWidth(s string) (width int) { return graphemes: + // Runes first: until one of them can join a cluster, each cluster is a + // single rune and segmenting the string would only find that out the + // expensive way. + if w, ok := c.runeWidthSum(s); ok { + width = w + return + } width = 0 - g := graphemes.FromString(s) - for g.Next() { + g := graphemes.FromString(clusterText(s)) + for g.Next() && g.Start() < len(s) { width += c.graphemeWidth(g.Value()) } return } +// runeWidthSum adds up the widths of the runes in s, and reports false +// without a total once it meets a rune that can join a cluster, which is +// where per-rune widths stop being the whole story. +func (c *Condition) runeWidthSum(s string) (int, bool) { + width := 0 + for _, r := range s { + if isJoiner(r) { + return 0, false + } + width += c.RuneWidth(r) + } + return width, true +} + // Truncate return string truncated with w cells func (c *Condition) Truncate(s string, w int, tail string) string { if c.StringWidth(s) <= w { return s } w -= c.StringWidth(tail) + if pos, ok := c.truncateRunes(s, w); ok { + return s[:pos] + tail + } var width int pos := len(s) - g := graphemes.FromString(s) - for g.Next() { + g := graphemes.FromString(clusterText(s)) + for g.Next() && g.Start() < len(s) { chWidth := c.graphemeWidth(g.Value()) if width+chWidth > w { pos = g.Start() @@ -517,17 +674,50 @@ func (c *Condition) Truncate(s string, w int, tail string) string { return s[:pos] + tail } +// truncateRunes is the loop in Truncate with every rune taken for a whole +// cluster, which holds until a rune can join one. It reports false there +// and leaves the string to the segmenter. +func (c *Condition) truncateRunes(s string, w int) (int, bool) { + width := 0 + for i, r := range s { + if isJoiner(r) { + return 0, false + } + cw := c.RuneWidth(r) + if width+cw > w { + return i, true + } + width += cw + } + return len(s), true +} + +// endsCluster reports whether the byte at i, which follows a rune that +// cannot join a cluster, also starts one. Cutting there is only safe when +// the rune that follows does not reach back. +func endsCluster(s string, i int) bool { + if i >= len(s) { + return true + } + r, _ := utf8.DecodeRuneInString(s[i:]) + return !isJoiner(r) +} + // TruncateLeft cuts w cells from the beginning of the `s`. func (c *Condition) TruncateLeft(s string, w int, prefix string) string { if c.StringWidth(s) <= w { return prefix } + if pos, pad, ok := c.truncateLeftRunes(s, w); ok { + return prefix + strings.Repeat(" ", pad) + s[pos:] + } + var width int pos := len(s) - g := graphemes.FromString(s) - for g.Next() { + g := graphemes.FromString(clusterText(s)) + for g.Next() && g.Start() < len(s) { chWidth := c.graphemeWidth(g.Value()) if width+chWidth > w { @@ -547,6 +737,32 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string { return prefix + s[pos:] } +// truncateLeftRunes is the loop in TruncateLeft with every rune taken for a +// whole cluster, returning the cut and the padding that replaces the cell +// the cut lands inside. It reports false at the first rune that can join a +// cluster. +func (c *Condition) truncateLeftRunes(s string, w int) (pos, pad int, ok bool) { + width := 0 + for i, r := range s { + if isJoiner(r) { + return 0, 0, false + } + cw := c.RuneWidth(r) + if width+cw > w { + if width >= w { + return i, 0, true + } + end := i + utf8.RuneLen(r) + if !endsCluster(s, end) { + return 0, 0, false + } + return end, width + cw - w, true + } + width += cw + } + return len(s), 0, true +} + // TruncatePrefix cuts the beginning of `s` so the result fits in w cells, with prefix prepended func (c *Condition) TruncatePrefix(s string, w int, prefix string) string { if c.StringWidth(prefix) >= w { @@ -558,10 +774,13 @@ func (c *Condition) TruncatePrefix(s string, w int, prefix string) string { return s } w -= c.StringWidth(prefix) + if pos, ok := c.truncatePrefixRunes(s, sw, w); ok { + return prefix + s[pos:] + } var width int var pos int - g := graphemes.FromString(s) - for g.Next() { + g := graphemes.FromString(clusterText(s)) + for g.Next() && g.Start() < len(s) { chWidth := c.graphemeWidth(g.Value()) if sw-(width+chWidth) <= w { pos = g.End() @@ -573,29 +792,119 @@ func (c *Condition) TruncatePrefix(s string, w int, prefix string) string { return prefix + s[pos:] } -// Wrap return string wrapped with w cells -func (c *Condition) Wrap(s string, w int) string { +// truncatePrefixRunes is the loop in TruncatePrefix with every rune taken +// for a whole cluster, reporting false at the first rune that can join one. +func (c *Condition) truncatePrefixRunes(s string, sw, w int) (int, bool) { + width := 0 + for i, r := range s { + if isJoiner(r) { + return 0, false + } + cw := c.RuneWidth(r) + if sw-(width+cw) <= w { + end := i + utf8.RuneLen(r) + if !endsCluster(s, end) { + return 0, false + } + return end, true + } + width += cw + } + return 0, true +} + +// wrapRunes wraps s treating every rune as its own grapheme cluster, and +// reports false without a result once it meets a rune that can join one. +func (c *Condition) wrapRunes(s string, w int) (string, bool) { width := 0 var out strings.Builder - // max keeps the capacity hint from dividing by zero when w is 0; a - // non-positive width breaks before every rune, as it always has. out.Grow(len(s) + len(s)/max(w, 1) + 1) for _, r := range s { + if isJoiner(r) { + return "", false + } cw := c.RuneWidth(r) if r == '\n' { out.WriteRune(r) width = 0 continue - } else if width+cw > w { + } + if width+cw > w { out.WriteByte('\n') width = 0 - out.WriteRune(r) - width += cw - continue } out.WriteRune(r) width += cw } + return out.String(), true +} + +// Wrap return string wrapped with w cells +func (c *Condition) Wrap(s string, w int) string { + // ASCII fast path: no grapheme clustering needed for pure ASCII + if isASCII(s) { + width := 0 + var out strings.Builder + // max keeps the capacity hint from dividing by zero when w is 0; + // a non-positive width breaks before every cluster, as it always + // has. + out.Grow(len(s) + len(s)/max(w, 1) + 1) + for i := 0; i < len(s); i++ { + b := s[i] + if b == '\n' { + out.WriteByte(b) + width = 0 + continue + } + // CRLF is one cluster that ends the line, as on the + // segmenter, so it is never broken before. + if b == '\r' && i+1 < len(s) && s[i+1] == '\n' { + out.WriteString("\r\n") + width = 0 + i++ + continue + } + // Same rule as the StringWidth fast path: no ASCII byte is + // wide or ambiguous, so the flags in c cannot change this. + cw := 0 + if b >= 0x20 && b != 0x7F { + cw = 1 + } + if width+cw > w { + out.WriteByte('\n') + width = 0 + } + out.WriteByte(b) + width += cw + } + return out.String() + } + // Runes first, as in StringWidth. Reaching a rune that can join a + // cluster throws the wrapped text away and starts over on the + // segmenter, which is the uncommon case. + if out, ok := c.wrapRunes(s, w); ok { + return out + } + width := 0 + var out strings.Builder + out.Grow(len(s) + len(s)/max(w, 1) + 1) + g := graphemes.FromString(clusterText(s)) + for g.Next() && g.Start() < len(s) { + cluster := g.Value() + // LF and CRLF are each a single cluster + if strings.HasSuffix(cluster, "\n") { + out.WriteString(cluster) + width = 0 + continue + } + cw := c.graphemeWidth(cluster) + if width+cw > w { + out.WriteByte('\n') + width = 0 + } + out.WriteString(cluster) + width += cw + } return out.String() } @@ -626,8 +935,13 @@ func RuneWidth(r rune) int { } // IsAmbiguousWidth returns whether is ambiguous width or not. +// +// NOTE: The Latin letters of U+0080..U+017F that Unicode gives ambiguous +// width (ü, é, ß, æ, ø and so on) are reported as ambiguous here, but +// RuneWidth measures them as one cell even with EastAsianWidth, since +// terminals draw them narrow in CJK locales too. func IsAmbiguousWidth(r rune) bool { - return inTable(r, private) || inTable(r, ambiguous) + return inTable(r, private) || inTable(r, ambiguous) || inTable(r, ambiguousLatin) } // IsCombiningWidth returns whether is combining width or not. diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go index 16673af3a1..302c3d0c6e 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go @@ -14,9 +14,11 @@ func mblen(charset string) int { return 6 case "jis": return 8 + case "euctw", "gb18030": + return 4 case "eucjp": return 3 - case "euckr", "euccn", "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950", "big5", "gbk", "gb2312": + case "euckr", "euccn", "sjis", "shiftjis", "cp932", "cp51932", "cp936", "cp949", "cp950", "big5", "big5hkscs", "gbk", "gb2312": return 2 } return 1 @@ -45,9 +47,35 @@ func localeCharset(locale string) string { return "" } +// isCJKLanguage reports whether the language code at the start of locale is +// Japanese, Korean or Chinese. +func isCJKLanguage(locale string) bool { + n := 0 + for n < len(locale) && locale[n] >= 'a' && locale[n] <= 'z' { + n++ + } + switch locale[:n] { + case "ja", "ko", "zh": + return true + } + return false +} + +// normalizeCharset drops the hyphens and underscores that charset names are +// spelled with or without, so that "EUC-JP" and "eucjp" compare equal. +func normalizeCharset(charset string) string { + return strings.Map(func(r rune) rune { + if r == '-' || r == '_' { + return -1 + } + return r + }, charset) +} + func isEastAsian(locale string) bool { charset := strings.ToLower(locale) - if cs := localeCharset(locale); cs != "" { + cs := localeCharset(locale) + if cs != "" { charset = strings.ToLower(cs) } @@ -61,14 +89,13 @@ func isEastAsian(locale string) bool { break } } - max := mblen(charset) - if max > 1 && (charset[0] != 'u' || - strings.HasPrefix(locale, "ja") || - strings.HasPrefix(locale, "ko") || - strings.HasPrefix(locale, "zh")) { + cjk := isCJKLanguage(locale) + if cs == "" && cjk { + // A CJK locale without a charset, such as "ja_JP" on macOS. return true } - return false + max := mblen(normalizeCharset(charset)) + return max > 1 && (charset[0] != 'u' || cjk) } // IsEastAsian return true if the current locale is CJK diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_table.go b/vendor/github.com/mattn/go-runewidth/runewidth_table.go index 62488d97da..81bc90752c 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth_table.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go @@ -173,65 +173,71 @@ var doublewidth = table{ var ambiguous = table{ {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, - {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4}, - {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, - {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, + {0x00AD, 0x00AE}, {0x00B0, 0x00B4}, {0x00B6, 0x00B9}, + {0x00BC, 0x00BF}, {0x00D7, 0x00D7}, {0x00F7, 0x00F7}, + {0x01CE, 0x01CE}, {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, + {0x01D4, 0x01D4}, {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, + {0x01DA, 0x01DA}, {0x01DC, 0x01DC}, {0x0251, 0x0251}, + {0x0261, 0x0261}, {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, + {0x02C9, 0x02CB}, {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, + {0x02D8, 0x02DB}, {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, + {0x0300, 0x036F}, {0x0391, 0x03A1}, {0x03A3, 0x03A9}, + {0x03B1, 0x03C1}, {0x03C3, 0x03C9}, {0x0401, 0x0401}, + {0x0410, 0x044F}, {0x0451, 0x0451}, {0x2010, 0x2010}, + {0x2013, 0x2016}, {0x2018, 0x2019}, {0x201C, 0x201D}, + {0x2020, 0x2022}, {0x2024, 0x2027}, {0x2030, 0x2030}, + {0x2032, 0x2033}, {0x2035, 0x2035}, {0x203B, 0x203B}, + {0x203E, 0x203E}, {0x2074, 0x2074}, {0x207F, 0x207F}, + {0x2081, 0x2084}, {0x20AC, 0x20AC}, {0x2103, 0x2103}, + {0x2105, 0x2105}, {0x2109, 0x2109}, {0x2113, 0x2113}, + {0x2116, 0x2116}, {0x2121, 0x2122}, {0x2126, 0x2126}, + {0x212B, 0x212B}, {0x2153, 0x2154}, {0x215B, 0x215E}, + {0x2160, 0x216B}, {0x2170, 0x2179}, {0x2189, 0x2189}, + {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, + {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200}, + {0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B}, + {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215}, + {0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223}, + {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E}, + {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248}, + {0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261}, + {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F}, + {0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295}, + {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, + {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B}, + {0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595}, + {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, + {0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, + {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, + {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606}, + {0x2609, 0x2609}, {0x260E, 0x260F}, {0x261C, 0x261C}, + {0x261E, 0x261E}, {0x2640, 0x2640}, {0x2642, 0x2642}, + {0x2660, 0x2661}, {0x2663, 0x2665}, {0x2667, 0x266A}, + {0x266C, 0x266D}, {0x266F, 0x266F}, {0x269E, 0x269F}, + {0x26BF, 0x26BF}, {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, + {0x26D5, 0x26E1}, {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, + {0x26EB, 0x26F1}, {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, + {0x26FB, 0x26FC}, {0x26FE, 0x26FF}, {0x273D, 0x273D}, + {0x2776, 0x277F}, {0x2B56, 0x2B59}, {0x3248, 0x324F}, + {0xE000, 0xF8FF}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A}, + {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D}, + {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xF0000, 0xFFFFD}, + {0x100000, 0x10FFFD}, +} + +var ambiguousLatin = table{ + {0x00AA, 0x00AA}, {0x00BA, 0x00BA}, {0x00C6, 0x00C6}, + {0x00D0, 0x00D0}, {0x00D8, 0x00D8}, {0x00DE, 0x00E1}, {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, - {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, + {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F8, 0x00FA}, {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101}, {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133}, {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, - {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE}, - {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, - {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, - {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, - {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, - {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB}, - {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F}, - {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, - {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F}, - {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016}, - {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022}, - {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033}, - {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E}, - {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084}, - {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105}, - {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116}, - {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B}, - {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B}, - {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199}, - {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4}, - {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203}, - {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F}, - {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A}, - {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225}, - {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237}, - {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C}, - {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267}, - {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283}, - {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299}, - {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312}, - {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573}, - {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1}, - {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7}, - {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8}, - {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5}, - {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609}, - {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E}, - {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661}, - {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D}, - {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF}, - {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1}, - {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1}, - {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC}, - {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F}, - {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF}, - {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A}, {0x1F110, 0x1F12D}, - {0x1F130, 0x1F169}, {0x1F170, 0x1F18D}, {0x1F18F, 0x1F190}, - {0x1F19B, 0x1F1AC}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}, + {0x0166, 0x0167}, {0x016B, 0x016B}, } + var narrow = table{ {0x0020, 0x007E}, {0x00A2, 0x00A3}, {0x00A5, 0x00A6}, {0x00AC, 0x00AC}, {0x00AF, 0x00AF}, {0x27E6, 0x27ED}, @@ -590,3 +596,120 @@ var emoji = table{ {0x1F947, 0x1F9FF}, {0x1FA58, 0x1FA5F}, {0x1FA6E, 0x1FAFF}, {0x1FC00, 0x1FFFD}, } + +var joiner = table{ + {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, {0x0600, 0x0605}, {0x0610, 0x061A}, + {0x064B, 0x065F}, {0x0670, 0x0670}, {0x06D6, 0x06DD}, + {0x06DF, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, + {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, + {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x07FD, 0x07FD}, + {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827}, + {0x0829, 0x082D}, {0x0859, 0x085B}, {0x0890, 0x0891}, + {0x0897, 0x089F}, {0x08CA, 0x0903}, {0x093A, 0x093C}, + {0x093E, 0x094F}, {0x0951, 0x0957}, {0x0962, 0x0963}, + {0x0981, 0x0983}, {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, + {0x09C7, 0x09C8}, {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, + {0x09E2, 0x09E3}, {0x09FE, 0x09FE}, {0x0A01, 0x0A03}, + {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, + {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A70, 0x0A71}, + {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, {0x0ABC, 0x0ABC}, + {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, + {0x0AE2, 0x0AE3}, {0x0AFA, 0x0AFF}, {0x0B01, 0x0B03}, + {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48}, + {0x0B4B, 0x0B4D}, {0x0B55, 0x0B57}, {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, + {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C04}, + {0x0C3C, 0x0C3C}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, + {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, + {0x0C81, 0x0C83}, {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, + {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, + {0x0CE2, 0x0CE3}, {0x0CF3, 0x0CF3}, {0x0D00, 0x0D03}, + {0x0D3B, 0x0D3C}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48}, + {0x0D4A, 0x0D4E}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63}, + {0x0D81, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, + {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3}, + {0x0E31, 0x0E31}, {0x0E33, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, {0x0EB3, 0x0EBC}, {0x0EC8, 0x0ECE}, + {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, {0x0F71, 0x0F84}, + {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC}, + {0x0FC6, 0x0FC6}, {0x102D, 0x1037}, {0x1039, 0x103E}, + {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1071, 0x1074}, + {0x1082, 0x1082}, {0x1084, 0x1086}, {0x108D, 0x108D}, + {0x109D, 0x109D}, {0x1100, 0x11FF}, {0x135D, 0x135F}, + {0x1712, 0x1715}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD}, + {0x180B, 0x180D}, {0x180F, 0x180F}, {0x1885, 0x1886}, + {0x18A9, 0x18A9}, {0x1920, 0x192B}, {0x1930, 0x193B}, + {0x1A17, 0x1A1B}, {0x1A55, 0x1A5E}, {0x1A60, 0x1A60}, + {0x1A62, 0x1A62}, {0x1A65, 0x1A7C}, {0x1A7F, 0x1A7F}, + {0x1AB0, 0x1ADD}, {0x1AE0, 0x1AEB}, {0x1B00, 0x1B04}, + {0x1B34, 0x1B44}, {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, + {0x1BA1, 0x1BAD}, {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, + {0x1CD0, 0x1CD2}, {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, + {0x1CF4, 0x1CF4}, {0x1CF7, 0x1CF9}, {0x1DC0, 0x1DFF}, + {0x200C, 0x200D}, {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, + {0x2D7F, 0x2D7F}, {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, + {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D}, + {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, + {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA823, 0xA827}, + {0xA82C, 0xA82C}, {0xA880, 0xA881}, {0xA8B4, 0xA8C5}, + {0xA8E0, 0xA8F1}, {0xA8FF, 0xA8FF}, {0xA926, 0xA92D}, + {0xA947, 0xA953}, {0xA960, 0xA97C}, {0xA980, 0xA983}, + {0xA9B3, 0xA9C0}, {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, + {0xAA43, 0xAA43}, {0xAA4C, 0xAA4D}, {0xAA7C, 0xAA7C}, + {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, + {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, + {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA}, {0xABEC, 0xABED}, + {0xAC00, 0xD7A3}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, + {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, + {0xFF9E, 0xFF9F}, {0x101FD, 0x101FD}, {0x102E0, 0x102E0}, + {0x10376, 0x1037A}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, + {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, + {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27}, {0x10D69, 0x10D6D}, + {0x10EAB, 0x10EAC}, {0x10EFA, 0x10EFF}, {0x10F46, 0x10F50}, + {0x10F82, 0x10F85}, {0x11000, 0x11002}, {0x11038, 0x11046}, + {0x11070, 0x11070}, {0x11073, 0x11074}, {0x1107F, 0x11082}, + {0x110B0, 0x110BA}, {0x110BD, 0x110BD}, {0x110C2, 0x110C2}, + {0x110CD, 0x110CD}, {0x11100, 0x11102}, {0x11127, 0x11134}, + {0x11145, 0x11146}, {0x11173, 0x11173}, {0x11180, 0x11182}, + {0x111B3, 0x111C0}, {0x111C2, 0x111C3}, {0x111C9, 0x111CC}, + {0x111CE, 0x111CF}, {0x1122C, 0x11237}, {0x1123E, 0x1123E}, + {0x11241, 0x11241}, {0x112DF, 0x112EA}, {0x11300, 0x11303}, + {0x1133B, 0x1133C}, {0x1133E, 0x11344}, {0x11347, 0x11348}, + {0x1134B, 0x1134D}, {0x11357, 0x11357}, {0x11362, 0x11363}, + {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x113B8, 0x113C0}, + {0x113C2, 0x113C2}, {0x113C5, 0x113C5}, {0x113C7, 0x113CA}, + {0x113CC, 0x113D2}, {0x113E1, 0x113E2}, {0x11435, 0x11446}, + {0x1145E, 0x1145E}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5}, + {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640}, + {0x116AB, 0x116B7}, {0x1171D, 0x1171F}, {0x11722, 0x1172B}, + {0x1182C, 0x1183A}, {0x11930, 0x11935}, {0x11937, 0x11938}, + {0x1193B, 0x11943}, {0x119D1, 0x119D7}, {0x119DA, 0x119E0}, + {0x119E4, 0x119E4}, {0x11A01, 0x11A0A}, {0x11A33, 0x11A3E}, + {0x11A47, 0x11A47}, {0x11A51, 0x11A5B}, {0x11A84, 0x11A99}, + {0x11B60, 0x11B67}, {0x11C2F, 0x11C36}, {0x11C38, 0x11C3F}, + {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, {0x11D31, 0x11D36}, + {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D}, {0x11D3F, 0x11D47}, + {0x11D8A, 0x11D8E}, {0x11D90, 0x11D91}, {0x11D93, 0x11D97}, + {0x11EF3, 0x11EF6}, {0x11F00, 0x11F03}, {0x11F34, 0x11F3A}, + {0x11F3E, 0x11F42}, {0x11F5A, 0x11F5A}, {0x13440, 0x13440}, + {0x13447, 0x13455}, {0x1611E, 0x1612F}, {0x16AF0, 0x16AF4}, + {0x16B30, 0x16B36}, {0x16D63, 0x16D63}, {0x16D67, 0x16D6A}, + {0x16F4F, 0x16F4F}, {0x16F51, 0x16F87}, {0x16F8F, 0x16F92}, + {0x16FE4, 0x16FE4}, {0x16FF0, 0x16FF1}, {0x1BC9D, 0x1BC9E}, + {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, + {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, + {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, + {0x1E026, 0x1E02A}, {0x1E08F, 0x1E08F}, {0x1E130, 0x1E136}, + {0x1E2AE, 0x1E2AE}, {0x1E2EC, 0x1E2EF}, {0x1E4EC, 0x1E4EF}, + {0x1E5EE, 0x1E5EF}, {0x1E6E3, 0x1E6E3}, {0x1E6E6, 0x1E6E6}, + {0x1E6EE, 0x1E6EF}, {0x1E6F5, 0x1E6F5}, {0x1E8D0, 0x1E8D6}, + {0x1E944, 0x1E94A}, {0x1F1E6, 0x1F1FF}, {0x1F3FB, 0x1F3FF}, + {0xE0020, 0xE007F}, {0xE0100, 0xE01EF}, +} diff --git a/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go b/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go index d1b0105a68..9e9686878c 100644 --- a/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go +++ b/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go @@ -21,7 +21,7 @@ func Encode(authConfig registry.AuthConfig) (string, error) { // // FIXME(thaJeztah): find exactly what code-paths are impacted by this. // if authConfig == (AuthConfig{}) { return "", nil } - buf, err := json.Marshal(authConfig) + buf, err := json.Marshal(authConfig) // #nosec G117 -- intentionally marshaling auth. if err != nil { return "", errInvalidParameter{err} } diff --git a/vendor/github.com/moby/moby/api/types/build/disk_usage.go b/vendor/github.com/moby/moby/api/types/build/disk_usage.go index 3613797dba..bf178f81e6 100644 --- a/vendor/github.com/moby/moby/api/types/build/disk_usage.go +++ b/vendor/github.com/moby/moby/api/types/build/disk_usage.go @@ -2,9 +2,6 @@ package build -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DiskUsage represents system data usage for build cache resources. // // swagger:model DiskUsage diff --git a/vendor/github.com/moby/moby/api/types/common/error_response.go b/vendor/github.com/moby/moby/api/types/common/error_response.go index b49d3eea0a..9c7f2fdc2d 100644 --- a/vendor/github.com/moby/moby/api/types/common/error_response.go +++ b/vendor/github.com/moby/moby/api/types/common/error_response.go @@ -2,9 +2,6 @@ package common -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ErrorResponse Represents an error. // Example: {"message":"Something went wrong."} // diff --git a/vendor/github.com/moby/moby/api/types/common/id_response.go b/vendor/github.com/moby/moby/api/types/common/id_response.go index 7dfe4bf12b..546f5e8d1f 100644 --- a/vendor/github.com/moby/moby/api/types/common/id_response.go +++ b/vendor/github.com/moby/moby/api/types/common/id_response.go @@ -2,9 +2,6 @@ package common -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // IDResponse Response to an API call that returns just an Id // // swagger:model IDResponse diff --git a/vendor/github.com/moby/moby/api/types/container/change_type.go b/vendor/github.com/moby/moby/api/types/container/change_type.go index 52fc99235b..1f2ac105f7 100644 --- a/vendor/github.com/moby/moby/api/types/container/change_type.go +++ b/vendor/github.com/moby/moby/api/types/container/change_type.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ChangeType Kind of change // // Can be one of: diff --git a/vendor/github.com/moby/moby/api/types/container/create_response.go b/vendor/github.com/moby/moby/api/types/container/create_response.go index 39d761aa96..9fc92fb6fe 100644 --- a/vendor/github.com/moby/moby/api/types/container/create_response.go +++ b/vendor/github.com/moby/moby/api/types/container/create_response.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // CreateResponse ContainerCreateResponse // // # OK response to ContainerCreate operation diff --git a/vendor/github.com/moby/moby/api/types/container/disk_usage.go b/vendor/github.com/moby/moby/api/types/container/disk_usage.go index c36721d3b0..0c0a772d62 100644 --- a/vendor/github.com/moby/moby/api/types/container/disk_usage.go +++ b/vendor/github.com/moby/moby/api/types/container/disk_usage.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DiskUsage represents system data usage information for container resources. // // swagger:model DiskUsage diff --git a/vendor/github.com/moby/moby/api/types/container/filesystem_change.go b/vendor/github.com/moby/moby/api/types/container/filesystem_change.go index b9ec83e521..d895095259 100644 --- a/vendor/github.com/moby/moby/api/types/container/filesystem_change.go +++ b/vendor/github.com/moby/moby/api/types/container/filesystem_change.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // FilesystemChange Change in the container's filesystem. // // swagger:model FilesystemChange diff --git a/vendor/github.com/moby/moby/api/types/container/port_summary.go b/vendor/github.com/moby/moby/api/types/container/port_summary.go index 68148eece4..0cb7455f36 100644 --- a/vendor/github.com/moby/moby/api/types/container/port_summary.go +++ b/vendor/github.com/moby/moby/api/types/container/port_summary.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( "net/netip" ) diff --git a/vendor/github.com/moby/moby/api/types/container/top_response.go b/vendor/github.com/moby/moby/api/types/container/top_response.go index 966603617f..50124e8a76 100644 --- a/vendor/github.com/moby/moby/api/types/container/top_response.go +++ b/vendor/github.com/moby/moby/api/types/container/top_response.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // TopResponse ContainerTopResponse // // Container "top" response. diff --git a/vendor/github.com/moby/moby/api/types/container/update_response.go b/vendor/github.com/moby/moby/api/types/container/update_response.go index 2f7263b141..94e5eccb20 100644 --- a/vendor/github.com/moby/moby/api/types/container/update_response.go +++ b/vendor/github.com/moby/moby/api/types/container/update_response.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // UpdateResponse ContainerUpdateResponse // // Response for a successful container-update. diff --git a/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go b/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go index 96a7770c34..50f353f95e 100644 --- a/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go +++ b/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // WaitExitError container waiting error, if any // // swagger:model WaitExitError diff --git a/vendor/github.com/moby/moby/api/types/container/wait_response.go b/vendor/github.com/moby/moby/api/types/container/wait_response.go index 68d3c38724..ff9281dd91 100644 --- a/vendor/github.com/moby/moby/api/types/container/wait_response.go +++ b/vendor/github.com/moby/moby/api/types/container/wait_response.go @@ -2,9 +2,6 @@ package container -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // WaitResponse ContainerWaitResponse // // # OK response to ContainerWait operation diff --git a/vendor/github.com/moby/moby/api/types/image/delete_response.go b/vendor/github.com/moby/moby/api/types/image/delete_response.go index b19119a381..c0a0a5af3d 100644 --- a/vendor/github.com/moby/moby/api/types/image/delete_response.go +++ b/vendor/github.com/moby/moby/api/types/image/delete_response.go @@ -2,9 +2,6 @@ package image -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DeleteResponse delete response // // swagger:model DeleteResponse diff --git a/vendor/github.com/moby/moby/api/types/image/disk_usage.go b/vendor/github.com/moby/moby/api/types/image/disk_usage.go index 7297813c1d..bbe2d57672 100644 --- a/vendor/github.com/moby/moby/api/types/image/disk_usage.go +++ b/vendor/github.com/moby/moby/api/types/image/disk_usage.go @@ -2,9 +2,6 @@ package image -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DiskUsage represents system data usage for image resources. // // swagger:model DiskUsage diff --git a/vendor/github.com/moby/moby/api/types/image/history_response_item.go b/vendor/github.com/moby/moby/api/types/image/history_response_item.go index 3de3181ab9..c7b1eddcd9 100644 --- a/vendor/github.com/moby/moby/api/types/image/history_response_item.go +++ b/vendor/github.com/moby/moby/api/types/image/history_response_item.go @@ -2,9 +2,6 @@ package image -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // HistoryResponseItem HistoryResponseItem // // individual image layer information in response to ImageHistory operation diff --git a/vendor/github.com/moby/moby/api/types/network/config_reference.go b/vendor/github.com/moby/moby/api/types/network/config_reference.go index 1158afe655..0c940a9e74 100644 --- a/vendor/github.com/moby/moby/api/types/network/config_reference.go +++ b/vendor/github.com/moby/moby/api/types/network/config_reference.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ConfigReference The config-only network source to provide the configuration for // this network. // diff --git a/vendor/github.com/moby/moby/api/types/network/connect_request.go b/vendor/github.com/moby/moby/api/types/network/connect_request.go index 2ff14d3603..68fbf16844 100644 --- a/vendor/github.com/moby/moby/api/types/network/connect_request.go +++ b/vendor/github.com/moby/moby/api/types/network/connect_request.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ConnectRequest NetworkConnectRequest represents the data to be used to connect a container to a network. // // swagger:model ConnectRequest diff --git a/vendor/github.com/moby/moby/api/types/network/create_response.go b/vendor/github.com/moby/moby/api/types/network/create_response.go index 1997059912..429b278e48 100644 --- a/vendor/github.com/moby/moby/api/types/network/create_response.go +++ b/vendor/github.com/moby/moby/api/types/network/create_response.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // CreateResponse NetworkCreateResponse // // # OK response to NetworkCreate operation diff --git a/vendor/github.com/moby/moby/api/types/network/disconnect_request.go b/vendor/github.com/moby/moby/api/types/network/disconnect_request.go index 7b1f521e77..aeebee70a9 100644 --- a/vendor/github.com/moby/moby/api/types/network/disconnect_request.go +++ b/vendor/github.com/moby/moby/api/types/network/disconnect_request.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DisconnectRequest NetworkDisconnectRequest represents the data to be used to disconnect a container from a network. // // swagger:model DisconnectRequest diff --git a/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go index bf493ad5dd..a9ab27ae3c 100644 --- a/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go +++ b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( "net/netip" ) diff --git a/vendor/github.com/moby/moby/api/types/network/inspect.go b/vendor/github.com/moby/moby/api/types/network/inspect.go index cded5e6081..c07026ac40 100644 --- a/vendor/github.com/moby/moby/api/types/network/inspect.go +++ b/vendor/github.com/moby/moby/api/types/network/inspect.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Inspect The body of the "get network" http response message. // // swagger:model Inspect diff --git a/vendor/github.com/moby/moby/api/types/network/ipam_status.go b/vendor/github.com/moby/moby/api/types/network/ipam_status.go index 7eb4e8487e..50e410ff8f 100644 --- a/vendor/github.com/moby/moby/api/types/network/ipam_status.go +++ b/vendor/github.com/moby/moby/api/types/network/ipam_status.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // IPAMStatus IPAM status // // swagger:model IPAMStatus diff --git a/vendor/github.com/moby/moby/api/types/network/network.go b/vendor/github.com/moby/moby/api/types/network/network.go index a7d9c0f6ad..b2d4d43cd2 100644 --- a/vendor/github.com/moby/moby/api/types/network/network.go +++ b/vendor/github.com/moby/moby/api/types/network/network.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( timeext "time" ) diff --git a/vendor/github.com/moby/moby/api/types/network/peer_info.go b/vendor/github.com/moby/moby/api/types/network/peer_info.go index dc88ec16fa..8638e61623 100644 --- a/vendor/github.com/moby/moby/api/types/network/peer_info.go +++ b/vendor/github.com/moby/moby/api/types/network/peer_info.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( "net/netip" ) diff --git a/vendor/github.com/moby/moby/api/types/network/service_info.go b/vendor/github.com/moby/moby/api/types/network/service_info.go index fdd92f1611..abb3619533 100644 --- a/vendor/github.com/moby/moby/api/types/network/service_info.go +++ b/vendor/github.com/moby/moby/api/types/network/service_info.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( "net/netip" ) diff --git a/vendor/github.com/moby/moby/api/types/network/status.go b/vendor/github.com/moby/moby/api/types/network/status.go index 94f4b4b2ec..b90f1bf1e8 100644 --- a/vendor/github.com/moby/moby/api/types/network/status.go +++ b/vendor/github.com/moby/moby/api/types/network/status.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Status provides runtime information about the network such as the number of allocated IPs. // // swagger:model Status diff --git a/vendor/github.com/moby/moby/api/types/network/subnet_status.go b/vendor/github.com/moby/moby/api/types/network/subnet_status.go index dd62429f5f..de74c7a2e6 100644 --- a/vendor/github.com/moby/moby/api/types/network/subnet_status.go +++ b/vendor/github.com/moby/moby/api/types/network/subnet_status.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // SubnetStatus subnet status // // swagger:model SubnetStatus diff --git a/vendor/github.com/moby/moby/api/types/network/summary.go b/vendor/github.com/moby/moby/api/types/network/summary.go index 3f50ce2278..50c346ffa5 100644 --- a/vendor/github.com/moby/moby/api/types/network/summary.go +++ b/vendor/github.com/moby/moby/api/types/network/summary.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Summary Network list response item // // swagger:model Summary diff --git a/vendor/github.com/moby/moby/api/types/network/task.go b/vendor/github.com/moby/moby/api/types/network/task.go index a547523a44..c0eac2322e 100644 --- a/vendor/github.com/moby/moby/api/types/network/task.go +++ b/vendor/github.com/moby/moby/api/types/network/task.go @@ -2,9 +2,6 @@ package network -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - import ( "net/netip" ) diff --git a/vendor/github.com/moby/moby/api/types/plugin/device.go b/vendor/github.com/moby/moby/api/types/plugin/device.go index ae96177047..2044e4b99a 100644 --- a/vendor/github.com/moby/moby/api/types/plugin/device.go +++ b/vendor/github.com/moby/moby/api/types/plugin/device.go @@ -2,9 +2,6 @@ package plugin -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Device device // // swagger:model Device diff --git a/vendor/github.com/moby/moby/api/types/plugin/env.go b/vendor/github.com/moby/moby/api/types/plugin/env.go index dcbe0b762d..99ee46dabf 100644 --- a/vendor/github.com/moby/moby/api/types/plugin/env.go +++ b/vendor/github.com/moby/moby/api/types/plugin/env.go @@ -2,9 +2,6 @@ package plugin -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Env env // // swagger:model Env diff --git a/vendor/github.com/moby/moby/api/types/plugin/mount.go b/vendor/github.com/moby/moby/api/types/plugin/mount.go index 7970306cc8..9426a94c57 100644 --- a/vendor/github.com/moby/moby/api/types/plugin/mount.go +++ b/vendor/github.com/moby/moby/api/types/plugin/mount.go @@ -2,9 +2,6 @@ package plugin -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Mount mount // // swagger:model Mount diff --git a/vendor/github.com/moby/moby/api/types/plugin/plugin.go b/vendor/github.com/moby/moby/api/types/plugin/plugin.go index 3305170d5e..2dcf83be25 100644 --- a/vendor/github.com/moby/moby/api/types/plugin/plugin.go +++ b/vendor/github.com/moby/moby/api/types/plugin/plugin.go @@ -2,9 +2,6 @@ package plugin -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Plugin A plugin for the Engine API // // swagger:model Plugin diff --git a/vendor/github.com/moby/moby/api/types/registry/auth_response.go b/vendor/github.com/moby/moby/api/types/registry/auth_response.go index 94c2e1bb36..c7057d8606 100644 --- a/vendor/github.com/moby/moby/api/types/registry/auth_response.go +++ b/vendor/github.com/moby/moby/api/types/registry/auth_response.go @@ -2,9 +2,6 @@ package registry -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // AuthResponse An identity token was generated successfully. // // swagger:model AuthResponse diff --git a/vendor/github.com/moby/moby/api/types/storage/driver_data.go b/vendor/github.com/moby/moby/api/types/storage/driver_data.go index 65d5b4c20e..5e6cb22ab5 100644 --- a/vendor/github.com/moby/moby/api/types/storage/driver_data.go +++ b/vendor/github.com/moby/moby/api/types/storage/driver_data.go @@ -2,9 +2,6 @@ package storage -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DriverData Information about the storage driver used to store the container's and // image's filesystem. // diff --git a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go index d82f2b6bcb..ecf63ea0cc 100644 --- a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go +++ b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go @@ -2,9 +2,6 @@ package storage -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // RootFSStorage Information about the storage used for the container's root filesystem. // // swagger:model RootFSStorage diff --git a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go index dd2b82d245..c040636da8 100644 --- a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go +++ b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go @@ -2,9 +2,6 @@ package storage -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // RootFSStorageSnapshot Information about a snapshot backend of the container's root filesystem. // // swagger:model RootFSStorageSnapshot diff --git a/vendor/github.com/moby/moby/api/types/storage/storage.go b/vendor/github.com/moby/moby/api/types/storage/storage.go index 77843db970..4cf31c54b5 100644 --- a/vendor/github.com/moby/moby/api/types/storage/storage.go +++ b/vendor/github.com/moby/moby/api/types/storage/storage.go @@ -2,9 +2,6 @@ package storage -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Storage Information about the storage used by the container. // // swagger:model Storage diff --git a/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go b/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go index ebbc097d90..2dcc49c903 100644 --- a/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go +++ b/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go @@ -2,9 +2,6 @@ package swarm -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ServiceCreateResponse contains the information returned to a client on the // creation of a new service. // diff --git a/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go b/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go index b7649096a0..be5d44c4cf 100644 --- a/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go +++ b/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go @@ -2,9 +2,6 @@ package swarm -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ServiceUpdateResponse service update response // Example: {"Warnings":["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]} // diff --git a/vendor/github.com/moby/moby/api/types/volume/create_request.go b/vendor/github.com/moby/moby/api/types/volume/create_request.go index 3217df8270..17c5f86784 100644 --- a/vendor/github.com/moby/moby/api/types/volume/create_request.go +++ b/vendor/github.com/moby/moby/api/types/volume/create_request.go @@ -2,9 +2,6 @@ package volume -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // CreateRequest VolumeConfig // // # Volume configuration diff --git a/vendor/github.com/moby/moby/api/types/volume/disk_usage.go b/vendor/github.com/moby/moby/api/types/volume/disk_usage.go index e2afbac659..cbf740e33c 100644 --- a/vendor/github.com/moby/moby/api/types/volume/disk_usage.go +++ b/vendor/github.com/moby/moby/api/types/volume/disk_usage.go @@ -2,9 +2,6 @@ package volume -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // DiskUsage represents system data usage for volume resources. // // swagger:model DiskUsage diff --git a/vendor/github.com/moby/moby/api/types/volume/list_response.go b/vendor/github.com/moby/moby/api/types/volume/list_response.go index f257762f09..02dc415a5f 100644 --- a/vendor/github.com/moby/moby/api/types/volume/list_response.go +++ b/vendor/github.com/moby/moby/api/types/volume/list_response.go @@ -2,9 +2,6 @@ package volume -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // ListResponse VolumeListResponse // // # Volume list response diff --git a/vendor/github.com/moby/moby/api/types/volume/volume.go b/vendor/github.com/moby/moby/api/types/volume/volume.go index 524ebfb8ac..a3d6d82864 100644 --- a/vendor/github.com/moby/moby/api/types/volume/volume.go +++ b/vendor/github.com/moby/moby/api/types/volume/volume.go @@ -2,9 +2,6 @@ package volume -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - // Volume volume // // swagger:model Volume diff --git a/vendor/github.com/moby/moby/client/client.go b/vendor/github.com/moby/moby/client/client.go index 3dbcacdeb9..f407505e01 100644 --- a/vendor/github.com/moby/moby/client/client.go +++ b/vendor/github.com/moby/moby/client/client.go @@ -60,7 +60,6 @@ import ( "net/url" "path" "runtime" - "slices" "strings" "sync" "sync/atomic" @@ -250,10 +249,11 @@ func New(ops ...Opt) (*Client, error) { c.client.Transport = otelhttp.NewTransport(c.client.Transport, c.traceOpts...) - if len(cfg.responseHooks) > 0 { - c.client.Transport = &responseHookTransport{ - base: c.client.Transport, - hooks: slices.Clone(cfg.responseHooks), + if len(cfg.requestHooks) > 0 || len(cfg.responseHooks) > 0 { + c.client.Transport = &hookTransport{ + base: c.client.Transport, + reqHooks: cfg.requestHooks, + respHooks: cfg.responseHooks, } } diff --git a/vendor/github.com/moby/moby/client/client_hook.go b/vendor/github.com/moby/moby/client/client_hook.go new file mode 100644 index 0000000000..c9afa34ddd --- /dev/null +++ b/vendor/github.com/moby/moby/client/client_hook.go @@ -0,0 +1,70 @@ +package client + +import ( + "errors" + "io" + "net/http" +) + +type hookTransport struct { + base http.RoundTripper + reqHooks []RequestHook + respHooks []ResponseHook +} + +func (t *hookTransport) RoundTrip(req *http.Request) (*http.Response, error) { + if len(t.reqHooks) > 0 { + hookReq := req.Clone(req.Context()) + + if hookReq.Body != nil { + hookReq.Body = hookBody{} + } + if hookReq.GetBody != nil { + hookReq.GetBody = func() (io.ReadCloser, error) { + return hookBody{}, nil + } + } + + for _, h := range t.reqHooks { + if err := h(hookReq); err != nil { + // The base transport never takes ownership, so close the original + // request body before returning the hook error. + if req.Body != nil { + _ = req.Body.Close() + } + return nil, err + } + } + // Restore the actual request body after the hooks have run. The + // modified request metadata is preserved on hookReq. + hookReq.Body = req.Body + hookReq.GetBody = req.GetBody + req = hookReq + } + + resp, err := t.base.RoundTrip(req) + if err != nil { + return resp, err + } + + if len(t.respHooks) > 0 { + hookResp := *resp + if hookResp.Body != nil { + hookResp.Body = hookBody{} + } + + for _, h := range t.respHooks { + h(&hookResp) + } + } + + return resp, nil +} + +type hookBody struct{} + +func (hookBody) Read([]byte) (int, error) { + return 0, errors.New("hooks must not read HTTP message body") +} + +func (hookBody) Close() error { return nil } diff --git a/vendor/github.com/moby/moby/client/client_options.go b/vendor/github.com/moby/moby/client/client_options.go index 3992557230..3499172c4d 100644 --- a/vendor/github.com/moby/moby/client/client_options.go +++ b/vendor/github.com/moby/moby/client/client_options.go @@ -58,13 +58,23 @@ type clientConfig struct { // takes precedence. Either field disables API-version negotiation. envAPIVersion string - // responseHooks is a list of custom response hooks to call on responses. + // requestHooks contains hooks to call before requests are made. + requestHooks []RequestHook + // responseHooks contains hooks to call on responses. responseHooks []ResponseHook // traceOpts is a list of options to configure the tracing span. traceOpts []otelhttp.Option } +// RequestHook is called for each HTTP request made by the client. +// Hooks are invoked in the order they were added. +// +// Hooks may inspect the request and modify request metadata, such as headers, +// before the request is sent. The request body cannot be read or closed by +// the hook. +type RequestHook func(*http.Request) error + // ResponseHook is called for each HTTP response returned by the daemon. // Hooks are invoked in the order they were added. // @@ -411,12 +421,25 @@ func WithTraceOptions(opts ...otelhttp.Option) Opt { } } -// WithResponseHook adds a ResponseHook to the client. ResponseHooks are called +// WithHTTPRequestHook adds a [RequestHook] to the client. RequestHooks are called +// before an HTTP request is made to the daemon. Hooks are invoked in the order +// they were added. +func WithHTTPRequestHook(h RequestHook) Opt { + return func(c *clientConfig) error { + if h == nil { + return errors.New("invalid request hook: hook is nil") + } + c.requestHooks = append(c.requestHooks, h) + return nil + } +} + +// WithHTTPResponseHook adds a [ResponseHook] to the client. ResponseHooks are called // for each HTTP response returned by the daemon. Hooks are invoked in the order // they were added. // // Hooks must not read or close resp.Body. -func WithResponseHook(h ResponseHook) Opt { +func WithHTTPResponseHook(h ResponseHook) Opt { return func(c *clientConfig) error { if h == nil { return errors.New("invalid response hook: hook is nil") @@ -425,3 +448,12 @@ func WithResponseHook(h ResponseHook) Opt { return nil } } + +// WithResponseHook is equivalent to [WithHTTPResponseHook]. +// +// Deprecated: use [WithHTTPResponseHook] instead. +// +//go:fix inline +func WithResponseHook(h ResponseHook) Opt { + return WithHTTPResponseHook(h) +} diff --git a/vendor/github.com/moby/moby/client/client_responsehook.go b/vendor/github.com/moby/moby/client/client_responsehook.go deleted file mode 100644 index 7c93f111c7..0000000000 --- a/vendor/github.com/moby/moby/client/client_responsehook.go +++ /dev/null @@ -1,23 +0,0 @@ -package client - -import ( - "net/http" -) - -type responseHookTransport struct { - base http.RoundTripper - hooks []ResponseHook -} - -func (t *responseHookTransport) RoundTrip(req *http.Request) (*http.Response, error) { - resp, err := t.base.RoundTrip(req) - if err != nil { - return resp, err - } - - for _, h := range t.hooks { - h(resp) - } - - return resp, nil -} diff --git a/vendor/github.com/moby/moby/client/container_attach.go b/vendor/github.com/moby/moby/client/container_attach.go index ce84122d32..9619e812b2 100644 --- a/vendor/github.com/moby/moby/client/container_attach.go +++ b/vendor/github.com/moby/moby/client/container_attach.go @@ -75,9 +75,8 @@ func (cli *Client) ContainerAttach(ctx context.Context, containerID string, opti query.Set("logs", "1") } - hijacked, err := cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, nil, http.Header{ - "Content-Type": {"text/plain"}, - }) + headers := http.Header{"Content-Type": {"text/plain"}} + hijacked, err := cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, headers, nil) if err != nil { return ContainerAttachResult{}, err } diff --git a/vendor/github.com/moby/moby/client/container_exec.go b/vendor/github.com/moby/moby/client/container_exec.go index 86c9474b48..d831521842 100644 --- a/vendor/github.com/moby/moby/client/container_exec.go +++ b/vendor/github.com/moby/moby/client/container_exec.go @@ -134,13 +134,11 @@ func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAt if err != nil { return ExecAttachResult{}, err } - req := container.ExecStartRequest{ + headers := http.Header{"Content-Type": {"application/json"}} + response, err := cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, headers, container.ExecStartRequest{ Detach: false, Tty: options.TTY, ConsoleSize: consoleSize, - } - response, err := cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, req, http.Header{ - "Content-Type": {"application/json"}, }) return ExecAttachResult{HijackedResponse: response}, err } diff --git a/vendor/github.com/moby/moby/client/hijack.go b/vendor/github.com/moby/moby/client/hijack.go index 3b6b12c8fd..fbb0402725 100644 --- a/vendor/github.com/moby/moby/client/hijack.go +++ b/vendor/github.com/moby/moby/client/hijack.go @@ -13,7 +13,7 @@ import ( ) // postHijacked sends a POST request and hijacks the connection. -func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, body any, headers map[string][]string) (HijackedResponse, error) { +func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, headers map[string][]string, body any) (HijackedResponse, error) { jsonBody, err := jsonEncode(body) if err != nil { return HijackedResponse{}, err @@ -22,7 +22,7 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu if err != nil { return HijackedResponse{}, err } - conn, mediaType, err := setupHijackConn(cli.dialer(), req, "tcp") + conn, mediaType, err := cli.setupHijackConn(req, "tcp") if err != nil { return HijackedResponse{}, err } @@ -38,16 +38,17 @@ func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[s } req = cli.addHeaders(req, meta) - conn, _, err := setupHijackConn(cli.Dialer(), req, proto) + conn, _, err := cli.setupHijackConn(req, proto) return conn, err } -func setupHijackConn(dialer func(context.Context) (net.Conn, error), req *http.Request, proto string) (_ net.Conn, _ string, retErr error) { +func (cli *Client) setupHijackConn(req *http.Request, proto string) (retConn net.Conn, mediaType string, retErr error) { ctx := req.Context() req.Header.Set("Connection", "Upgrade") req.Header.Set("Upgrade", proto) - conn, err := dialer(ctx) + dial := cli.dialer() + conn, err := dial(ctx) if err != nil { return nil, "", fmt.Errorf("cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: %w", err) } @@ -69,8 +70,33 @@ func setupHijackConn(dialer func(context.Context) (net.Conn, error), req *http.R hc := &hijackedConn{conn, bufio.NewReader(conn)} + // Cancel the handshake without tying the returned connection to ctx. + cancelled := make(chan struct{}) + stop := context.AfterFunc(ctx, func() { + _ = hc.Conn.Close() + close(cancelled) + }) + defer func() { + if !stop() { + // Cancellation won the race; don't return a connection being closed. + <-cancelled + retConn, mediaType, retErr = nil, "", ctx.Err() + } + }() + + cfg := &cli.clientConfig + + var rt http.RoundTripper = otelhttp.NewTransport(hc, cli.traceOpts...) + if len(cfg.requestHooks) > 0 || len(cfg.responseHooks) > 0 { + rt = &hookTransport{ + base: rt, + reqHooks: cfg.requestHooks, + respHooks: cfg.responseHooks, + } + } + // Server hijacks the connection, error 'connection closed' expected - resp, err := otelhttp.NewTransport(hc).RoundTrip(req) + resp, err := rt.RoundTrip(req) if err != nil { return nil, "", err } diff --git a/vendor/github.com/moby/moby/client/plugin_create.go b/vendor/github.com/moby/moby/client/plugin_create.go index f4e7c9a02f..774b9e36b5 100644 --- a/vendor/github.com/moby/moby/client/plugin_create.go +++ b/vendor/github.com/moby/moby/client/plugin_create.go @@ -19,12 +19,10 @@ type PluginCreateResult struct { // PluginCreate creates a plugin func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) (PluginCreateResult, error) { - headers := http.Header(make(map[string][]string)) - headers.Set("Content-Type", "application/x-tar") - query := url.Values{} query.Set("name", createOptions.RepoName) + headers := http.Header{"Content-Type": {"application/x-tar"}} resp, err := cli.postRaw(ctx, "/plugins/create", query, headers, createContext) defer ensureReaderClosed(resp) return PluginCreateResult{}, err diff --git a/vendor/github.com/sirupsen/logrus/hooks/slog/handler.go b/vendor/github.com/sirupsen/logrus/hooks/slog/handler.go new file mode 100644 index 0000000000..1b846c3c04 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/slog/handler.go @@ -0,0 +1,201 @@ +package slog + +import ( + "context" + "log/slog" + "maps" + "runtime" + "slices" + "strings" + + "github.com/sirupsen/logrus" +) + +// HandlerOptions are options for a [Handler]. +// A zero HandlerOptions consists entirely of default values. +type HandlerOptions struct { + // AddSource causes the handler to include the source code position + // of the log statement in the Logrus entry. + AddSource bool + + // LevelMapper maps slog levels to Logrus levels. If nil, the default + // mapping is used. Set it to customize level mapping, for example to map + // custom slog levels to specific Logrus levels. + LevelMapper func(slog.Level) logrus.Level +} + +// Handler is a [slog.Handler] that writes records to a [logrus.Logger]. +// +// It is intended for bridging libraries or application code that log via slog +// into an existing Logrus logger, for example during a gradual migration. +// +// By default, slog levels are mapped using [SlogLevel]. +// Set [HandlerOptions.LevelMapper] to customize the mapping. +// +// Mapping to [logrus.FatalLevel] or [logrus.PanicLevel] preserves the level +// only; handling a record does not exit or panic. +type Handler struct { + logger *logrus.Logger + opts HandlerOptions + + // fields holds attributes from prior WithAttrs calls, already resolved + // under the group prefix that applied when they were added. + fields logrus.Fields + + // groups is the current group name stack for attributes added later. + groups []string +} + +var _ slog.Handler = (*Handler)(nil) + +// NewHandler creates a [slog.Handler] that writes to the provided +// [logrus.Logger]. +// +// The provided logger must not be nil. NewHandler panics if logger is nil. +// If opts is nil, the default options are used. +func NewHandler(logger *logrus.Logger, opts *HandlerOptions) *Handler { + if logger == nil { + panic("cannot create handler from nil logger") + } + if opts == nil { + opts = &HandlerOptions{} + } + return &Handler{ + logger: logger, + opts: *opts, + } +} + +// toLogrusLevel maps a slog level using LevelMapper or the default mapping. +func (h *Handler) toLogrusLevel(level slog.Level) logrus.Level { + if h.opts.LevelMapper != nil { + return h.opts.LevelMapper(level) + } + return SlogLevel(level).Level() +} + +// Enabled reports whether the handler handles records at the given level. +// It maps the slog level to a logrus level and consults the underlying logger. +func (h *Handler) Enabled(_ context.Context, level slog.Level) bool { + return h.logger.IsLevelEnabled(h.toLogrusLevel(level)) +} + +// Handle converts the slog record into a logrus entry and logs it. +// Record time, context, message, and attributes (including those from +// [Handler.WithAttrs]/[Handler.WithGroup]) are preserved. Attributes are +// attached as logrus fields; group names are joined with "." as a key prefix +// (similar to [slog.TextHandler]). +func (h *Handler) Handle(ctx context.Context, record slog.Record) error { + // Stop recursive forwarding before it can cycle back through this logger. + if hasLogrusLogger(ctx, h.logger) { + return nil + } + level := h.toLogrusLevel(record.Level) + if !h.logger.IsLevelEnabled(level) { + return nil + } + + entry := &logrus.Entry{ + Logger: h.logger, + Data: h.fields, + Time: record.Time, + Context: ctx, + } + + if h.opts.AddSource && record.PC != 0 { + // Preserve the caller selected by slog instead of rediscovering it + // through Logrus's caller stack filtering. + // + // Record.PC is a return PC; resolve it with CallersFrames. + frame, _ := runtime.CallersFrames([]uintptr{record.PC}).Next() + entry.Caller = &frame + } + + if n := record.NumAttrs(); n > 0 { + // Clone before mutating the handler's fields. + entry.Data = maps.Clone(h.fields) + if entry.Data == nil { + entry.Data = make(logrus.Fields, n) + } + record.Attrs(func(a slog.Attr) bool { + appendAttr(entry.Data, h.groups, a) + return true + }) + } + + entry.Log(level, record.Message) + return nil +} + +// WithAttrs returns a new Handler whose attributes consist of h's attributes +// followed by attrs. +func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + h2 := h.clone() + h2.fields = maps.Clone(h.fields) + if h2.fields == nil { + h2.fields = make(logrus.Fields, len(attrs)) + } + for _, a := range attrs { + appendAttr(h2.fields, h.groups, a) + } + return h2 +} + +// WithGroup returns a new Handler with a group appended to the receiver's +// existing groups. All attributes added to the returned handler (via WithAttrs +// or Handle) are nested under the combined group names. +// If name is empty, WithGroup returns h unchanged. +func (h *Handler) WithGroup(name string) slog.Handler { + if name == "" { + return h + } + h2 := h.clone() + h2.groups = append(slices.Clip(h.groups), name) + return h2 +} + +// clone returns a shallow copy of h. Callers must clone fields or groups +// before modifying them. +func (h *Handler) clone() *Handler { + return &Handler{ + logger: h.logger, + opts: h.opts, + fields: h.fields, + groups: h.groups, + } +} + +// appendAttr adds attr to fields, resolving it and applying group prefixes. +// Group attributes are flattened with "."-separated keys. +func appendAttr(fields logrus.Fields, groups []string, attr slog.Attr) { + attr.Value = attr.Value.Resolve() + if attr.Equal(slog.Attr{}) { + return + } + if attr.Value.Kind() == slog.KindGroup { + gs := attr.Value.Group() + if len(gs) == 0 { + return + } + g := groups + if attr.Key != "" { + g = append(slices.Clip(groups), attr.Key) + } + for _, a := range gs { + appendAttr(fields, g, a) + } + return + } + + key := attr.Key + if len(groups) > 0 { + key = strings.Join(groups, ".") + if attr.Key != "" { + key += "." + attr.Key + } + } + fields[key] = attr.Value.Any() +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/slog/level.go b/vendor/github.com/sirupsen/logrus/hooks/slog/level.go new file mode 100644 index 0000000000..737f5e065f --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/slog/level.go @@ -0,0 +1,119 @@ +package slog + +import ( + "log/slog" + + "github.com/sirupsen/logrus" +) + +// slog levels corresponding to Logrus levels. +const ( + slogLevelTrace = slog.LevelDebug - 4 + slogLevelDebug = slog.LevelDebug + slogLevelInfo = slog.LevelInfo + slogLevelWarn = slog.LevelWarn + slogLevelError = slog.LevelError + slogLevelFatal = slog.LevelError + 2 + slogLevelPanic = slog.LevelError + 4 +) + +// A Leveler provides a [logrus.Level] value. +// +// It is the Logrus counterpart of [slog.Leveler]. +// +// As [SlogLevel] itself implements Leveler, clients typically supply +// a SlogLevel value wherever a Leveler is needed. +// Clients who need to vary the level dynamically can provide a more complex +// Leveler implementation. +type Leveler interface { + Level() logrus.Level +} + +// Level adapts a [logrus.Level] to a [slog.Leveler] using the default +// Logrus-to-slog level mapping: +// +// - [logrus.TraceLevel] -> [slog.LevelDebug] - 4 +// - [logrus.DebugLevel] -> [slog.LevelDebug] +// - [logrus.InfoLevel] -> [slog.LevelInfo] +// - [logrus.WarnLevel] -> [slog.LevelWarn] +// - [logrus.ErrorLevel] -> [slog.LevelError] +// - [logrus.FatalLevel] -> [slog.LevelError] + 2 +// - [logrus.PanicLevel] -> [slog.LevelError] + 4 +// +// Unknown Logrus levels map to [slog.LevelError]. +type Level logrus.Level + +// Level returns l mapped to the corresponding slog level. +func (l Level) Level() slog.Level { + return toSlogLevel(logrus.Level(l)) +} + +var _ slog.Leveler = Level(0) + +// SlogLevel adapts a [slog.Level] to a [Leveler] using the default +// slog-to-Logrus level mapping: +// +// - [slog.LevelDebug] - 4 -> [logrus.TraceLevel] +// - [slog.LevelDebug] -> [logrus.DebugLevel] +// - [slog.LevelInfo] -> [logrus.InfoLevel] +// - [slog.LevelWarn] -> [logrus.WarnLevel] +// - [slog.LevelError] -> [logrus.ErrorLevel] +// - [slog.LevelError] + 2 -> [logrus.FatalLevel] +// - [slog.LevelError] + 4 -> [logrus.PanicLevel] +// +// Levels between these boundaries map to the next lower Logrus severity. +// Levels below [slog.LevelDebug] map to [logrus.TraceLevel], and levels at or +// above the Panic boundary map to [logrus.PanicLevel]. +type SlogLevel slog.Level + +// Level returns l mapped to the corresponding Logrus level. +func (l SlogLevel) Level() logrus.Level { + return toLogrusLevel(slog.Level(l)) +} + +var _ Leveler = SlogLevel(0) + +// toLogrusLevel maps a slog level using the default mapping. +func toLogrusLevel(level slog.Level) logrus.Level { + switch { + case level >= slogLevelPanic: + return logrus.PanicLevel + case level >= slogLevelFatal: + return logrus.FatalLevel + case level >= slogLevelError: + return logrus.ErrorLevel + case level >= slogLevelWarn: + return logrus.WarnLevel + case level >= slogLevelInfo: + return logrus.InfoLevel + case level >= slogLevelDebug: + return logrus.DebugLevel + case level >= slogLevelTrace: + return logrus.TraceLevel + default: + return logrus.TraceLevel + } +} + +// toSlogLevel maps a Logrus level using the default mapping. +func toSlogLevel(level logrus.Level) slog.Level { + switch level { + case logrus.PanicLevel: + return slogLevelPanic + case logrus.FatalLevel: + return slogLevelFatal + case logrus.ErrorLevel: + return slogLevelError + case logrus.WarnLevel: + return slogLevelWarn + case logrus.InfoLevel: + return slogLevelInfo + case logrus.DebugLevel: + return slogLevelDebug + case logrus.TraceLevel: + return slogLevelTrace + default: + // Treat all unknown levels as errors + return slogLevelError + } +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/slog/slog.go b/vendor/github.com/sirupsen/logrus/hooks/slog/slog.go new file mode 100644 index 0000000000..d5609ee5f6 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/slog/slog.go @@ -0,0 +1,126 @@ +// Package slog provides adapters between Logrus and log/slog. +// +// [Handler] forwards slog records to a Logrus logger, while [Hook] forwards +// Logrus entries to a slog logger. They can be used independently to support +// incremental migration between the two logging APIs. +package slog + +import ( + "context" + "log/slog" + "maps" + + "github.com/sirupsen/logrus" +) + +// logrusLoggerContextKey is the context key used to track Logrus loggers a +// record has already traversed while being forwarded through slog adapters. +type logrusLoggerContextKey struct{} + +// withLogrusLogger returns a context that records logger as having already +// handled the current log record. +func withLogrusLogger(ctx context.Context, logger *logrus.Logger) context.Context { + seen, _ := ctx.Value(logrusLoggerContextKey{}).(map[*logrus.Logger]struct{}) + seen = maps.Clone(seen) + if seen == nil { + seen = make(map[*logrus.Logger]struct{}, 1) + } + seen[logger] = struct{}{} + return context.WithValue(ctx, logrusLoggerContextKey{}, seen) +} + +// hasLogrusLogger reports whether logger has already handled the current log +// record while it was forwarded through slog adapters. +func hasLogrusLogger(ctx context.Context, logger *logrus.Logger) bool { + seen, _ := ctx.Value(logrusLoggerContextKey{}).(map[*logrus.Logger]struct{}) + _, ok := seen[logger] + return ok +} + +// HookOptions are options for a [Hook]. +// A zero HookOptions consists entirely of default values. +type HookOptions struct { + // LevelMapper maps Logrus levels to slog levels. If nil, the default + // mapping is used. Set it to customize level mapping, for example to map + // custom Logrus levels to specific slog levels. + LevelMapper func(logrus.Level) slog.Level +} + +// Hook sends Logrus entries to slog. +// +// It is intended for bridging libraries or application code that log via +// Logrus into an existing slog logger, for example during a gradual migration. +// +// By default, Logrus levels are mapped using [Level]. Set +// [HookOptions.LevelMapper] to customize the mapping. +type Hook struct { + logger *slog.Logger + opts HookOptions +} + +var _ logrus.Hook = (*Hook)(nil) + +// NewHook creates a [logrus.Hook] that sends logs to the provided [slog.Logger]. +// +// This hook is intended to be used during transition from Logrus to slog, +// or as a shim between different parts of your application or different +// libraries that depend on different loggers. +// +// The provided logger must not be nil. NewHook panics if logger is nil. +// If opts is nil, the default options are used. +func NewHook(logger *slog.Logger, opts *HookOptions) *Hook { + if logger == nil { + panic("cannot create hook from nil logger") + } + if opts == nil { + opts = &HookOptions{} + } + return &Hook{ + logger: logger, + opts: *opts, + } +} + +// toSlogLevel maps a Logrus level using LevelMapper or the default mapping. +func (h *Hook) toSlogLevel(level logrus.Level) slog.Level { + if h.opts.LevelMapper != nil { + return h.opts.LevelMapper(level) + } + return Level(level).Level() +} + +// Levels always returns all levels, since slog allows controlling level +// enabling based on context. +func (h *Hook) Levels() []logrus.Level { + return logrus.AllLevels +} + +// Fire forwards the provided logrus Entry to the underlying slog.Logger's +// Handler, mapping it to a slog.Record. Time and caller information are +// preserved when available, and Entry.Data is converted to attributes. +// If Entry.Context is nil, context.Background() is used. +func (h *Hook) Fire(entry *logrus.Entry) error { + ctx := entry.Context + if ctx == nil { + ctx = context.Background() + } + // Track this logger to guard against recursive forwarding. + ctx = withLogrusLogger(ctx, entry.Logger) + + level := h.toSlogLevel(entry.Level) + handler := h.logger.Handler() + if !handler.Enabled(ctx, level) { + return nil + } + attrs := make([]slog.Attr, 0, len(entry.Data)) + for k, v := range entry.Data { + attrs = append(attrs, slog.Any(k, v)) + } + var pc uintptr + if entry.Caller != nil { + pc = entry.Caller.PC + } + r := slog.NewRecord(entry.Time, level, entry.Message, pc) + r.AddAttrs(attrs...) + return handler.Handle(ctx, r) +} diff --git a/vendor/golang.org/x/net/http2/flow.go b/vendor/golang.org/x/net/http2/flow.go index b7dbd18695..5066a39912 100644 --- a/vendor/golang.org/x/net/http2/flow.go +++ b/vendor/golang.org/x/net/http2/flow.go @@ -10,6 +10,9 @@ package http2 // flow control window update. const inflowMinRefresh = 4 << 10 +// maxFlowWindow is the maximum size of a flow control window. +const maxFlowWindow = (1 << 31) - 1 + // inflow accounts for an inbound flow control window. // It tracks both the latest window sent to the peer (used for enforcement) // and the accumulated unsent window. @@ -74,47 +77,99 @@ func takeInflows(f1, f2 *inflow, n uint32) bool { return true } -// outflow is the outbound flow control window's size. +// connOutflow is connection-level outbound flow control. +type connOutflow struct { + initial int32 // SETTINGS_INITIAL_WINDOW_SIZE, changes with settings updates + n int32 // connection-level flow control window + flowErr bool // set when a flow control error is encountered +} + +func (f *connOutflow) init() { + f.initial = initialWindowSize // initial stream window size + f.n = initialWindowSize // current connection window size +} + +func (f *connOutflow) changeInitialWindowSize(size int64) bool { + if size > maxFlowWindow { + f.flowErr = true + return false + } + f.initial = int32(size) + return true +} + +func (f *connOutflow) add(n int32) bool { + sum := int64(f.n) + int64(n) + if sum > maxFlowWindow { + f.flowErr = true + return false + } + f.n += n + return true +} + +// outflow is the stream-level outbound flow control window's size. type outflow struct { _ incomparable - // n is the number of DATA bytes we're allowed to send. - // An outflow is kept both on a conn and a per-stream. - n int32 + // delta is the difference between the stream's flow control window and + // the connection's initial window size (conn.initial). + // + // Another view is that delta is the number of flow control bytes provided to this + // stream in WINDOW_UPDATE frames, less the number of bytes sent on the stream. + delta int32 // conn points to the shared connection-level outflow that is - // shared by all streams on that conn. It is nil for the outflow - // that's on the conn directly. - conn *outflow + // shared by all streams on that conn. + conn *connOutflow } -func (f *outflow) setConnFlow(cf *outflow) { f.conn = cf } - -func (f *outflow) available() int32 { - n := f.n - if f.conn != nil && f.conn.n < n { - n = f.conn.n +func (f *outflow) available() (int32, bool) { + if f.conn == nil { + return maxFlowWindow, true // only happens in tests } - return n + if f.conn.flowErr { + // Block all sending once any stream observes a flow control error. + return 0, false + } + n := int64(f.conn.initial) + int64(f.delta) + if n > maxFlowWindow { + f.conn.flowErr = true + return 0, false + } + return min(int32(n), f.conn.n), true } func (f *outflow) take(n int32) { - if n > f.available() { + if f.conn == nil { + return // only happens in tests + } + avail, _ := f.available() + if n > avail { panic("internal error: took too much") } - f.n -= n - if f.conn != nil { - f.conn.n -= n - } + f.delta -= n + f.conn.n -= n } // add adds n bytes (positive or negative) to the flow control window. // It returns false if the sum would exceed 2^31-1. func (f *outflow) add(n int32) bool { - sum := f.n + n - if (sum > n) == (f.n > 0) { - f.n = sum - return true + if f.conn == nil { + return true // only happens in tests } - return false + avail := int64(f.conn.initial) + int64(f.delta) + if avail > maxFlowWindow { + // An earlier change to the initial window pushed this stream over the limit. + // This is a connection-level flow control error. + f.conn.flowErr = true + return false + } + if avail+int64(n) > maxFlowWindow { + // This update would push the stream over the limit. + // This is a stream-level flow control error. + return false + } + f.delta += n + return true } diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go index be75badcc0..3363bbafc8 100644 --- a/vendor/golang.org/x/net/http2/frame.go +++ b/vendor/golang.org/x/net/http2/frame.go @@ -1711,7 +1711,8 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) { mh := &MetaHeadersFrame{ HeadersFrame: hf, } - var remainSize = fr.maxHeaderListSize() + var headersRemainSize = fr.maxHeaderListSize() + var trailersRemainSize = fr.maxHeaderListSize() var sawRegular bool var invalid error // pseudo header field errors @@ -1743,14 +1744,29 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) { return } - size := hf.Size() - if size > remainSize { + var remainSize *uint32 + var size uint32 + if hf.Name == "trailer" { + remainSize = &trailersRemainSize + fieldCount := strings.Count(hf.Value, ",") + 1 + // Rather than actually constructing hpack.HeaderField for each + // trailer field and cumulatively adding its Size, just do the math + // manually to avoid unnecessary work. This does make it so + // whitespaces after comma are counted against the budget, but that + // should be innocuous. + size = uint32(len(hf.Value)-fieldCount+1) + uint32(fieldCount)*hpack.HeaderField{}.Size() + } else { + remainSize = &headersRemainSize + size = hf.Size() + } + if size > *remainSize { hdec.SetEmitEnabled(false) mh.Truncated = true - remainSize = 0 + headersRemainSize = 0 + trailersRemainSize = 0 return } - remainSize -= size + *remainSize -= size mh.Fields = append(mh.Fields, hf) }) @@ -1766,10 +1782,10 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) { // skip parsing the fragment and close the connection. // // "Too much" is either any CONTINUATION frame after we've already - // exceeded the max header list size (in which case remainSize is 0), - // or a frame whose encoded size is more than twice the remaining - // header list bytes we're willing to accept. - if int64(len(frag)) > int64(2*remainSize) { + // exceeded the max header list size (if so, both budgets are 0), or a + // frame whose encoded size is more than twice the remaining header + // list bytes we're willing to accept. + if int64(len(frag)) > 2*int64(headersRemainSize+trailersRemainSize) { if VerboseLogs { log.Printf("http2: header list too large") } diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index a7d2053b6c..a6cd66226d 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -280,7 +280,6 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon doneServing: make(chan struct{}), clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value" advMaxStreams: conf.MaxConcurrentStreams, - initialStreamSendWindowSize: initialWindowSize, initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream, maxFrameSize: initialMaxFrameSize, pingTimeout: conf.PingTimeout, @@ -320,7 +319,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon // These start at the RFC-specified defaults. If there is a higher // configured value for inflow, that will be updated when we send a // WINDOW_UPDATE shortly after sending SETTINGS. - sc.flow.add(initialWindowSize) + sc.flow.init() sc.inflow.init(initialWindowSize) sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) sc.hpackEncoder.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize) @@ -427,7 +426,7 @@ type serverConn struct { wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes bodyReadCh chan bodyReadMsg // from handlers -> serve serveMsgCh chan interface{} // misc messages & code to send to / run on the serve loop - flow outflow // conn-wide (not stream-specific) outbound flow control + flow connOutflow // conn-wide (not stream-specific) outbound flow control inflow inflow // conn-wide inbound flow control tlsState *tls.ConnectionState // shared by all handlers, like net/http remoteAddrStr string @@ -441,6 +440,9 @@ type serverConn struct { sawFirstSettings bool // got the initial SETTINGS frame after the preface needToSendSettingsAck bool unackedSettings int // how many SETTINGS have we sent without ACKs? + pendingEncoderTableSize bool // peer changed SETTINGS_HEADER_TABLE_SIZE; apply to hpackEncoder before the next frame write + encoderTableSizeMin uint32 // smallest SETTINGS_HEADER_TABLE_SIZE since the last apply + encoderTableSize uint32 // latest SETTINGS_HEADER_TABLE_SIZE queuedControlFrames int // control frames in the writeSched queue clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit) advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client @@ -451,7 +453,6 @@ type serverConn struct { maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes streams map[uint32]*stream unstartedHandlers []unstartedHandler - initialStreamSendWindowSize int32 initialStreamRecvWindowSize int32 maxFrameSize int32 peerMaxHeaderListSize uint32 // zero means unknown (default) @@ -521,7 +522,8 @@ type stream struct { // immutable: sc *serverConn id uint32 - body *pipe // non-nil if expecting DATA frames + body *pipe // non-nil if expecting DATA frames + reqBody *requestBody cw closeWaiter // closed wait stream transitions to closed state ctx context.Context cancelCtx func() @@ -1172,6 +1174,16 @@ func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) { sc.writingFrame = true sc.needsFrameFlush = true + if sc.pendingEncoderTableSize { + // hpackEncoder may be in use by writeFrameAsync, so SETTINGS + // changes to it are deferred until no frame is being written. + // Replaying the smallest size before the latest one keeps the + // encoder's view identical to having applied every change + // (RFC 7541, Section 4.2). + sc.pendingEncoderTableSize = false + sc.hpackEncoder.SetMaxDynamicTableSize(sc.encoderTableSizeMin) + sc.hpackEncoder.SetMaxDynamicTableSize(sc.encoderTableSize) + } if wr.write.staysWithinBuffer(sc.bw.Available()) { sc.writingFrameAsync = false err := wr.write.writeFrame(sc) @@ -1271,6 +1283,11 @@ func (sc *serverConn) scheduleFrameWrite() { } sc.inFrameScheduleLoop = true for !sc.writingFrameAsync { + if sc.flow.flowErr && (!sc.inGoAway || sc.goAwayCode == ErrCodeNo) { + sc.inGoAway = true + sc.needToSendGoAway = true + sc.goAwayCode = ErrCodeFlowControl + } if sc.needToSendGoAway { sc.needToSendGoAway = false sc.startFrameWrite(FrameWriteRequest{ @@ -1294,6 +1311,9 @@ func (sc *serverConn) scheduleFrameWrite() { sc.startFrameWrite(wr) continue } + if sc.flow.flowErr { + continue + } } if sc.needsFrameFlush { sc.startFrameWrite(FrameWriteRequest{write: flushFrameWriter{}}) @@ -1526,6 +1546,10 @@ func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error { return nil } if !st.flow.add(int32(f.Increment)) { + if st.flow.conn.flowErr { + // This is a lazily-detected connection-level flow control error. + return sc.countError("bad_flow", ConnectionError(ErrCodeFlowControl)) + } return sc.countError("bad_flow", streamError(f.StreamID, ErrCodeFlowControl)) } default: // connection-level flow control @@ -1584,10 +1608,6 @@ func (sc *serverConn) closeStream(st *stream, err error) { } } if p := st.body; p != nil { - // Return any buffered unread bytes worth of conn-level flow control. - // See golang.org/issue/16481 - sc.sendWindowUpdate(nil, p.Len()) - p.CloseWithError(err) } if e, ok := err.(StreamError); ok { @@ -1641,7 +1661,12 @@ func (sc *serverConn) processSetting(s Setting) error { } switch s.ID { case SettingHeaderTableSize: - sc.hpackEncoder.SetMaxDynamicTableSize(s.Val) + // Applied by startFrameWrite; see comment there. + if !sc.pendingEncoderTableSize || s.Val < sc.encoderTableSizeMin { + sc.encoderTableSizeMin = s.Val + } + sc.encoderTableSize = s.Val + sc.pendingEncoderTableSize = true case SettingEnablePush: sc.pushEnabled = s.Val != 0 case SettingMaxConcurrentStreams: @@ -1672,28 +1697,14 @@ func (sc *serverConn) processSetting(s Setting) error { func (sc *serverConn) processSettingInitialWindowSize(val uint32) error { sc.serveG.check() - // Note: val already validated to be within range by - // processSetting's Valid call. - - // "A SETTINGS frame can alter the initial flow control window - // size for all current streams. When the value of - // SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST - // adjust the size of all stream flow control windows that it - // maintains by the difference between the new value and the - // old value." - old := sc.initialStreamSendWindowSize - sc.initialStreamSendWindowSize = int32(val) - growth := int32(val) - old // may be negative - for _, st := range sc.streams { - if !st.flow.add(growth) { - // 6.9.2 Initial Flow Control Window Size - // "An endpoint MUST treat a change to - // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow - // control window to exceed the maximum size as a - // connection error (Section 5.4.1) of type - // FLOW_CONTROL_ERROR." - return sc.countError("setting_win_size", ConnectionError(ErrCodeFlowControl)) - } + if !sc.flow.changeInitialWindowSize(int64(val)) { + // 6.9.2 Initial Flow Control Window Size + // "An endpoint MUST treat a change to + // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow + // control window to exceed the maximum size as a + // connection error (Section 5.4.1) of type + // FLOW_CONTROL_ERROR." + return sc.countError("setting_win_size", ConnectionError(ErrCodeFlowControl)) } return nil } @@ -1966,7 +1977,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { if st.reqTrailer != nil { st.trailer = make(http.Header) } - st.body = req.Body.(*requestBody).pipe // may be nil + st.body = st.reqBody.pipe // may be nil st.declBodyBytes = req.ContentLength handler := sc.handler.ServeHTTP @@ -1989,7 +2000,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout) } - return sc.scheduleHandler(id, rw, req, handler) + return sc.scheduleHandler(st, rw, req, handler) } func (sc *serverConn) upgradeRequest(req *http.Request) { @@ -2102,7 +2113,6 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState, priority } st.cw.Init() st.flow.conn = &sc.flow // link to conn-level counter - st.flow.add(sc.initialStreamSendWindowSize) st.inflow.init(sc.initialStreamRecvWindowSize) if sc.hs.WriteTimeout > 0 { st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) @@ -2184,7 +2194,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res } else { req.ContentLength = -1 } - req.Body.(*requestBody).pipe = &pipe{ + st.reqBody.pipe = &pipe{ b: &dataBuffer{expected: req.ContentLength}, } } @@ -2204,7 +2214,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp httpcommon.Server return nil, nil, sc.countError(res.InvalidReason, streamError(st.id, ErrCodeProtocol)) } - body := &requestBody{ + st.reqBody = &requestBody{ conn: sc, stream: st, needsContinue: res.NeedsContinue, @@ -2220,7 +2230,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp httpcommon.Server ProtoMinor: 0, TLS: tlsState, Host: rp.Authority, - Body: body, + Body: st.reqBody, Trailer: res.Trailer, }).WithContext(st.ctx) rw := sc.newResponseWriter(st, req) @@ -2244,11 +2254,12 @@ type unstartedHandler struct { rw *responseWriter req *http.Request handler func(http.ResponseWriter, *http.Request) + body *pipe } // scheduleHandler starts a handler goroutine, // or schedules one to start as soon as an existing handler finishes. -func (sc *serverConn) scheduleHandler(streamID uint32, rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) error { +func (sc *serverConn) scheduleHandler(st *stream, rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) error { sc.serveG.check() maxHandlers := sc.advMaxStreams if sc.curHandlers < maxHandlers { @@ -2260,10 +2271,11 @@ func (sc *serverConn) scheduleHandler(streamID uint32, rw *responseWriter, req * return sc.countError("too_many_early_resets", ConnectionError(ErrCodeEnhanceYourCalm)) } sc.unstartedHandlers = append(sc.unstartedHandlers, unstartedHandler{ - streamID: streamID, + streamID: st.id, rw: rw, req: req, handler: handler, + body: st.body, }) return nil } @@ -2277,6 +2289,10 @@ func (sc *serverConn) handlerDone() { u := sc.unstartedHandlers[i] if sc.streams[u.streamID] == nil { // This stream was reset before its goroutine had a chance to start. + if u.body != nil { + u.body.BreakWithError(errClosedBody) + sc.sendWindowUpdate(nil, u.body.Len()) + } continue } if sc.curHandlers >= maxHandlers { @@ -2298,6 +2314,12 @@ func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler didPanic := true defer func() { rw.rws.stream.cancelCtx() + if b := rw.rws.stream.reqBody; b != nil { + // Closing the body refunds flow control credit for any unconsumed data. + // (reqBody is nil for Upgrade: h2c requests, but those do not use flow + // control for the request body.) + b.Close() + } if req.MultipartForm != nil { req.MultipartForm.RemoveAll() } @@ -2396,7 +2418,7 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) { func (sc *serverConn) noteBodyRead(st *stream, n int) { sc.serveG.check() sc.sendWindowUpdate(nil, n) // conn-level - if st.state != stateHalfClosedRemote && st.state != stateClosed { + if st != nil && st.state != stateHalfClosedRemote && st.state != stateClosed { // Don't send this WINDOW_UPDATE if the stream is closed // remotely. sc.sendWindowUpdate(st, n) @@ -2444,6 +2466,9 @@ func (b *requestBody) Close() error { b.closeOnce.Do(func() { if b.pipe != nil { b.pipe.BreakWithError(errClosedBody) + if unread := b.pipe.Len(); unread > 0 { + b.conn.noteBodyReadFromHandler(nil, unread, errClosedBody) + } } }) return nil @@ -2461,9 +2486,6 @@ func (b *requestBody) Read(p []byte) (n int, err error) { if err == io.EOF { b.sawEOF = true } - if b.conn == nil { - return - } b.conn.noteBodyReadFromHandler(b.stream, n, err) return } diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 088eb9bef8..d894c6019c 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -27,6 +27,7 @@ import ( "net/http" "net/http/httptrace" "net/textproto" + "slices" "strconv" "sync" "sync/atomic" @@ -203,7 +204,7 @@ type ClientConn struct { mu sync.Mutex // guards following cond *sync.Cond // hold mu; broadcast on flow/closed changes - flow outflow // our conn-level flow control quota (cs.outflow is per stream) + flow connOutflow // our conn-level flow control quota (cs.outflow is per stream) inflow inflow // peer's conn-level flow control doNotReuse bool // whether conn is marked to not be reused for any future requests closing bool @@ -227,7 +228,6 @@ type ClientConn struct { maxConcurrentStreams uint32 peerMaxHeaderListSize uint64 peerMaxHeaderTableSize uint32 - initialWindowSize uint32 initialStreamRecvWindowSize int32 readIdleTimeout time.Duration pingTimeout time.Duration @@ -472,7 +472,6 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, internalStateHook readerDone: make(chan struct{}), nextStreamID: 1, maxFrameSize: 16 << 10, // spec default - initialWindowSize: 65535, // spec default initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream, maxConcurrentStreams: initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings. strictMaxConcurrentStreams: conf.StrictMaxConcurrentRequests, @@ -497,7 +496,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, internalStateHook } cc.cond = sync.NewCond(&cc.mu) - cc.flow.add(int32(initialWindowSize)) + cc.flow.init() // TODO: adjust this writer size to account for frame size + // MTU + crypto/tls record padding. @@ -876,6 +875,33 @@ func (cc *ClientConn) sendGoAway() error { return nil } +func (cc *ClientConn) goAwayAndClose(code ErrCode) { + cc.mu.Lock() + closed := cc.closed + cc.closing = true + cc.closed = true + cc.mu.Unlock() + if closed { + return + } + if f := cc.fr.countError; f != nil { + f(fmt.Sprintf("conn_close_error_%s", code.stringToken())) + } + done := make(chan struct{}) + go func() { + defer close(done) + cc.wmu.Lock() + cc.fr.WriteGoAway(0, code, nil) + cc.bw.Flush() + cc.wmu.Unlock() + }() + select { + case <-done: + case <-time.After(250 * time.Millisecond): + } + cc.closeForError(fmt.Errorf("http2: closing connection with %v", code)) +} + // closes the client connection immediately. In-flight requests are interrupted. // err is sent to streams. func (cc *ClientConn) closeForError(err error) { @@ -1319,7 +1345,9 @@ func (cs *clientStream) cleanupWriteRequest(err error) { } if err != nil { cs.abortStream(err) // possibly redundant, but harmless - if cs.sentHeaders { + if ce, ok := err.(ConnectionError); ok { + cc.goAwayAndClose(ErrCode(ce)) + } else if cs.sentHeaders { if se, ok := err.(StreamError); ok { if se.Cause != errFromPeer { cc.writeStreamReset(cs.ID, se.Code, false, err) @@ -1648,8 +1676,12 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) return 0, errRequestCanceled default: } - if a := cs.flow.available(); a > 0 { - take := a + avail, ok := cs.flow.available() + if !ok { + return 0, ConnectionError(ErrCodeFlowControl) + } + if avail > 0 { + take := avail if int(take) > maxBytes { take = int32(maxBytes) // can't truncate int; take is int32 @@ -1710,8 +1742,7 @@ type resAndError struct { // requires cc.mu be held. func (cc *ClientConn) addStreamLocked(cs *clientStream) { - cs.flow.add(int32(cc.initialWindowSize)) - cs.flow.setConnFlow(&cc.flow) + cs.flow.conn = &cc.flow cs.inflow.init(cc.initialStreamRecvWindowSize) cs.ID = cc.nextStreamID cc.nextStreamID += 2 @@ -2095,18 +2126,42 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra return nil, nil } + // Delete various headers that might mess up framing for HTTP/1. This is + // not a problem for HTTP/2, but someone might use HTTP/2 transport as a + // reverse proxy which forwards the response to an HTTP/1 client. Our + // HTTP/1 client transport will properly reject improper headers such as + // multiple conflicting Content-Length headers, but other implementations + // might not. + // TODO: just reject such responses? We deleted them for compatibility + // since this was done in a security fix (go.dev/issue/81115). However, + // rejecting them seems entirely reasonable and relatively safe. + + // Connection-specific header fields must not appear in an HTTP/2 message, + // and any message containing them is malformed. RFC 9113, Section 8.2.2. + for _, k := range connHeaders { + delete(res.Header, k) + } res.ContentLength = -1 - if clens := res.Header["Content-Length"]; len(clens) == 1 { - if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil { - res.ContentLength = int64(cl) + if clens, ok := res.Header["Content-Length"]; ok { + // Repeated Content-Length values may be collapsed into one only if + // they are identical per RFC 9110 Section 8.6. + // No need to trim whitespace, HTTP/2 header values must not have + // extraneous whitespace per RFC 9113 Section 8.2.1. + // Non-canonical headers are already rejected by our framer at this + // point. + conflicting := slices.ContainsFunc(clens[1:], func(clen string) bool { + return clen != clens[0] + }) + cl, err := strconv.ParseUint(clens[0], 10, 63) + if conflicting || err != nil { + delete(res.Header, "Content-Length") } else { - // TODO: care? unlike http/1, it won't mess up our framing, so it's - // more safe smuggling-wise to ignore. + res.Header["Content-Length"] = clens[:1] + res.ContentLength = int64(cl) } - } else if len(clens) > 1 { - // TODO: care? unlike http/1, it won't mess up our framing, so it's - // more safe smuggling-wise to ignore. - } else if f.StreamEnded() && !cs.isHead { + } + + if res.ContentLength < 0 && f.StreamEnded() && !cs.isHead { res.ContentLength = 0 } @@ -2417,6 +2472,10 @@ const ( func (rl *clientConnReadLoop) streamByID(id uint32, headerOrData bool) *clientStream { rl.cc.mu.Lock() defer rl.cc.mu.Unlock() + return rl.streamByIDLocked(id, headerOrData) +} + +func (rl *clientConnReadLoop) streamByIDLocked(id uint32, headerOrData bool) *clientStream { if headerOrData { // Work around an unfortunate gRPC behavior. // See comment on ClientConn.rstStreamPingsBlocked for details. @@ -2499,24 +2558,10 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error { case SettingMaxHeaderListSize: cc.peerMaxHeaderListSize = uint64(s.Val) case SettingInitialWindowSize: - // Values above the maximum flow-control - // window size of 2^31-1 MUST be treated as a - // connection error (Section 5.4.1) of type - // FLOW_CONTROL_ERROR. - if s.Val > math.MaxInt32 { + if !cc.flow.changeInitialWindowSize(int64(s.Val)) { return ConnectionError(ErrCodeFlowControl) } - - // Adjust flow control of currently-open - // frames by the difference of the old initial - // window size and this one. - delta := int32(s.Val) - int32(cc.initialWindowSize) - for _, cs := range cc.streams { - cs.flow.add(delta) - } cc.cond.Broadcast() - - cc.initialWindowSize = s.Val case SettingHeaderTableSize: cc.henc.SetMaxDynamicTableSize(s.Val) cc.peerMaxHeaderTableSize = s.Val @@ -2558,29 +2603,30 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error { func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error { cc := rl.cc - cs := rl.streamByID(f.StreamID, notHeaderOrDataFrame) - if f.StreamID != 0 && cs == nil { - return nil - } - cc.mu.Lock() defer cc.mu.Unlock() - - fl := &cc.flow - if cs != nil { - fl = &cs.flow - } - if !fl.add(int32(f.Increment)) { - // For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR - if cs != nil { + if f.StreamID == 0 { + if !cc.flow.add(int32(f.Increment)) { + return ConnectionError(ErrCodeFlowControl) + } + } else { + cs := rl.streamByIDLocked(f.StreamID, notHeaderOrDataFrame) + if cs == nil { + return nil + } + if !cs.flow.add(int32(f.Increment)) { + if cs.flow.conn.flowErr { + // This is a lazily-detected connection-level flow control error. + return ConnectionError(ErrCodeFlowControl) + } + // For stream, the sender sends RST_STREAM with + // an error code of FLOW_CONTROL_ERROR. rl.endStreamErrorLocked(cs, StreamError{ StreamID: f.StreamID, Code: ErrCodeFlowControl, }) return nil } - - return ConnectionError(ErrCodeFlowControl) } cc.cond.Broadcast() return nil diff --git a/vendor/golang.org/x/net/http2/transport_wrap.go b/vendor/golang.org/x/net/http2/transport_wrap.go index 34dfb3cca6..eeaa95f03c 100644 --- a/vendor/golang.org/x/net/http2/transport_wrap.go +++ b/vendor/golang.org/x/net/http2/transport_wrap.go @@ -119,33 +119,27 @@ type http2TransportContextKey struct{} // DialFromContext dials a new connection using the http2.Transport's DialTLS/DialTLSContext. func (t transportConfig) DialFromContext(ctx context.Context, network, address string) (net.Conn, error) { - if ctx.Value(http2TransportContextKey{}) == nil { + dial, _ := ctx.Value(http2TransportContextKey{}).(*transportRoundTripState) + if dial == nil { // We're being called from a RoundTrip that did not start with an http2.Transport. // Use the http.Transport's dialer. return nil, errors.ErrUnsupported } - - tlsConf := t.t.TLSClientConfig - if tlsConf == nil { - tlsConf = &tls.Config{} - } else { - tlsConf = tlsConf.Clone() - } - if !slices.Contains(tlsConf.NextProtos, "h2") { - tlsConf.NextProtos = append([]string{"h2"}, tlsConf.NextProtos...) - } - if tlsConf.ServerName == "" { - host, _, err := net.SplitHostPort(address) - if err == nil { - tlsConf.ServerName = host - } - } - return t.t.dialTLS(ctx, network, address, tlsConf) + return t.t.dialForRoundTrip(ctx, dial, network, address) } type transportInternal struct { initOnce sync.Once lazyt1 *http.Transport + + dialMu sync.Mutex + dials map[string]*transportDialState +} + +type transportDialState struct { + dialc chan struct{} // close when dial returns + dialErr error // dial result, set before dialc is closed + rtdonec chan struct{} // closed when RoundTrip initiating the dial returns } func (t *Transport) init() *http.Transport { @@ -167,6 +161,52 @@ func (t *Transport) configure(t1 *http.Transport) { } } +// transportRoundTripState is the state of the dial for an http2.Transport.RoundTrip. +type transportRoundTripState struct { + mu sync.Mutex + rtdone bool // set when RoundTrip returns + rtdonec chan struct{} // closed when RoundTrip returns + gotconnc chan struct{} // closed when GotConn hook is called +} + +// startDial is called when a dial starts. +// +// It returns done=true if the RoundTrip has already returned, +// in which case we should skip dialing. +func (dial *transportRoundTripState) startDial() (gotconnc chan struct{}, done bool) { + dial.mu.Lock() + defer dial.mu.Unlock() + if dial.rtdone { + return nil, true + } + if dial.rtdonec == nil { + dial.rtdonec = make(chan struct{}) + } + dial.gotconnc = make(chan struct{}) + return dial.gotconnc, false +} + +// gotConn is called when RoundTrip gets a connection. +// This may happen multiple times per RoundTrip, if a request is retried. +func (dial *transportRoundTripState) gotConn() { + dial.mu.Lock() + defer dial.mu.Unlock() + if dial.gotconnc != nil { + close(dial.gotconnc) + dial.gotconnc = nil + } +} + +// roundTripDone is called when RoundTrip returns. +func (dial *transportRoundTripState) roundTripDone() { + dial.mu.Lock() + defer dial.mu.Unlock() + dial.rtdone = true + if dial.rtdonec != nil { + close(dial.rtdonec) + } +} + func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) { t1 := t.init() @@ -186,12 +226,146 @@ func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res // Both http.Transport and http2.Transport allow the user to provide a custom // dial function, and historically you only get the dial function from the // Transport you're calling RoundTrip on. - ctx := context.WithValue(req.Context(), http2TransportContextKey{}, t) + // + // In addition, http2.Transport coalesces dials, which http.Transport historically + // has not. + dial := &transportRoundTripState{} + defer dial.roundTripDone() + ctx := context.WithValue(req.Context(), http2TransportContextKey{}, dial) + ctx = httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{ + GotConn: func(httptrace.GotConnInfo) { + // Tell dialForRoundTrip that we have received a connection. + dial.gotConn() + }, + }) req = req.WithContext(ctx) - return t1.RoundTrip(req) } +var errCoalescedDialAbandoned = errors.New("http2: abandoned coalesced dial") + +const coalescedDialRetryTimeout = 50 * time.Millisecond + +// dialForRoundTrip is called (indirectly) by net/http when dialing a new connection +// for a request call which originated as an http2.Transport.RoundTrip call. +// +// It uses the http2.Transport's Dial hooks and coalesces dials. +func (t *Transport) dialForRoundTrip(ctx context.Context, dial *transportRoundTripState, network, address string) (net.Conn, error) { + gotconnc, rtdone := dial.startDial() + if rtdone { + // RoundTrip returned, no need for this dial to proceed. + return nil, errCoalescedDialAbandoned + } + + var state *transportDialState + for { + // The first dial to an address registers itself with t.dials. + // When the dial finishes, it records the outcome and removes itself from t.dials + // so future dials will start a new round of coalescing. + // + // Subsequent dials observe that a dial is in progress, and skip dialing. + t.dialMu.Lock() + if t.dials == nil { + t.dials = make(map[string]*transportDialState) + } + leader := t.dials[address] + if leader == nil { + // No entry in t.dials to coalesce with. Add ourselves as leader. + state = &transportDialState{ + dialc: make(chan struct{}), + rtdonec: dial.rtdonec, + } + t.dials[address] = state + } + t.dialMu.Unlock() + if leader == nil { + // We are the leader, so we should dial for real. + break + } + + // Coalesce with a previous dial. + var ( + done = false + leaderdialc = leader.dialc + leaderrtdonec = leader.rtdonec + timerc <-chan time.Time + ) + for !done { + if leaderdialc == nil && leaderrtdonec == nil && timerc == nil { + // The leader finished dialing, and its RoundTrip finished. + // + // There are several possibilities, which reduce to: + // - The RoundTrip we are dialing for is about to receive + // a connection (possibly the one the leader just dialed), + // but we haven't observed it yet. + // - There's something wrong with the leader's connection, + // such as a TLS handshake failure. + // + // We have no good way to distinguish between these cases. + // + // Wait a short time for the leader's connection (or some + // other usable connection) to be delivered to our RoundTrip. + // If it is not, start a dial of our own. + timerc = time.After(coalescedDialRetryTimeout) + } + select { + case <-leaderdialc: + // The leader's dial completed. + if leader.dialErr != nil { + return nil, leader.dialErr + } + leaderdialc = nil + case <-leaderrtdonec: + // The leader's RoundTrip completed. + leaderrtdonec = nil + case <-timerc: + // The leader's dial and RoundTrip completed, and some time + // has passed. Assume we're not getting a connection and + // restart the dial process. + done = true + case <-dial.rtdonec: + // Our RoundTrip returned. + return nil, errCoalescedDialAbandoned + case <-gotconnc: + // Our RoundTrip got a connection. + return nil, errCoalescedDialAbandoned + case <-ctx.Done(): + // net/http abandoned the dial. + return nil, ctx.Err() + } + } + } + + // Dial for real. + tlsConf := t.TLSClientConfig + if tlsConf == nil { + tlsConf = &tls.Config{} + } else { + tlsConf = tlsConf.Clone() + } + if !slices.Contains(tlsConf.NextProtos, "h2") { + tlsConf.NextProtos = append([]string{"h2"}, tlsConf.NextProtos...) + } + if tlsConf.ServerName == "" { + host, _, err := net.SplitHostPort(address) + if err == nil { + tlsConf.ServerName = host + } + } + nc, err := t.dialTLS(ctx, network, address, tlsConf) + + // Remove this dial from t.dials, so future dial attempts will not coalesce with it. + t.dialMu.Lock() + delete(t.dials, address) + t.dialMu.Unlock() + + // Notify any dial coalesced with this one that we are done. + state.dialErr = err + close(state.dialc) + + return nc, err +} + func (t *Transport) closeIdleConnections() { t1 := t.init() t1.CloseIdleConnections() diff --git a/vendor/golang.org/x/net/http2/writesched.go b/vendor/golang.org/x/net/http2/writesched.go index 36ad5e32b4..f1903a8c66 100644 --- a/vendor/golang.org/x/net/http2/writesched.go +++ b/vendor/golang.org/x/net/http2/writesched.go @@ -79,10 +79,11 @@ func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteReque } // Might need to split after applying limits. - allowed := wr.stream.flow.available() - if n < allowed { - allowed = n + avail, ok := wr.stream.flow.available() + if !ok { + return empty, empty, 0 } + allowed := min(n, avail) if wr.stream.sc.maxFrameSize < allowed { allowed = wr.stream.sc.maxFrameSize } diff --git a/vendor/golang.org/x/net/internal/httpcommon/gzip.go b/vendor/golang.org/x/net/internal/httpcommon/gzip.go new file mode 100644 index 0000000000..819dd650cb --- /dev/null +++ b/vendor/golang.org/x/net/internal/httpcommon/gzip.go @@ -0,0 +1,132 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package httpcommon + +import ( + "compress/flate" + "compress/gzip" + "errors" + "io" + "io/fs" + "sync" +) + +var errConcurrentRead = errors.New("http: concurrent read on response body") + +// incomparable is a zero-width, non-comparable type. Adding it to a struct +// makes that struct also non-comparable, and generally doesn't add +// any size (as long as it's first). +type incomparable [0]func() + +// GzipReader wraps a response body so it can lazily +// get gzip.Reader from the pool on the first call to Read. +// After Close is called it puts gzip.Reader to the pool immediately +// if there is no Read in progress or later when Read completes. +type GzipReader struct { + _ incomparable + Body io.ReadCloser // underlying Response.Body + mu sync.Mutex // guards zr and zerr + zr *gzip.Reader // stores gzip reader from the pool between reads + zerr error // sticky gzip reader init error or sentinel value to detect concurrent read and read after close +} + +type eofReader struct{} + +func (eofReader) Read([]byte) (int, error) { return 0, io.EOF } +func (eofReader) ReadByte() (byte, error) { return 0, io.EOF } + +var gzipPool = sync.Pool{New: func() any { return new(gzip.Reader) }} + +// gzipPoolGet gets a gzip.Reader from the pool and resets it to read from r. +func gzipPoolGet(r io.Reader) (*gzip.Reader, error) { + zr := gzipPool.Get().(*gzip.Reader) + if err := zr.Reset(r); err != nil { + gzipPoolPut(zr) + return nil, err + } + return zr, nil +} + +// gzipPoolPut puts a gzip.Reader back into the pool. +func gzipPoolPut(zr *gzip.Reader) { + // Reset will allocate bufio.Reader if we pass it anything + // other than a flate.Reader, so ensure that it's getting one. + var r flate.Reader = eofReader{} + zr.Reset(r) + gzipPool.Put(zr) +} + +// acquire returns a gzip.Reader for reading response body. +// The reader must be released after use. +func (gz *GzipReader) acquire() (*gzip.Reader, error) { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr != nil { + return nil, gz.zerr + } + if gz.zr == nil { + // gzipPoolGet might block indefinitely since it reads the gzip header. + // Therefore, drop mu temporarily when using gzipPoolGet. + // We set zerr to errConcurrentRead to prevent concurrent read + // even when mu is temporarily dropped. + gz.zerr = errConcurrentRead + gz.mu.Unlock() + zr, err := gzipPoolGet(gz.Body) + gz.mu.Lock() + // Guard against Close being called while gzipPoolGet is running. + if gz.zerr != errConcurrentRead { + if zr != nil { + gzipPoolPut(zr) + } + return nil, gz.zerr + } + gz.zr, gz.zerr = zr, err + if gz.zerr != nil { + return nil, gz.zerr + } + } + ret := gz.zr + gz.zr, gz.zerr = nil, errConcurrentRead + return ret, nil +} + +// release returns the gzip.Reader to the pool if Close was called during Read. +func (gz *GzipReader) release(zr *gzip.Reader) { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr == errConcurrentRead { + gz.zr, gz.zerr = zr, nil + } else { // fs.ErrClosed + gzipPoolPut(zr) + } +} + +// close returns the gzip.Reader to the pool immediately or +// signals release to do so after Read completes. +func (gz *GzipReader) close() { + gz.mu.Lock() + defer gz.mu.Unlock() + if gz.zerr == nil && gz.zr != nil { + gzipPoolPut(gz.zr) + gz.zr = nil + } + gz.zerr = fs.ErrClosed +} + +func (gz *GzipReader) Read(p []byte) (n int, err error) { + zr, err := gz.acquire() + if err != nil { + return 0, err + } + defer gz.release(zr) + + return zr.Read(p) +} + +func (gz *GzipReader) Close() error { + gz.close() + + return gz.Body.Close() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 501237c5a1..c9f32360ea 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,12 +1,12 @@ # dario.cat/mergo v1.0.2 ## explicit; go 1.13 dario.cat/mergo -# github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c -## explicit; go 1.16 +# github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 +## explicit; go 1.17 github.com/Azure/go-ansiterm github.com/Azure/go-ansiterm/winterm -# github.com/Microsoft/go-winio v0.6.2 -## explicit; go 1.21 +# github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 +## explicit; go 1.26.0 github.com/Microsoft/go-winio github.com/Microsoft/go-winio/internal/fs github.com/Microsoft/go-winio/internal/socket @@ -31,8 +31,8 @@ github.com/containerd/errdefs ## explicit; go 1.22 github.com/containerd/errdefs/pkg/errhttp github.com/containerd/errdefs/pkg/internal/cause -# github.com/containerd/log v0.1.0 -## explicit; go 1.20 +# github.com/containerd/log v0.2.0 +## explicit; go 1.23 github.com/containerd/log # github.com/containerd/platforms v1.0.0-rc.5 ## explicit; go 1.24 @@ -71,7 +71,7 @@ github.com/docker/distribution/registry/storage/cache/memory ## explicit; go 1.21 github.com/docker/docker-credential-helpers/client github.com/docker/docker-credential-helpers/credentials -# github.com/docker/go-connections v0.8.1 +# github.com/docker/go-connections v0.8.2 ## explicit; go 1.23 github.com/docker/go-connections/nat github.com/docker/go-connections/sockets @@ -145,8 +145,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2/utilities # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap -# github.com/klauspost/compress v1.19.2 -## explicit; go 1.24 +# github.com/klauspost/compress v1.20.1 +## explicit; go 1.25 github.com/klauspost/compress github.com/klauspost/compress/fse github.com/klauspost/compress/huff0 @@ -155,7 +155,7 @@ github.com/klauspost/compress/internal/le github.com/klauspost/compress/internal/snapref github.com/klauspost/compress/zstd github.com/klauspost/compress/zstd/internal/xxhash -# github.com/mattn/go-runewidth v0.0.29 +# github.com/mattn/go-runewidth v0.0.31 ## explicit; go 1.23 github.com/mattn/go-runewidth # github.com/moby/docker-image-spec v1.3.1 @@ -167,7 +167,7 @@ github.com/moby/go-archive github.com/moby/go-archive/compression github.com/moby/go-archive/internal/archiveoptions github.com/moby/go-archive/tarheader -# github.com/moby/moby/api v1.56.0 +# github.com/moby/moby/api v1.56.1 ## explicit; go 1.24 github.com/moby/moby/api/pkg/authconfig github.com/moby/moby/api/pkg/stdcopy @@ -189,7 +189,7 @@ github.com/moby/moby/api/types/storage github.com/moby/moby/api/types/swarm github.com/moby/moby/api/types/system github.com/moby/moby/api/types/volume -# github.com/moby/moby/client v0.6.0 +# github.com/moby/moby/client v0.6.2 ## explicit; go 1.24 github.com/moby/moby/client github.com/moby/moby/client/internal @@ -283,6 +283,7 @@ github.com/santhosh-tekuri/jsonschema/v6/kind # github.com/sirupsen/logrus v1.10.2 ## explicit; go 1.23 github.com/sirupsen/logrus +github.com/sirupsen/logrus/hooks/slog # github.com/spf13/cobra v1.10.2 ## explicit; go 1.15 github.com/spf13/cobra @@ -396,7 +397,7 @@ golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.59.0 +# golang.org/x/net v0.60.0 ## explicit; go 1.26.0 golang.org/x/net/http/httpguts golang.org/x/net/http2