[chore]: Bump github.com/gin-contrib/gzip from 1.1.0 to 1.2.2 (#3693)

Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.1.0 to 1.2.2.
- [Release notes](https://github.com/gin-contrib/gzip/releases)
- [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml)
- [Commits](https://github.com/gin-contrib/gzip/compare/v1.1.0...v1.2.2)

---
updated-dependencies:
- dependency-name: github.com/gin-contrib/gzip
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
dependabot[bot] 2025-01-27 11:06:46 +00:00 committed by GitHub
parent 2a46681147
commit 5c96702cb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
80 changed files with 5055 additions and 114881 deletions

17
go.mod
View file

@ -48,7 +48,7 @@ require (
github.com/buckket/go-blurhash v1.1.0 github.com/buckket/go-blurhash v1.1.0
github.com/coreos/go-oidc/v3 v3.12.0 github.com/coreos/go-oidc/v3 v3.12.0
github.com/gin-contrib/cors v1.7.3 github.com/gin-contrib/cors v1.7.3
github.com/gin-contrib/gzip v1.1.0 github.com/gin-contrib/gzip v1.2.2
github.com/gin-contrib/sessions v1.0.2 github.com/gin-contrib/sessions v1.0.2
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/go-playground/form/v4 v4.2.1 github.com/go-playground/form/v4 v4.2.1
@ -114,13 +114,12 @@ require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.12.6 // indirect github.com/bytedance/sonic v1.12.7 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/bytedance/sonic/loader v0.2.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cilium/ebpf v0.9.1 // indirect github.com/cilium/ebpf v0.9.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/containerd/cgroups/v3 v3.0.1 // indirect github.com/containerd/cgroups/v3 v3.0.1 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@ -133,8 +132,8 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-errors/errors v1.1.1 // indirect github.com/go-errors/errors v1.1.1 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect github.com/go-ini/ini v1.67.0 // indirect
@ -154,7 +153,7 @@ require (
github.com/go-openapi/validate v0.24.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/go-playground/validator/v10 v10.24.0 // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/goccy/go-json v0.10.4 // indirect github.com/goccy/go-json v0.10.4 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/godbus/dbus/v5 v5.0.4 // indirect
@ -230,7 +229,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.12.0 // indirect golang.org/x/arch v0.13.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.22.0 // indirect golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.10.0 // indirect
@ -239,7 +238,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.66.1 // indirect google.golang.org/grpc v1.66.1 // indirect
google.golang.org/protobuf v1.36.1 // indirect google.golang.org/protobuf v1.36.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect

35
go.sum generated
View file

@ -103,11 +103,11 @@ 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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do= github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8= github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -121,7 +121,6 @@ github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnx
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
@ -175,18 +174,18 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg= github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU= github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU=
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns=
github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4=
github.com/gin-contrib/gzip v1.1.0 h1:kVw7Nr9M+Z6Ch4qo7aGMbiqxDeyQFru+07MgAcUF62M= github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI=
github.com/gin-contrib/gzip v1.1.0/go.mod h1:iHJXCup4CWiKyPUEl+GwkHjchl+YyYuMKbOCiXujPIA= github.com/gin-contrib/gzip v1.2.2/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s=
github.com/gin-contrib/sessions v1.0.2 h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA= github.com/gin-contrib/sessions v1.0.2 h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA=
github.com/gin-contrib/sessions v1.0.2/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs= github.com/gin-contrib/sessions v1.0.2/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@ -238,8 +237,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
@ -517,6 +516,7 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -526,6 +526,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
@ -661,8 +662,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -959,8 +960,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

5
vendor/github.com/bytedance/sonic/.codespellrc generated vendored Normal file
View file

@ -0,0 +1,5 @@
[codespell]
# ignore test files, go project names, binary files via `skip` and special var/regex via `ignore-words`
skip = fuzz,*_test.tmpl,testdata,*_test.go,go.mod,go.sum,*.gz
ignore-words = .github/workflows/.ignore_words
check-filenames = true

View file

@ -211,7 +211,7 @@ ret, err := Encode(v, EscapeHTML) // ret == `{"\u0026\u0026":{"X":"\u003c\u003e"
### Compact Format ### Compact Format
Sonic encodes primitive objects (struct/map...) as compact-format JSON by default, except marshaling `json.RawMessage` or `json.Marshaler`: sonic ensures validating their output JSON but **DONOT** compacting them for performance concerns. We provide the option `encoder.CompactMarshaler` to add compacting process. Sonic encodes primitive objects (struct/map...) as compact-format JSON by default, except marshaling `json.RawMessage` or `json.Marshaler`: sonic ensures validating their output JSON but **DO NOT** compacting them for performance concerns. We provide the option `encoder.CompactMarshaler` to add compacting process.
### Print Error ### Print Error
@ -480,9 +480,9 @@ But `ast.Visitor` is not a very handy API. You might need to write a lot of code
### Buffer Size ### Buffer Size
Sonic use memory pool in many places like `encoder.Encode`, `ast.Node.MarshalJSON` to improve performace, which may produce more memory usage (in-use) when server's load is high. See [issue 614](https://github.com/bytedance/sonic/issues/614). Therefore, we introduce some options to let user control the behavior of memory pool. See [option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables) package. Sonic use memory pool in many places like `encoder.Encode`, `ast.Node.MarshalJSON` to improve performance, which may produce more memory usage (in-use) when server's load is high. See [issue 614](https://github.com/bytedance/sonic/issues/614). Therefore, we introduce some options to let user control the behavior of memory pool. See [option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables) package.
### Faster JSON skip ### Faster JSON Skip
For security, sonic use [FSM](native/skip_one.c) algorithm to validate JSON when decoding raw JSON or encoding `json.Marshaler`, which is much slower (1~10x) than [SIMD-searching-pair](native/skip_one_fast.c) algorithm. If user has many redundant JSON value and DO NOT NEED to strictly validate JSON correctness, you can enable below options: For security, sonic use [FSM](native/skip_one.c) algorithm to validate JSON when decoding raw JSON or encoding `json.Marshaler`, which is much slower (1~10x) than [SIMD-searching-pair](native/skip_one_fast.c) algorithm. If user has many redundant JSON value and DO NOT NEED to strictly validate JSON correctness, you can enable below options:
@ -490,6 +490,11 @@ For security, sonic use [FSM](native/skip_one.c) algorithm to validate JSON whe
- `Config.NoValidateJSONMarshaler`: avoid validating JSON when encoding `json.Marshaler` - `Config.NoValidateJSONMarshaler`: avoid validating JSON when encoding `json.Marshaler`
- `SearchOption.ValidateJSON`: indicates if validate located JSON value when `Get` - `SearchOption.ValidateJSON`: indicates if validate located JSON value when `Get`
## JSON-Path Support (GJSON)
[tidwall/gjson](https://github.com/tidwall/gjson) has provided a comprehensive and popular JSON-Path API, and
a lot of older codes heavily relies on it. Therefore, we provides a wrapper library, which combines gjson's API with sonic's SIMD algorithm to boost up the performance. See [cloudwego/gjson](https://github.com/cloudwego/gjson).
## Community ## Community
Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem. Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem.

View file

@ -77,7 +77,7 @@ type Config struct {
// CopyString indicates decoder to decode string values by copying instead of referring. // CopyString indicates decoder to decode string values by copying instead of referring.
CopyString bool CopyString bool
// ValidateString indicates decoder and encoder to valid string values: decoder will return errors // ValidateString indicates decoder and encoder to validate string values: decoder will return errors
// when unescaped control chars(\u0000-\u001f) in the string value of JSON. // when unescaped control chars(\u0000-\u001f) in the string value of JSON.
ValidateString bool ValidateString bool
@ -120,7 +120,7 @@ type Config struct {
// API is a binding of specific config. // API is a binding of specific config.
// This interface is inspired by github.com/json-iterator/go, // This interface is inspired by github.com/json-iterator/go,
// and has same behaviors under equavilent config. // and has same behaviors under equivalent config.
type API interface { type API interface {
// MarshalToString returns the JSON encoding string of v // MarshalToString returns the JSON encoding string of v
MarshalToString(v interface{}) (string, error) MarshalToString(v interface{}) (string, error)

View file

@ -34,7 +34,7 @@ func quote(buf *[]byte, val string) {
quoteString(buf, val) quoteString(buf, val)
} }
// unquote unescapes a internal JSON string (it doesn't count quotas at the begining and end) // unquote unescapes an internal JSON string (it doesn't count quotas at the beginning and end)
func unquote(src string) (string, types.ParsingError) { func unquote(src string) (string, types.ParsingError) {
sp := rt.IndexChar(src, -1) sp := rt.IndexChar(src, -1)
out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2)) out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2))

View file

@ -27,7 +27,7 @@
"github.com/bytedance/sonic/internal/utils" "github.com/bytedance/sonic/internal/utils"
) )
// Hack: this is used for both checking space and cause firendly compile errors in 32-bit arch. // Hack: this is used for both checking space and cause friendly compile errors in 32-bit arch.
const _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n') const _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
var bytesNull = []byte("null") var bytesNull = []byte("null")

View file

@ -173,7 +173,7 @@ func (s Sequence) String() string {
// ForEach scans one V_OBJECT node's children from JSON head to tail, // ForEach scans one V_OBJECT node's children from JSON head to tail,
// and pass the Sequence and Node of corresponding JSON value. // and pass the Sequence and Node of corresponding JSON value.
// //
// Especailly, if the node is not V_ARRAY or V_OBJECT, // Especially, if the node is not V_ARRAY or V_OBJECT,
// the node itself will be returned and Sequence.Index == -1. // the node itself will be returned and Sequence.Index == -1.
// //
// NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index // NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index

View file

@ -140,7 +140,7 @@ func (self *Node) Check() error {
// isRaw returns true if node's underlying value is raw json // isRaw returns true if node's underlying value is raw json
// //
// Deprecated: not concurent safe // Deprecated: not concurrent safe
func (self Node) IsRaw() bool { func (self Node) IsRaw() bool {
return self.t & _V_RAW != 0 return self.t & _V_RAW != 0
} }
@ -440,7 +440,7 @@ func (self *Node) String() (string, error) {
} }
} }
// StrictString returns string value (unescaped), includeing V_STRING, V_ANY of string. // StrictString returns string value (unescaped), including V_STRING, V_ANY of string.
// In other cases, it will return empty string. // In other cases, it will return empty string.
func (self *Node) StrictString() (string, error) { func (self *Node) StrictString() (string, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
@ -509,7 +509,7 @@ func (self *Node) Float64() (float64, error) {
} }
} }
// Float64 exports underlying float64 value, includeing V_NUMBER, V_ANY // Float64 exports underlying float64 value, including V_NUMBER, V_ANY
func (self *Node) StrictFloat64() (float64, error) { func (self *Node) StrictFloat64() (float64, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
return 0.0, err return 0.0, err
@ -527,7 +527,7 @@ func (self *Node) StrictFloat64() (float64, error) {
} }
} }
/** Sequencial Value Methods **/ /** Sequential Value Methods **/
// Len returns children count of a array|object|string node // Len returns children count of a array|object|string node
// WARN: For partially loaded node, it also works but only counts the parsed children // WARN: For partially loaded node, it also works but only counts the parsed children
@ -611,7 +611,7 @@ func (self *Node) Unset(key string) (bool, error) {
if err := self.should(types.V_OBJECT); err != nil { if err := self.should(types.V_OBJECT); err != nil {
return false, err return false, err
} }
// NOTICE: must get acurate length before deduct // NOTICE: must get accurate length before deduct
if err := self.skipAllKey(); err != nil { if err := self.skipAllKey(); err != nil {
return false, err return false, err
} }
@ -657,7 +657,7 @@ func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) {
return self.SetByIndex(index, NewAny(val)) return self.SetByIndex(index, NewAny(val))
} }
// UnsetByIndex REOMVE (softly) the node of given index. // UnsetByIndex REMOVE (softly) the node of given index.
// //
// WARN: this will change address of elements, which is a dangerous action. // WARN: this will change address of elements, which is a dangerous action.
// Use Unset() for object or Pop() for array instead. // Use Unset() for object or Pop() for array instead.
@ -957,7 +957,7 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) {
return self.toGenericObjectUseNumber() return self.toGenericObjectUseNumber()
} }
// MapUseNode scans both parsed and non-parsed chidren nodes, // MapUseNode scans both parsed and non-parsed children nodes,
// and map them by their keys // and map them by their keys
func (self *Node) MapUseNode() (map[string]Node, error) { func (self *Node) MapUseNode() (map[string]Node, error) {
if self.isAny() { if self.isAny() {
@ -1102,7 +1102,7 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) {
return self.toGenericArrayUseNumber() return self.toGenericArrayUseNumber()
} }
// ArrayUseNode copys both parsed and non-parsed chidren nodes, // ArrayUseNode copies both parsed and non-parsed children nodes,
// and indexes them by original order // and indexes them by original order
func (self *Node) ArrayUseNode() ([]Node, error) { func (self *Node) ArrayUseNode() ([]Node, error) {
if self.isAny() { if self.isAny() {
@ -1147,9 +1147,9 @@ func (self *Node) unsafeArray() (*linkedNodes, error) {
return (*linkedNodes)(self.p), nil return (*linkedNodes)(self.p), nil
} }
// Interface loads all children under all pathes from this node, // Interface loads all children under all paths from this node,
// and converts itself as generic type. // and converts itself as generic type.
// WARN: all numberic nodes are casted to float64 // WARN: all numeric nodes are casted to float64
func (self *Node) Interface() (interface{}, error) { func (self *Node) Interface() (interface{}, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
return nil, err return nil, err
@ -1193,7 +1193,7 @@ func (self *Node) packAny() interface{} {
} }
// InterfaceUseNumber works same with Interface() // InterfaceUseNumber works same with Interface()
// except numberic nodes are casted to json.Number // except numeric nodes are casted to json.Number
func (self *Node) InterfaceUseNumber() (interface{}, error) { func (self *Node) InterfaceUseNumber() (interface{}, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
return nil, err return nil, err

View file

@ -192,5 +192,5 @@ func (s SyntaxError) Error() string {
return (*json.SyntaxError)(unsafe.Pointer(&s)).Error() return (*json.SyntaxError)(unsafe.Pointer(&s)).Error()
} }
// MismatchTypeError represents dismatching between json and object // MismatchTypeError represents mismatching between json and object
type MismatchTypeError json.UnmarshalTypeError type MismatchTypeError json.UnmarshalTypeError

View file

@ -30,7 +30,7 @@
// SyntaxError represents json syntax error // SyntaxError represents json syntax error
type SyntaxError = api.SyntaxError type SyntaxError = api.SyntaxError
// MismatchTypeError represents dismatching between json and object // MismatchTypeError represents mismatching between json and object
type MismatchTypeError = api.MismatchTypeError type MismatchTypeError = api.MismatchTypeError
// Options for decode. // Options for decode.

View file

@ -1 +1,3 @@
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=

View file

@ -30,7 +30,7 @@
func init() { func init() {
// whe in aarch64. we enable all optimize // when in aarch64, we enable all optimization
envs.EnableOptDec() envs.EnableOptDec()
envs.EnableFastMap() envs.EnableFastMap()
} }

View file

@ -67,7 +67,7 @@
*/ */
const ( const (
_FP_args = 72 // 72 bytes to pass and spill register arguements _FP_args = 72 // 72 bytes to pass and spill register arguments
_FP_fargs = 80 // 80 bytes for passing arguments to other Go functions _FP_fargs = 80 // 80 bytes for passing arguments to other Go functions
_FP_saves = 48 // 48 bytes for saving the registers before CALL instructions _FP_saves = 48 // 48 bytes for saving the registers before CALL instructions
_FP_locals = 144 // 144 bytes for local variables _FP_locals = 144 // 144 bytes for local variables
@ -203,9 +203,9 @@
var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112) var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112)
var ( var (
_VAR_et = jit.Ptr(_SP, _FP_fargs + _FP_saves + 120) // save dismatched type _VAR_et = jit.Ptr(_SP, _FP_fargs + _FP_saves + 120) // save mismatched type
_VAR_pc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 128) // save skip return pc _VAR_pc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 128) // save skip return pc
_VAR_ic = jit.Ptr(_SP, _FP_fargs + _FP_saves + 136) // save dismatched position _VAR_ic = jit.Ptr(_SP, _FP_fargs + _FP_saves + 136) // save mismatched position
) )
type _Assembler struct { type _Assembler struct {
@ -1361,7 +1361,7 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) {
self.Emit("MOVQ", _R9, _VAR_pc) self.Emit("MOVQ", _R9, _VAR_pc)
self.Sjmp("JMP" , _LB_skip_one) self.Sjmp("JMP" , _LB_skip_one)
/* assgin string */ /* assign string */
self.Link("_num_next_{n}") self.Link("_num_next_{n}")
self.slice_from_r(_AX, 0) self.slice_from_r(_AX, 0)
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv) self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)

View file

@ -736,7 +736,7 @@ func (self *_Compiler) compilePtr(p *_Program, sp int, et reflect.Type) {
self.tab[et] = true self.tab[et] = true
/* not inline the pointer type /* not inline the pointer type
* recursing the defined pointer type's elem will casue issue379. * recursing the defined pointer type's elem will cause issue379.
*/ */
self.compileOps(p, sp, et) self.compileOps(p, sp, et)
} }

View file

@ -63,8 +63,8 @@ type _Stack struct {
vp unsafe.Pointer, vp unsafe.Pointer,
sb *_Stack, sb *_Stack,
fv uint64, fv uint64,
sv string, // DO NOT pass value to this arguement, since it is only used for local _VAR_sv sv string, // DO NOT pass value to this argument, since it is only used for local _VAR_sv
vk unsafe.Pointer, // DO NOT pass value to this arguement, since it is only used for local _VAR_vk vk unsafe.Pointer, // DO NOT pass value to this argument, since it is only used for local _VAR_vk
) (int, error) ) (int, error)
var _KeepAlive struct { var _KeepAlive struct {

View file

@ -177,7 +177,7 @@ func (c *compiler) compilePtr(vt reflect.Type) decFunc {
c.enter(vt) c.enter(vt)
defer c.exit(vt) defer c.exit(vt)
// specail logic for Named Ptr, issue 379 // special logic for Named Ptr, issue 379
if reflect.PtrTo(vt.Elem()) != vt { if reflect.PtrTo(vt.Elem()) != vt {
c.namedPtr = true c.namedPtr = true
return &ptrDecoder{ return &ptrDecoder{
@ -432,7 +432,7 @@ func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFun
/* check for `encoding.TextMarshaler` with pointer receiver */ /* check for `encoding.TextMarshaler` with pointer receiver */
if pt.Implements(encodingTextUnmarshalerType) { if pt.Implements(encodingTextUnmarshalerType) {
/* TextUnmarshal not support ,strig tag */ /* TextUnmarshal not support, string tag */
if strOpt { if strOpt {
panicForInvalidStrType(vt) panicForInvalidStrType(vt)
} }

View file

@ -11,7 +11,7 @@
func SkipNumberFast(json string, start int) (int, bool) { func SkipNumberFast(json string, start int) (int, bool) {
// find the number ending, we pasred in native, it alway valid // find the number ending, we parsed in native, it always valid
pos := start pos := start
for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' { for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' {
if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' {
@ -40,7 +40,7 @@ func ValidNumberFast(raw string) bool {
return false return false
} }
// check trainling chars // check trailing chars
for ret < len(raw) { for ret < len(raw) {
return false return false
} }
@ -49,7 +49,7 @@ func ValidNumberFast(raw string) bool {
} }
func SkipOneFast2(json string, pos *int) (int, error) { func SkipOneFast2(json string, pos *int) (int, error) {
// find the number ending, we pasred in sonic-cpp, it alway valid // find the number ending, we parsed in sonic-cpp, it always valid
start := native.SkipOneFast(&json, pos) start := native.SkipOneFast(&json, pos)
if start < 0 { if start < 0 {
return -1, error_syntax(*pos, json, types.ParsingError(-start).Error()) return -1, error_syntax(*pos, json, types.ParsingError(-start).Error())
@ -58,7 +58,7 @@ func SkipOneFast2(json string, pos *int) (int, error) {
} }
func SkipOneFast(json string, pos int) (string, error) { func SkipOneFast(json string, pos int) (string, error) {
// find the number ending, we pasred in sonic-cpp, it alway valid // find the number ending, we parsed in sonic-cpp, it always valid
start := native.SkipOneFast(&json, &pos) start := native.SkipOneFast(&json, &pos)
if start < 0 { if start < 0 {
// TODO: details error code // TODO: details error code

View file

@ -61,13 +61,13 @@ type node struct {
val uint64 val uint64
} }
// should consitent with native/parser.c // should consistent with native/parser.c
type _nospaceBlock struct { type _nospaceBlock struct {
_ [8]byte _ [8]byte
_ [8]byte _ [8]byte
} }
// should consitent with native/parser.c // should consistent with native/parser.c
type nodeBuf struct { type nodeBuf struct {
ncur uintptr ncur uintptr
parent int64 parent int64
@ -84,7 +84,7 @@ func (self *nodeBuf) init(nodes []node) {
self.parent = -1 self.parent = -1
} }
// should consitent with native/parser.c // should consistent with native/parser.c
type Parser struct { type Parser struct {
Json string Json string
padded []byte padded []byte

View file

@ -372,7 +372,7 @@ func (val Node) ParseF64(ctx *Context) (float64, bool) {
} }
func (val Node) ParseString(ctx *Context) (string, bool) { func (val Node) ParseString(ctx *Context) (string, bool) {
// shoud not use AsStrRef // should not use AsStrRef
s, ok := val.AsStr(ctx) s, ok := val.AsStr(ctx)
if !ok { if !ok {
return "", false return "", false
@ -391,7 +391,7 @@ func (val Node) ParseString(ctx *Context) (string, bool) {
func (val Node) ParseNumber(ctx *Context) (json.Number, bool) { func (val Node) ParseNumber(ctx *Context) (json.Number, bool) {
// shoud not use AsStrRef // should not use AsStrRef
s, ok := val.AsStr(ctx) s, ok := val.AsStr(ctx)
if !ok { if !ok {
return json.Number(""), false return json.Number(""), false

View file

@ -46,7 +46,7 @@ func radixQsort(kvs []_MapPair, d, maxDepth int) {
} }
// kvs[0:lt] < v = kvs[lt:gt] < kvs[gt:len(kvs)] // kvs[0:lt] < v = kvs[lt:gt] < kvs[gt:len(kvs)]
// Native implemention: // Native implementation:
// radixQsort(kvs[:lt], d, maxDepth) // radixQsort(kvs[:lt], d, maxDepth)
// if p > -1 { // if p > -1 {
// radixQsort(kvs[lt:gt], d+1, maxDepth) // radixQsort(kvs[lt:gt], d+1, maxDepth)

View file

@ -673,7 +673,7 @@ func (self *Assembler) encode_string(doubleQuote bool) {
self.Sjmp("JMP", _LB_panic) self.Sjmp("JMP", _LB_panic)
self.Link("_str_next_{n}") self.Link("_str_next_{n}")
/* openning quote, check for double quote */ /* opening quote, check for double quote */
if !doubleQuote { if !doubleQuote {
self.check_size_r(_AX, 2) // SIZE $2 self.check_size_r(_AX, 2) // SIZE $2
self.add_char('"') // CHAR $'"' self.add_char('"') // CHAR $'"'

View file

@ -84,7 +84,7 @@ func NewSmallFieldMap (hint int) *SmallFieldMap {
func (self *SmallFieldMap) Set(fields []resolver.FieldMeta) { func (self *SmallFieldMap) Set(fields []resolver.FieldMeta) {
if len(fields) > 8 { if len(fields) > 8 {
panic("small field map shoud use in small struct") panic("small field map should use in small struct")
} }
for i, f := range fields { for i, f := range fields {
@ -254,7 +254,7 @@ type keysInfo struct {
func (self *NormalFieldMap) Set(fields []resolver.FieldMeta) { func (self *NormalFieldMap) Set(fields []resolver.FieldMeta) {
if len(fields) <=8 || len(fields) > 128 { if len(fields) <=8 || len(fields) > 128 {
panic("normal field map shoud use in small struct") panic("normal field map should use in small struct")
} }
// allocate the flat map in []byte // allocate the flat map in []byte
@ -278,7 +278,7 @@ func (self *NormalFieldMap) Set(fields []resolver.FieldMeta) {
} }
// add a padding size at last to make it firendly for SIMD. // add a padding size at last to make it friendly for SIMD.
self.keys = make([]byte, _HdrSize + 2 * kvLen, _HdrSize + 2 * kvLen + _PaddingSize) self.keys = make([]byte, _HdrSize + 2 * kvLen, _HdrSize + 2 * kvLen + _PaddingSize)
self.lowOffset = _HdrSize + kvLen self.lowOffset = _HdrSize + kvLen

View file

@ -153,7 +153,7 @@ func MakeSlice(oldPtr unsafe.Pointer, et *GoType, newLen int) *GoSlice {
new := GrowSlice(et, *old, newLen) new := GrowSlice(et, *old, newLen)
// we sould clear the memory from [oldLen:newLen] // we should clear the memory from [oldLen:newLen]
if et.PtrData == 0 { if et.PtrData == 0 {
oldlenmem := uintptr(old.Len) * et.Size oldlenmem := uintptr(old.Len) * et.Size
newlenmem := uintptr(newLen) * et.Size newlenmem := uintptr(newLen) * et.Size

View file

@ -329,7 +329,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs) funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab mod.funcnametab = funcnametab
// mmap() text and funcdata segements // mmap() text and funcdata segments
p := os.Getpagesize() p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p))) size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size) addr := mmap(size)
@ -389,7 +389,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
pclnOffset: getOffsetOf(moduledata{}, "pclntable"), pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
} }
// sepecial case: gcdata and gcbss must by non-empty // special case: gcdata and gcbss must by non-empty
mod.gcdata = uintptr(unsafe.Pointer(&emptyByte)) mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
mod.gcbss = uintptr(unsafe.Pointer(&emptyByte)) mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -330,7 +330,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs) funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab mod.funcnametab = funcnametab
// mmap() text and funcdata segements // mmap() text and funcdata segments
p := os.Getpagesize() p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p))) size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size) addr := mmap(size)
@ -390,7 +390,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
pclnOffset: getOffsetOf(moduledata{}, "pclntable"), pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
} }
// sepecial case: gcdata and gcbss must by non-empty // special case: gcdata and gcbss must by non-empty
mod.gcdata = uintptr(unsafe.Pointer(&emptyByte)) mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
mod.gcbss = uintptr(unsafe.Pointer(&emptyByte)) mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -222,7 +222,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs) funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab mod.funcnametab = funcnametab
// mmap() text and funcdata segements // mmap() text and funcdata segments
p := os.Getpagesize() p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p))) size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size) addr := mmap(size)
@ -283,7 +283,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
pclnOffset: getOffsetOf(moduledata{}, "pclntable"), pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
} }
// sepecial case: gcdata and gcbss must by non-empty // special case: gcdata and gcbss must by non-empty
mod.gcdata = uintptr(unsafe.Pointer(&emptyByte)) mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
mod.gcbss = uintptr(unsafe.Pointer(&emptyByte)) mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -17,11 +17,35 @@
package abi package abi
import ( import (
`fmt` "fmt"
`reflect` "reflect"
`unsafe` "unsafe"
. `github.com/cloudwego/iasm/x86_64` x64 "github.com/bytedance/sonic/loader/internal/iasm/x86_64"
)
type (
Register = x64.Register
Register64 = x64.Register64
XMMRegister = x64.XMMRegister
Program = x64.Program
MemoryOperand = x64.MemoryOperand
Label = x64.Label
)
var (
Ptr = x64.Ptr
DefaultArch = x64.DefaultArch
CreateLabel = x64.CreateLabel
)
const (
RAX = x64.RAX
RSP = x64.RSP
RBP = x64.RBP
R12 = x64.R12
R14 = x64.R14
R15 = x64.R15
) )
const ( const (
@ -30,23 +54,23 @@
) )
var iregOrderC = []Register{ var iregOrderC = []Register{
RDI, x64.RDI,
RSI, x64.RSI,
RDX, x64.RDX,
RCX, x64.RCX,
R8, x64.R8,
R9, x64.R9,
} }
var xregOrderC = []Register{ var xregOrderC = []Register{
XMM0, x64.XMM0,
XMM1, x64.XMM1,
XMM2, x64.XMM2,
XMM3, x64.XMM3,
XMM4, x64.XMM4,
XMM5, x64.XMM5,
XMM6, x64.XMM6,
XMM7, x64.XMM7,
} }
var ( var (
@ -55,21 +79,21 @@
) )
func (self *Frame) argv(i int) *MemoryOperand { func (self *Frame) argv(i int) *MemoryOperand {
return Ptr(RSP, int32(self.Prev() + self.desc.Args[i].Mem)) return Ptr(RSP, int32(self.Prev()+self.desc.Args[i].Mem))
} }
// spillv is used for growstack spill registers // spillv is used for growstack spill registers
func (self *Frame) spillv(i int) *MemoryOperand { func (self *Frame) spillv(i int) *MemoryOperand {
// remain one slot for caller return pc // remain one slot for caller return pc
return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem)) return Ptr(RSP, PtrSize+int32(self.desc.Args[i].Mem))
} }
func (self *Frame) retv(i int) *MemoryOperand { func (self *Frame) retv(i int) *MemoryOperand {
return Ptr(RSP, int32(self.Prev() + self.desc.Rets[i].Mem)) return Ptr(RSP, int32(self.Prev()+self.desc.Rets[i].Mem))
} }
func (self *Frame) resv(i int) *MemoryOperand { func (self *Frame) resv(i int) *MemoryOperand {
return Ptr(RSP, int32(self.Offs() - uint32((i+1) * PtrSize))) return Ptr(RSP, int32(self.Offs()-uint32((i+1)*PtrSize)))
} }
func (self *Frame) emitGrowStack(p *Program, entry *Label) { func (self *Frame) emitGrowStack(p *Program, entry *Label) {
@ -80,7 +104,7 @@ func (self *Frame) emitGrowStack(p *Program, entry *Label) {
p.MOVSD(v.Reg, self.spillv(i)) p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 { } else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i)) p.MOVSS(v.Reg, self.spillv(i))
}else { } else {
p.MOVQ(v.Reg, self.spillv(i)) p.MOVQ(v.Reg, self.spillv(i))
} }
} }
@ -96,7 +120,7 @@ func (self *Frame) emitGrowStack(p *Program, entry *Label) {
p.MOVSD(self.spillv(i), v.Reg) p.MOVSD(self.spillv(i), v.Reg)
} else if v.IsFloat == floatKind32 { } else if v.IsFloat == floatKind32 {
p.MOVSS(self.spillv(i), v.Reg) p.MOVSS(self.spillv(i), v.Reg)
}else { } else {
p.MOVQ(self.spillv(i), v.Reg) p.MOVQ(self.spillv(i), v.Reg)
} }
} }
@ -115,7 +139,7 @@ func (self *Frame) GrowStackTextSize() uint32 {
p.MOVSD(v.Reg, self.spillv(i)) p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 { } else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i)) p.MOVSS(v.Reg, self.spillv(i))
}else { } else {
p.MOVQ(v.Reg, self.spillv(i)) p.MOVQ(v.Reg, self.spillv(i))
} }
} }
@ -275,8 +299,3 @@ func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
return p.Assemble(0) return p.Assemble(0)
} }
func (self *Frame) emitDebug(p *Program) {
p.INT(3)
}

View file

@ -20,11 +20,9 @@
package abi package abi
import ( import (
`fmt` "fmt"
`reflect` "reflect"
`runtime` "runtime"
. `github.com/cloudwego/iasm/x86_64`
) )
func ReservedRegs(callc bool) []Register { func ReservedRegs(callc bool) []Register {
@ -33,33 +31,60 @@ func ReservedRegs(callc bool) []Register {
func salloc(p []Parameter, sp uint32, vt reflect.Type) (uint32, []Parameter) { func salloc(p []Parameter, sp uint32, vt reflect.Type) (uint32, []Parameter) {
switch vt.Kind() { switch vt.Kind() {
case reflect.Bool : return sp + 8, append(p, mkStack(reflect.TypeOf(false), sp)) case reflect.Bool:
case reflect.Int : return sp + 8, append(p, mkStack(intType, sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(false), sp))
case reflect.Int8 : return sp + 8, append(p, mkStack(reflect.TypeOf(int8(0)), sp)) case reflect.Int:
case reflect.Int16 : return sp + 8, append(p, mkStack(reflect.TypeOf(int16(0)), sp)) return sp + 8, append(p, mkStack(intType, sp))
case reflect.Int32 : return sp + 8, append(p, mkStack(reflect.TypeOf(int32(0)), sp)) case reflect.Int8:
case reflect.Int64 : return sp + 8, append(p, mkStack(reflect.TypeOf(int64(0)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(int8(0)), sp))
case reflect.Uint : return sp + 8, append(p, mkStack(reflect.TypeOf(uint(0)), sp)) case reflect.Int16:
case reflect.Uint8 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint8(0)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(int16(0)), sp))
case reflect.Uint16 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint16(0)), sp)) case reflect.Int32:
case reflect.Uint32 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint32(0)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(int32(0)), sp))
case reflect.Uint64 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint64(0)), sp)) case reflect.Int64:
case reflect.Uintptr : return sp + 8, append(p, mkStack(reflect.TypeOf(uintptr(0)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(int64(0)), sp))
case reflect.Float32 : return sp + 8, append(p, mkStack(reflect.TypeOf(float32(0)), sp)) case reflect.Uint:
case reflect.Float64 : return sp + 8, append(p, mkStack(reflect.TypeOf(float64(0)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(uint(0)), sp))
case reflect.Complex64 : panic("abi: go116: not implemented: complex64") case reflect.Uint8:
case reflect.Complex128 : panic("abi: go116: not implemented: complex128") return sp + 8, append(p, mkStack(reflect.TypeOf(uint8(0)), sp))
case reflect.Array : panic("abi: go116: not implemented: arrays") case reflect.Uint16:
case reflect.Chan : return sp + 8, append(p, mkStack(reflect.TypeOf((chan int)(nil)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(uint16(0)), sp))
case reflect.Func : return sp + 8, append(p, mkStack(reflect.TypeOf((func())(nil)), sp)) case reflect.Uint32:
case reflect.Map : return sp + 8, append(p, mkStack(reflect.TypeOf((map[int]int)(nil)), sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(uint32(0)), sp))
case reflect.Ptr : return sp + 8, append(p, mkStack(reflect.TypeOf((*int)(nil)), sp)) case reflect.Uint64:
case reflect.UnsafePointer : return sp + 8, append(p, mkStack(ptrType, sp)) return sp + 8, append(p, mkStack(reflect.TypeOf(uint64(0)), sp))
case reflect.Interface : return sp + 16, append(p, mkStack(ptrType, sp), mkStack(ptrType, sp + 8)) case reflect.Uintptr:
case reflect.Slice : return sp + 24, append(p, mkStack(ptrType, sp), mkStack(intType, sp + 8), mkStack(intType, sp + 16)) return sp + 8, append(p, mkStack(reflect.TypeOf(uintptr(0)), sp))
case reflect.String : return sp + 16, append(p, mkStack(ptrType, sp), mkStack(intType, sp + 8)) case reflect.Float32:
case reflect.Struct : panic("abi: go116: not implemented: structs") return sp + 8, append(p, mkStack(reflect.TypeOf(float32(0)), sp))
default : panic("abi: invalid value type") case reflect.Float64:
return sp + 8, append(p, mkStack(reflect.TypeOf(float64(0)), sp))
case reflect.Complex64:
panic("abi: go116: not implemented: complex64")
case reflect.Complex128:
panic("abi: go116: not implemented: complex128")
case reflect.Array:
panic("abi: go116: not implemented: arrays")
case reflect.Chan:
return sp + 8, append(p, mkStack(reflect.TypeOf((chan int)(nil)), sp))
case reflect.Func:
return sp + 8, append(p, mkStack(reflect.TypeOf((func())(nil)), sp))
case reflect.Map:
return sp + 8, append(p, mkStack(reflect.TypeOf((map[int]int)(nil)), sp))
case reflect.Ptr:
return sp + 8, append(p, mkStack(reflect.TypeOf((*int)(nil)), sp))
case reflect.UnsafePointer:
return sp + 8, append(p, mkStack(ptrType, sp))
case reflect.Interface:
return sp + 16, append(p, mkStack(ptrType, sp), mkStack(ptrType, sp+8))
case reflect.Slice:
return sp + 24, append(p, mkStack(ptrType, sp), mkStack(intType, sp+8), mkStack(intType, sp+16))
case reflect.String:
return sp + 16, append(p, mkStack(ptrType, sp), mkStack(intType, sp+8))
case reflect.Struct:
panic("abi: go116: not implemented: structs")
default:
panic("abi: invalid value type")
} }
} }
@ -103,13 +128,13 @@ func (self *Frame) emitExchangeArgs(p *Program) {
for i := 0; i < len(self.desc.Args); i++ { for i := 0; i < len(self.desc.Args); i++ {
arg := self.desc.Args[i] arg := self.desc.Args[i]
if arg.IsFloat == floatKind64 { if arg.IsFloat == floatKind64 {
p.MOVSD(self.argv(i), xregOrderC[xregArgs - xc]) p.MOVSD(self.argv(i), xregOrderC[xregArgs-xc])
xc -= 1 xc -= 1
} else if arg.IsFloat == floatKind32 { } else if arg.IsFloat == floatKind32 {
p.MOVSS(self.argv(i), xregOrderC[xregArgs - xc]) p.MOVSS(self.argv(i), xregOrderC[xregArgs-xc])
xc -= 1 xc -= 1
} else { } else {
p.MOVQ(self.argv(i), iregOrderC[iregArgs - ic]) p.MOVQ(self.argv(i), iregOrderC[iregArgs-ic])
ic -= 1 ic -= 1
} }
} }
@ -118,14 +143,18 @@ func (self *Frame) emitExchangeArgs(p *Program) {
func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) { func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) {
// get the current goroutine // get the current goroutine
switch runtime.GOOS { switch runtime.GOOS {
case "linux" : p.MOVQ(Abs(-8), R14).FS() case "linux":
case "darwin" : p.MOVQ(Abs(0x30), R14).GS() p.MOVQ(Abs(-8), R14).FS()
case "windows": break // windows always stores G pointer at R14 case "darwin":
default : panic("unsupported operating system") p.MOVQ(Abs(0x30), R14).GS()
case "windows":
break // windows always stores G pointer at R14
default:
panic("unsupported operating system")
} }
// check the stack guard // check the stack guard
p.LEAQ(Ptr(RSP, -int32(self.Size() + uint32(maxStack))), RAX) p.LEAQ(Ptr(RSP, -int32(self.Size()+uint32(maxStack))), RAX)
p.CMPQ(Ptr(R14, _G_stackguard0), RAX) p.CMPQ(Ptr(R14, _G_stackguard0), RAX)
p.JBE(to) p.JBE(to)
} }
@ -135,10 +164,14 @@ func (self *Frame) StackCheckTextSize() uint32 {
// get the current goroutine // get the current goroutine
switch runtime.GOOS { switch runtime.GOOS {
case "linux" : p.MOVQ(Abs(-8), R14).FS() case "linux":
case "darwin" : p.MOVQ(Abs(0x30), R14).GS() p.MOVQ(Abs(-8), R14).FS()
case "windows": break // windows always stores G pointer at R14 case "darwin":
default : panic("unsupported operating system") p.MOVQ(Abs(0x30), R14).GS()
case "windows":
break // windows always stores G pointer at R14
default:
panic("unsupported operating system")
} }
// check the stack guard // check the stack guard
@ -156,7 +189,7 @@ func (self *Frame) emitExchangeRets(p *Program) {
panic("too many results, only support one result now") panic("too many results, only support one result now")
} }
// store result // store result
if len(self.desc.Rets) ==1 { if len(self.desc.Rets) == 1 {
if self.desc.Rets[0].IsFloat == floatKind64 { if self.desc.Rets[0].IsFloat == floatKind64 {
p.MOVSD(xregOrderC[0], self.retv(0)) p.MOVSD(xregOrderC[0], self.retv(0))
} else if self.desc.Rets[0].IsFloat == floatKind32 { } else if self.desc.Rets[0].IsFloat == floatKind32 {

View file

@ -26,10 +26,10 @@
package abi package abi
import ( import (
`fmt` "fmt"
`reflect` "reflect"
. `github.com/cloudwego/iasm/x86_64` x64 "github.com/bytedance/sonic/loader/internal/iasm/x86_64"
) )
/** Frame Structure of the Generated Function /** Frame Structure of the Generated Function
@ -59,43 +59,43 @@
RSP -------------------------------| lower addresses RSP -------------------------------| lower addresses
*/ */
const zeroRegGo = XMM15 const zeroRegGo = x64.XMM15
var iregOrderGo = [...]Register64 { var iregOrderGo = [...]Register64{
RAX,// RDI x64.RAX, // RDI
RBX,// RSI x64.RBX, // RSI
RCX,// RDX x64.RCX, // RDX
RDI,// RCX x64.RDI, // RCX
RSI,// R8 x64.RSI, // R8
R8, // R9 x64.R8, // R9
R9, x64.R9,
R10, x64.R10,
R11, x64.R11,
} }
var xregOrderGo = [...]XMMRegister { var xregOrderGo = [...]XMMRegister{
XMM0, x64.XMM0,
XMM1, x64.XMM1,
XMM2, x64.XMM2,
XMM3, x64.XMM3,
XMM4, x64.XMM4,
XMM5, x64.XMM5,
XMM6, x64.XMM6,
XMM7, x64.XMM7,
XMM8, x64.XMM8,
XMM9, x64.XMM9,
XMM10, x64.XMM10,
XMM11, x64.XMM11,
XMM12, x64.XMM12,
XMM13, x64.XMM13,
XMM14, x64.XMM14,
} }
func ReservedRegs(callc bool) []Register { func ReservedRegs(callc bool) []Register {
if callc { if callc {
return nil return nil
} }
return []Register { return []Register{
R14, // current goroutine R14, // current goroutine
R15, // GOT reference R15, // GOT reference
} }
@ -145,33 +145,60 @@ func (self *stackAlloc) alloc(p []Parameter, vt reflect.Type) []Parameter {
/* check for value type */ /* check for value type */
switch vk { switch vk {
case reflect.Bool : return self.valloc(p, reflect.TypeOf(false)) case reflect.Bool:
case reflect.Int : return self.valloc(p, intType) return self.valloc(p, reflect.TypeOf(false))
case reflect.Int8 : return self.valloc(p, reflect.TypeOf(int8(0))) case reflect.Int:
case reflect.Int16 : return self.valloc(p, reflect.TypeOf(int16(0))) return self.valloc(p, intType)
case reflect.Int32 : return self.valloc(p, reflect.TypeOf(uint32(0))) case reflect.Int8:
case reflect.Int64 : return self.valloc(p, reflect.TypeOf(int64(0))) return self.valloc(p, reflect.TypeOf(int8(0)))
case reflect.Uint : return self.valloc(p, reflect.TypeOf(uint(0))) case reflect.Int16:
case reflect.Uint8 : return self.valloc(p, reflect.TypeOf(uint8(0))) return self.valloc(p, reflect.TypeOf(int16(0)))
case reflect.Uint16 : return self.valloc(p, reflect.TypeOf(uint16(0))) case reflect.Int32:
case reflect.Uint32 : return self.valloc(p, reflect.TypeOf(uint32(0))) return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Uint64 : return self.valloc(p, reflect.TypeOf(uint64(0))) case reflect.Int64:
case reflect.Uintptr : return self.valloc(p, reflect.TypeOf(uintptr(0))) return self.valloc(p, reflect.TypeOf(int64(0)))
case reflect.Float32 : return self.valloc(p, reflect.TypeOf(float32(0))) case reflect.Uint:
case reflect.Float64 : return self.valloc(p, reflect.TypeOf(float64(0))) return self.valloc(p, reflect.TypeOf(uint(0)))
case reflect.Complex64 : panic("abi: go117: not implemented: complex64") case reflect.Uint8:
case reflect.Complex128 : panic("abi: go117: not implemented: complex128") return self.valloc(p, reflect.TypeOf(uint8(0)))
case reflect.Array : panic("abi: go117: not implemented: arrays") case reflect.Uint16:
case reflect.Chan : return self.valloc(p, reflect.TypeOf((chan int)(nil))) return self.valloc(p, reflect.TypeOf(uint16(0)))
case reflect.Func : return self.valloc(p, reflect.TypeOf((func())(nil))) case reflect.Uint32:
case reflect.Map : return self.valloc(p, reflect.TypeOf((map[int]int)(nil))) return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Ptr : return self.valloc(p, reflect.TypeOf((*int)(nil))) case reflect.Uint64:
case reflect.UnsafePointer : return self.valloc(p, ptrType) return self.valloc(p, reflect.TypeOf(uint64(0)))
case reflect.Interface : return self.valloc(p, ptrType, ptrType) case reflect.Uintptr:
case reflect.Slice : return self.valloc(p, ptrType, intType, intType) return self.valloc(p, reflect.TypeOf(uintptr(0)))
case reflect.String : return self.valloc(p, ptrType, intType) case reflect.Float32:
case reflect.Struct : panic("abi: go117: not implemented: structs") return self.valloc(p, reflect.TypeOf(float32(0)))
default : panic("abi: invalid value type") case reflect.Float64:
return self.valloc(p, reflect.TypeOf(float64(0)))
case reflect.Complex64:
panic("abi: go117: not implemented: complex64")
case reflect.Complex128:
panic("abi: go117: not implemented: complex128")
case reflect.Array:
panic("abi: go117: not implemented: arrays")
case reflect.Chan:
return self.valloc(p, reflect.TypeOf((chan int)(nil)))
case reflect.Func:
return self.valloc(p, reflect.TypeOf((func())(nil)))
case reflect.Map:
return self.valloc(p, reflect.TypeOf((map[int]int)(nil)))
case reflect.Ptr:
return self.valloc(p, reflect.TypeOf((*int)(nil)))
case reflect.UnsafePointer:
return self.valloc(p, ptrType)
case reflect.Interface:
return self.valloc(p, ptrType, ptrType)
case reflect.Slice:
return self.valloc(p, ptrType, intType, intType)
case reflect.String:
return self.valloc(p, ptrType, intType)
case reflect.Struct:
panic("abi: go117: not implemented: structs")
default:
panic("abi: invalid value type")
} }
} }
@ -239,19 +266,21 @@ func (self *Frame) emitExchangeArgs(p *Program) {
} }
switch len(iregArgs) { switch len(iregArgs) {
case 0, 1, 2, 3: { case 0, 1, 2, 3:
{
//Fast-Path: when arguments count are less than four, just exchange the registers //Fast-Path: when arguments count are less than four, just exchange the registers
for i := 0; i < len(iregArgs); i++ { for i := 0; i < len(iregArgs); i++ {
p.MOVQ(iregOrderGo[i], iregOrderC[i]) p.MOVQ(iregOrderGo[i], iregOrderC[i])
} }
} }
case 4, 5, 6: { case 4, 5, 6:
{
// need to spill 3th ~ regArgs registers before exchange // need to spill 3th ~ regArgs registers before exchange
for i := 3; i < len(iregArgs); i++ { for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i] arg := iregArgs[i]
// pointer args have already been spilled // pointer args have already been spilled
if !arg.IsPointer { if !arg.IsPointer {
p.MOVQ(iregOrderGo[i], Ptr(RSP, int32(self.Prev() + arg.Mem))) p.MOVQ(iregOrderGo[i], Ptr(RSP, int32(self.Prev()+arg.Mem)))
} }
} }
p.MOVQ(iregOrderGo[0], iregOrderC[0]) p.MOVQ(iregOrderGo[0], iregOrderC[0])
@ -259,7 +288,7 @@ func (self *Frame) emitExchangeArgs(p *Program) {
p.MOVQ(iregOrderGo[2], iregOrderC[2]) p.MOVQ(iregOrderGo[2], iregOrderC[2])
for i := 3; i < len(iregArgs); i++ { for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i] arg := iregArgs[i]
p.MOVQ(Ptr(RSP, int32(self.Prev() + arg.Mem)), iregOrderC[i]) p.MOVQ(Ptr(RSP, int32(self.Prev()+arg.Mem)), iregOrderC[i])
} }
} }
default: default:
@ -268,7 +297,7 @@ func (self *Frame) emitExchangeArgs(p *Program) {
} }
func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) { func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) {
p.LEAQ(Ptr(RSP, int32(-(self.Size() + uint32(maxStack)))), R12) p.LEAQ(Ptr(RSP, int32(-(self.Size()+uint32(maxStack)))), R12)
p.CMPQ(Ptr(R14, _G_stackguard0), R12) p.CMPQ(Ptr(R14, _G_stackguard0), R12)
p.JBE(to) p.JBE(to)
} }

View file

@ -0,0 +1,273 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
"fmt"
)
// Type is tyep expression type.
type Type int
const (
// CONST indicates that the expression is a constant.
CONST Type = iota
// TERM indicates that the expression is a Term reference.
TERM
// EXPR indicates that the expression is a unary or binary expression.
EXPR
)
var typeNames = map[Type]string{
EXPR: "Expr",
TERM: "Term",
CONST: "Const",
}
// String returns the string representation of a Type.
func (self Type) String() string {
if v, ok := typeNames[self]; ok {
return v
} else {
return fmt.Sprintf("expr.Type(%d)", self)
}
}
// Operator represents an operation to perform when Type is EXPR.
type Operator uint8
const (
// ADD performs "Add Expr.Left and Expr.Right".
ADD Operator = iota
// SUB performs "Subtract Expr.Left by Expr.Right".
SUB
// MUL performs "Multiply Expr.Left by Expr.Right".
MUL
// DIV performs "Divide Expr.Left by Expr.Right".
DIV
// MOD performs "Modulo Expr.Left by Expr.Right".
MOD
// AND performs "Bitwise AND Expr.Left and Expr.Right".
AND
// OR performs "Bitwise OR Expr.Left and Expr.Right".
OR
// XOR performs "Bitwise XOR Expr.Left and Expr.Right".
XOR
// SHL performs "Bitwise Shift Expr.Left to the Left by Expr.Right Bits".
SHL
// SHR performs "Bitwise Shift Expr.Left to the Right by Expr.Right Bits".
SHR
// POW performs "Raise Expr.Left to the power of Expr.Right"
POW
// NOT performs "Bitwise Invert Expr.Left".
NOT
// NEG performs "Negate Expr.Left".
NEG
)
var operatorNames = map[Operator]string{
ADD: "Add",
SUB: "Subtract",
MUL: "Multiply",
DIV: "Divide",
MOD: "Modulo",
AND: "And",
OR: "Or",
XOR: "ExclusiveOr",
SHL: "ShiftLeft",
SHR: "ShiftRight",
POW: "Power",
NOT: "Invert",
NEG: "Negate",
}
// String returns the string representation of a Type.
func (self Operator) String() string {
if v, ok := operatorNames[self]; ok {
return v
} else {
return fmt.Sprintf("expr.Operator(%d)", self)
}
}
// Expr represents an expression node.
type Expr struct {
Type Type
Term Term
Op Operator
Left *Expr
Right *Expr
Const int64
}
// Ref creates an expression from a Term.
func Ref(t Term) (p *Expr) {
p = newExpression()
p.Term = t
p.Type = TERM
return
}
// Int creates an expression from an integer.
func Int(v int64) (p *Expr) {
p = newExpression()
p.Type = CONST
p.Const = v
return
}
func (self *Expr) clear() {
if self.Term != nil {
self.Term.Free()
}
if self.Left != nil {
self.Left.Free()
}
if self.Right != nil {
self.Right.Free()
}
}
// Free returns the Expr into pool.
// Any operation performed after Free is undefined behavior.
func (self *Expr) Free() {
self.clear()
freeExpression(self)
}
// Evaluate evaluates the expression into an integer.
// It also implements the Term interface.
func (self *Expr) Evaluate() (int64, error) {
switch self.Type {
case EXPR:
return self.eval()
case TERM:
return self.Term.Evaluate()
case CONST:
return self.Const, nil
default:
panic("invalid expression type: " + self.Type.String())
}
}
/** Expression Combinator **/
func combine(a *Expr, op Operator, b *Expr) (r *Expr) {
r = newExpression()
r.Op = op
r.Type = EXPR
r.Left = a
r.Right = b
return
}
func (self *Expr) Add(v *Expr) *Expr { return combine(self, ADD, v) }
func (self *Expr) Sub(v *Expr) *Expr { return combine(self, SUB, v) }
func (self *Expr) Mul(v *Expr) *Expr { return combine(self, MUL, v) }
func (self *Expr) Div(v *Expr) *Expr { return combine(self, DIV, v) }
func (self *Expr) Mod(v *Expr) *Expr { return combine(self, MOD, v) }
func (self *Expr) And(v *Expr) *Expr { return combine(self, AND, v) }
func (self *Expr) Or(v *Expr) *Expr { return combine(self, OR, v) }
func (self *Expr) Xor(v *Expr) *Expr { return combine(self, XOR, v) }
func (self *Expr) Shl(v *Expr) *Expr { return combine(self, SHL, v) }
func (self *Expr) Shr(v *Expr) *Expr { return combine(self, SHR, v) }
func (self *Expr) Pow(v *Expr) *Expr { return combine(self, POW, v) }
func (self *Expr) Not() *Expr { return combine(self, NOT, nil) }
func (self *Expr) Neg() *Expr { return combine(self, NEG, nil) }
/** Expression Evaluator **/
var binaryEvaluators = [256]func(int64, int64) (int64, error){
ADD: func(a, b int64) (int64, error) { return a + b, nil },
SUB: func(a, b int64) (int64, error) { return a - b, nil },
MUL: func(a, b int64) (int64, error) { return a * b, nil },
DIV: idiv,
MOD: imod,
AND: func(a, b int64) (int64, error) { return a & b, nil },
OR: func(a, b int64) (int64, error) { return a | b, nil },
XOR: func(a, b int64) (int64, error) { return a ^ b, nil },
SHL: func(a, b int64) (int64, error) { return a << b, nil },
SHR: func(a, b int64) (int64, error) { return a >> b, nil },
POW: ipow,
}
func (self *Expr) eval() (int64, error) {
var lhs int64
var rhs int64
var err error
var vfn func(int64, int64) (int64, error)
/* evaluate LHS */
if lhs, err = self.Left.Evaluate(); err != nil {
return 0, err
}
/* check for unary operators */
switch self.Op {
case NOT:
return self.unaryNot(lhs)
case NEG:
return self.unaryNeg(lhs)
}
/* check for operators */
if vfn = binaryEvaluators[self.Op]; vfn == nil {
panic("invalid operator: " + self.Op.String())
}
/* must be a binary expression */
if self.Right == nil {
panic("operator " + self.Op.String() + " is a binary operator")
}
/* evaluate RHS, and call the operator */
if rhs, err = self.Right.Evaluate(); err != nil {
return 0, err
} else {
return vfn(lhs, rhs)
}
}
func (self *Expr) unaryNot(v int64) (int64, error) {
if self.Right == nil {
return ^v, nil
} else {
panic("operator Invert is an unary operator")
}
}
func (self *Expr) unaryNeg(v int64) (int64, error) {
if self.Right == nil {
return -v, nil
} else {
panic("operator Negate is an unary operator")
}
}

View file

@ -17,7 +17,7 @@
package expr package expr
import ( import (
`fmt` "fmt"
) )
// SyntaxError represents a syntax error in the expression. // SyntaxError represents a syntax error in the expression.
@ -27,9 +27,9 @@ type SyntaxError struct {
} }
func newSyntaxError(pos int, reason string) *SyntaxError { func newSyntaxError(pos int, reason string) *SyntaxError {
return &SyntaxError { return &SyntaxError{
Pos : pos, Pos: pos,
Reason : reason, Reason: reason,
} }
} }
@ -43,7 +43,7 @@ type RuntimeError struct {
} }
func newRuntimeError(reason string) *RuntimeError { func newRuntimeError(reason string) *RuntimeError {
return &RuntimeError { return &RuntimeError{
Reason: reason, Reason: reason,
} }
} }

View file

@ -0,0 +1,67 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
"fmt"
)
func idiv(v int64, d int64) (int64, error) {
if d != 0 {
return v / d, nil
} else {
return 0, newRuntimeError("division by zero")
}
}
func imod(v int64, d int64) (int64, error) {
if d != 0 {
return v % d, nil
} else {
return 0, newRuntimeError("division by zero")
}
}
func ipow(v int64, e int64) (int64, error) {
mul := v
ret := int64(1)
/* value must be 0 or positive */
if v < 0 {
return 0, newRuntimeError(fmt.Sprintf("negative base value: %d", v))
}
/* exponent must be non-negative */
if e < 0 {
return 0, newRuntimeError(fmt.Sprintf("negative exponent: %d", e))
}
/* fast power first round */
if (e & 1) != 0 {
ret *= mul
}
/* fast power remaining rounds */
for e >>= 1; e != 0; e >>= 1 {
if mul *= mul; (e & 1) != 0 {
ret *= mul
}
}
/* all done */
return ret, nil
}

View file

@ -0,0 +1,331 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
"strconv"
"unicode"
"unsafe"
)
type _TokenKind uint8
const (
_T_end _TokenKind = iota + 1
_T_int
_T_punc
_T_name
)
const (
_OP2 = 0x80
_POW = _OP2 | '*'
_SHL = _OP2 | '<'
_SHR = _OP2 | '>'
)
type _Slice struct {
p unsafe.Pointer
n int
c int
}
type _Token struct {
pos int
ptr *rune
u64 uint64
tag _TokenKind
}
func (self _Token) str() (v string) {
return string(self.rbuf())
}
func (self _Token) rbuf() (v []rune) {
(*_Slice)(unsafe.Pointer(&v)).c = int(self.u64)
(*_Slice)(unsafe.Pointer(&v)).n = int(self.u64)
(*_Slice)(unsafe.Pointer(&v)).p = unsafe.Pointer(self.ptr)
return
}
func tokenEnd(p int) _Token {
return _Token{
pos: p,
tag: _T_end,
}
}
func tokenInt(p int, v uint64) _Token {
return _Token{
pos: p,
u64: v,
tag: _T_int,
}
}
func tokenPunc(p int, v rune) _Token {
return _Token{
pos: p,
tag: _T_punc,
u64: uint64(v),
}
}
func tokenName(p int, v []rune) _Token {
return _Token{
pos: p,
ptr: &v[0],
tag: _T_name,
u64: uint64(len(v)),
}
}
// Repository represents a repository of Term's.
type Repository interface {
Get(name string) (Term, error)
}
// Parser parses an expression string to it's AST representation.
type Parser struct {
pos int
src []rune
}
var binaryOps = [...]func(*Expr, *Expr) *Expr{
'+': (*Expr).Add,
'-': (*Expr).Sub,
'*': (*Expr).Mul,
'/': (*Expr).Div,
'%': (*Expr).Mod,
'&': (*Expr).And,
'^': (*Expr).Xor,
'|': (*Expr).Or,
_SHL: (*Expr).Shl,
_SHR: (*Expr).Shr,
_POW: (*Expr).Pow,
}
var precedence = [...]map[int]bool{
{_SHL: true, _SHR: true},
{'|': true},
{'^': true},
{'&': true},
{'+': true, '-': true},
{'*': true, '/': true, '%': true},
{_POW: true},
}
func (self *Parser) ch() rune {
return self.src[self.pos]
}
func (self *Parser) eof() bool {
return self.pos >= len(self.src)
}
func (self *Parser) rch() (v rune) {
v, self.pos = self.src[self.pos], self.pos+1
return
}
func (self *Parser) hex(ss []rune) bool {
if len(ss) == 1 && ss[0] == '0' {
return unicode.ToLower(self.ch()) == 'x'
} else if len(ss) <= 1 || unicode.ToLower(ss[1]) != 'x' {
return unicode.IsDigit(self.ch())
} else {
return ishexdigit(self.ch())
}
}
func (self *Parser) int(p int, ss []rune) (_Token, error) {
var err error
var val uint64
/* find all the digits */
for !self.eof() && self.hex(ss) {
ss = append(ss, self.rch())
}
/* parse the value */
if val, err = strconv.ParseUint(string(ss), 0, 64); err != nil {
return _Token{}, err
} else {
return tokenInt(p, val), nil
}
}
func (self *Parser) name(p int, ss []rune) _Token {
for !self.eof() && isident(self.ch()) {
ss = append(ss, self.rch())
}
return tokenName(p, ss)
}
func (self *Parser) read(p int, ch rune) (_Token, error) {
if isdigit(ch) {
return self.int(p, []rune{ch})
} else if isident0(ch) {
return self.name(p, []rune{ch}), nil
} else if isop2ch(ch) && !self.eof() && self.ch() == ch {
return tokenPunc(p, _OP2|self.rch()), nil
} else if isop1ch(ch) {
return tokenPunc(p, ch), nil
} else {
return _Token{}, newSyntaxError(self.pos, "invalid character "+strconv.QuoteRuneToASCII(ch))
}
}
func (self *Parser) next() (_Token, error) {
for {
var p int
var c rune
/* check for EOF */
if self.eof() {
return tokenEnd(self.pos), nil
}
/* read the next char */
p = self.pos
c = self.rch()
/* parse the token if not a space */
if !unicode.IsSpace(c) {
return self.read(p, c)
}
}
}
func (self *Parser) grab(tk _Token, repo Repository) (*Expr, error) {
if repo == nil {
return nil, newSyntaxError(tk.pos, "unresolved symbol: "+tk.str())
} else if term, err := repo.Get(tk.str()); err != nil {
return nil, err
} else {
return Ref(term), nil
}
}
func (self *Parser) nest(nest int, repo Repository) (*Expr, error) {
var err error
var ret *Expr
var ntk _Token
/* evaluate the nested expression */
if ret, err = self.expr(0, nest+1, repo); err != nil {
return nil, err
}
/* must follows with a ')' */
if ntk, err = self.next(); err != nil {
return nil, err
} else if ntk.tag != _T_punc || ntk.u64 != ')' {
return nil, newSyntaxError(ntk.pos, "')' expected")
} else {
return ret, nil
}
}
func (self *Parser) unit(nest int, repo Repository) (*Expr, error) {
if tk, err := self.next(); err != nil {
return nil, err
} else if tk.tag == _T_int {
return Int(int64(tk.u64)), nil
} else if tk.tag == _T_name {
return self.grab(tk, repo)
} else if tk.tag == _T_punc && tk.u64 == '(' {
return self.nest(nest, repo)
} else if tk.tag == _T_punc && tk.u64 == '+' {
return self.unit(nest, repo)
} else if tk.tag == _T_punc && tk.u64 == '-' {
return neg2(self.unit(nest, repo))
} else if tk.tag == _T_punc && tk.u64 == '~' {
return not2(self.unit(nest, repo))
} else {
return nil, newSyntaxError(tk.pos, "integer, unary operator or nested expression expected")
}
}
func (self *Parser) term(prec int, nest int, repo Repository) (*Expr, error) {
var err error
var val *Expr
/* parse the LHS operand */
if val, err = self.expr(prec+1, nest, repo); err != nil {
return nil, err
}
/* parse all the operators of the same precedence */
for {
var op int
var rv *Expr
var tk _Token
/* peek the next token */
pp := self.pos
tk, err = self.next()
/* check for errors */
if err != nil {
return nil, err
}
/* encountered EOF */
if tk.tag == _T_end {
return val, nil
}
/* must be an operator */
if tk.tag != _T_punc {
return nil, newSyntaxError(tk.pos, "operators expected")
}
/* check for the operator precedence */
if op = int(tk.u64); !precedence[prec][op] {
self.pos = pp
return val, nil
}
/* evaluate the RHS operand, and combine the value */
if rv, err = self.expr(prec+1, nest, repo); err != nil {
return nil, err
} else {
val = binaryOps[op](val, rv)
}
}
}
func (self *Parser) expr(prec int, nest int, repo Repository) (*Expr, error) {
if prec >= len(precedence) {
return self.unit(nest, repo)
} else {
return self.term(prec, nest, repo)
}
}
// Parse parses the expression, and returns it's AST tree.
func (self *Parser) Parse(repo Repository) (*Expr, error) {
return self.expr(0, 0, repo)
}
// SetSource resets the expression parser and sets the expression source.
func (self *Parser) SetSource(src string) *Parser {
self.pos = 0
self.src = []rune(src)
return self
}

View file

@ -17,7 +17,7 @@
package expr package expr
import ( import (
`sync` "sync"
) )
var ( var (

View file

@ -16,7 +16,7 @@
package expr package expr
var op1ch = [...]bool { var op1ch = [...]bool{
'+': true, '+': true,
'-': true, '-': true,
'*': true, '*': true,
@ -30,7 +30,7 @@
')': true, ')': true,
} }
var op2ch = [...]bool { var op2ch = [...]bool{
'*': true, '*': true,
'<': true, '<': true,
'>': true, '>': true,

View file

@ -0,0 +1,251 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
"fmt"
)
// ISA represents an extension to x86-64 instruction set.
type ISA uint64
const (
ISA_CPUID ISA = 1 << iota
ISA_RDTSC
ISA_RDTSCP
ISA_CMOV
ISA_MOVBE
ISA_POPCNT
ISA_LZCNT
ISA_TBM
ISA_BMI
ISA_BMI2
ISA_ADX
ISA_MMX
ISA_MMX_PLUS
ISA_FEMMS
ISA_3DNOW
ISA_3DNOW_PLUS
ISA_SSE
ISA_SSE2
ISA_SSE3
ISA_SSSE3
ISA_SSE4A
ISA_SSE4_1
ISA_SSE4_2
ISA_FMA3
ISA_FMA4
ISA_XOP
ISA_F16C
ISA_AVX
ISA_AVX2
ISA_AVX512F
ISA_AVX512BW
ISA_AVX512DQ
ISA_AVX512VL
ISA_AVX512PF
ISA_AVX512ER
ISA_AVX512CD
ISA_AVX512VBMI
ISA_AVX512IFMA
ISA_AVX512VPOPCNTDQ
ISA_AVX512_4VNNIW
ISA_AVX512_4FMAPS
ISA_PREFETCH
ISA_PREFETCHW
ISA_PREFETCHWT1
ISA_CLFLUSH
ISA_CLFLUSHOPT
ISA_CLWB
ISA_CLZERO
ISA_RDRAND
ISA_RDSEED
ISA_PCLMULQDQ
ISA_AES
ISA_SHA
ISA_MONITOR
ISA_MONITORX
ISA_ALL = ^ISA(0)
)
var _ISA_NAMES = map[ISA]string{
ISA_CPUID: "CPUID",
ISA_RDTSC: "RDTSC",
ISA_RDTSCP: "RDTSCP",
ISA_CMOV: "CMOV",
ISA_MOVBE: "MOVBE",
ISA_POPCNT: "POPCNT",
ISA_LZCNT: "LZCNT",
ISA_TBM: "TBM",
ISA_BMI: "BMI",
ISA_BMI2: "BMI2",
ISA_ADX: "ADX",
ISA_MMX: "MMX",
ISA_MMX_PLUS: "MMX+",
ISA_FEMMS: "FEMMS",
ISA_3DNOW: "3dnow!",
ISA_3DNOW_PLUS: "3dnow!+",
ISA_SSE: "SSE",
ISA_SSE2: "SSE2",
ISA_SSE3: "SSE3",
ISA_SSSE3: "SSSE3",
ISA_SSE4A: "SSE4A",
ISA_SSE4_1: "SSE4.1",
ISA_SSE4_2: "SSE4.2",
ISA_FMA3: "FMA3",
ISA_FMA4: "FMA4",
ISA_XOP: "XOP",
ISA_F16C: "F16C",
ISA_AVX: "AVX",
ISA_AVX2: "AVX2",
ISA_AVX512F: "AVX512F",
ISA_AVX512BW: "AVX512BW",
ISA_AVX512DQ: "AVX512DQ",
ISA_AVX512VL: "AVX512VL",
ISA_AVX512PF: "AVX512PF",
ISA_AVX512ER: "AVX512ER",
ISA_AVX512CD: "AVX512CD",
ISA_AVX512VBMI: "AVX512VBMI",
ISA_AVX512IFMA: "AVX512IFMA",
ISA_AVX512VPOPCNTDQ: "AVX512VPOPCNTDQ",
ISA_AVX512_4VNNIW: "AVX512_4VNNIW",
ISA_AVX512_4FMAPS: "AVX512_4FMAPS",
ISA_PREFETCH: "PREFETCH",
ISA_PREFETCHW: "PREFETCHW",
ISA_PREFETCHWT1: "PREFETCHWT1",
ISA_CLFLUSH: "CLFLUSH",
ISA_CLFLUSHOPT: "CLFLUSHOPT",
ISA_CLWB: "CLWB",
ISA_CLZERO: "CLZERO",
ISA_RDRAND: "RDRAND",
ISA_RDSEED: "RDSEED",
ISA_PCLMULQDQ: "PCLMULQDQ",
ISA_AES: "AES",
ISA_SHA: "SHA",
ISA_MONITOR: "MONITOR",
ISA_MONITORX: "MONITORX",
}
var _ISA_MAPPING = map[string]ISA{
"CPUID": ISA_CPUID,
"RDTSC": ISA_RDTSC,
"RDTSCP": ISA_RDTSCP,
"CMOV": ISA_CMOV,
"MOVBE": ISA_MOVBE,
"POPCNT": ISA_POPCNT,
"LZCNT": ISA_LZCNT,
"TBM": ISA_TBM,
"BMI": ISA_BMI,
"BMI2": ISA_BMI2,
"ADX": ISA_ADX,
"MMX": ISA_MMX,
"MMX+": ISA_MMX_PLUS,
"FEMMS": ISA_FEMMS,
"3dnow!": ISA_3DNOW,
"3dnow!+": ISA_3DNOW_PLUS,
"SSE": ISA_SSE,
"SSE2": ISA_SSE2,
"SSE3": ISA_SSE3,
"SSSE3": ISA_SSSE3,
"SSE4A": ISA_SSE4A,
"SSE4.1": ISA_SSE4_1,
"SSE4.2": ISA_SSE4_2,
"FMA3": ISA_FMA3,
"FMA4": ISA_FMA4,
"XOP": ISA_XOP,
"F16C": ISA_F16C,
"AVX": ISA_AVX,
"AVX2": ISA_AVX2,
"AVX512F": ISA_AVX512F,
"AVX512BW": ISA_AVX512BW,
"AVX512DQ": ISA_AVX512DQ,
"AVX512VL": ISA_AVX512VL,
"AVX512PF": ISA_AVX512PF,
"AVX512ER": ISA_AVX512ER,
"AVX512CD": ISA_AVX512CD,
"AVX512VBMI": ISA_AVX512VBMI,
"AVX512IFMA": ISA_AVX512IFMA,
"AVX512VPOPCNTDQ": ISA_AVX512VPOPCNTDQ,
"AVX512_4VNNIW": ISA_AVX512_4VNNIW,
"AVX512_4FMAPS": ISA_AVX512_4FMAPS,
"PREFETCH": ISA_PREFETCH,
"PREFETCHW": ISA_PREFETCHW,
"PREFETCHWT1": ISA_PREFETCHWT1,
"CLFLUSH": ISA_CLFLUSH,
"CLFLUSHOPT": ISA_CLFLUSHOPT,
"CLWB": ISA_CLWB,
"CLZERO": ISA_CLZERO,
"RDRAND": ISA_RDRAND,
"RDSEED": ISA_RDSEED,
"PCLMULQDQ": ISA_PCLMULQDQ,
"AES": ISA_AES,
"SHA": ISA_SHA,
"MONITOR": ISA_MONITOR,
"MONITORX": ISA_MONITORX,
}
func (self ISA) String() string {
if v, ok := _ISA_NAMES[self]; ok {
return v
} else {
return fmt.Sprintf("(invalid: %#x)", uint64(self))
}
}
// ParseISA parses name into ISA, it will panic if the name is invalid.
func ParseISA(name string) ISA {
if v, ok := _ISA_MAPPING[name]; ok {
return v
} else {
panic("invalid ISA name: " + name)
}
}
// Arch represents the x86_64 architecture.
type Arch struct {
isa ISA
}
// DefaultArch is the default architecture with all ISA enabled.
var DefaultArch = CreateArch()
// CreateArch creates a new Arch with all ISA enabled.
func CreateArch() *Arch {
return new(Arch).EnableISA(ISA_ALL)
}
// HasISA checks if a particular ISA was enabled.
func (self *Arch) HasISA(isa ISA) bool {
return (self.isa & isa) != 0
}
// EnableISA enables a particular ISA.
func (self *Arch) EnableISA(isa ISA) *Arch {
self.isa |= isa
return self
}
// DisableISA disables a particular ISA.
func (self *Arch) DisableISA(isa ISA) *Arch {
self.isa &^= isa
return self
}
// CreateProgram creates a new empty program.
func (self *Arch) CreateProgram() *Program {
return newProgram(self)
}

View file

@ -17,8 +17,8 @@
package x86_64 package x86_64
import ( import (
`reflect` "reflect"
`unsafe` "unsafe"
) )
type _GoType struct { type _GoType struct {

View file

@ -0,0 +1,836 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
"encoding/binary"
"math"
)
/** Operand Encoding Helpers **/
func imml(v interface{}) byte {
return byte(toImmAny(v) & 0x0f)
}
func relv(v interface{}) int64 {
switch r := v.(type) {
case *Label:
return 0
case RelativeOffset:
return int64(r)
default:
panic("invalid relative offset")
}
}
func addr(v interface{}) interface{} {
switch a := v.(*MemoryOperand).Addr; a.Type {
case Memory:
return a.Memory
case Offset:
return a.Offset
case Reference:
return a.Reference
default:
panic("invalid memory operand type")
}
}
func bcode(v interface{}) byte {
if m, ok := v.(*MemoryOperand); !ok {
panic("v is not a memory operand")
} else if m.Broadcast == 0 {
return 0
} else {
return 1
}
}
func vcode(v interface{}) byte {
switch r := v.(type) {
case XMMRegister:
return byte(r)
case YMMRegister:
return byte(r)
case ZMMRegister:
return byte(r)
case MaskedRegister:
return vcode(r.Reg)
default:
panic("v is not a vector register")
}
}
func kcode(v interface{}) byte {
switch r := v.(type) {
case KRegister:
return byte(r)
case XMMRegister:
return 0
case YMMRegister:
return 0
case ZMMRegister:
return 0
case RegisterMask:
return byte(r.K)
case MaskedRegister:
return byte(r.Mask.K)
case *MemoryOperand:
return toKcodeMem(r)
default:
panic("v is not a maskable operand")
}
}
func zcode(v interface{}) byte {
switch r := v.(type) {
case KRegister:
return 0
case XMMRegister:
return 0
case YMMRegister:
return 0
case ZMMRegister:
return 0
case RegisterMask:
return toZcodeRegM(r)
case MaskedRegister:
return toZcodeRegM(r.Mask)
case *MemoryOperand:
return toZcodeMem(r)
default:
panic("v is not a maskable operand")
}
}
func lcode(v interface{}) byte {
switch r := v.(type) {
case Register8:
return byte(r & 0x07)
case Register16:
return byte(r & 0x07)
case Register32:
return byte(r & 0x07)
case Register64:
return byte(r & 0x07)
case KRegister:
return byte(r & 0x07)
case MMRegister:
return byte(r & 0x07)
case XMMRegister:
return byte(r & 0x07)
case YMMRegister:
return byte(r & 0x07)
case ZMMRegister:
return byte(r & 0x07)
case MaskedRegister:
return lcode(r.Reg)
default:
panic("v is not a register")
}
}
func hcode(v interface{}) byte {
switch r := v.(type) {
case Register8:
return byte(r>>3) & 1
case Register16:
return byte(r>>3) & 1
case Register32:
return byte(r>>3) & 1
case Register64:
return byte(r>>3) & 1
case KRegister:
return byte(r>>3) & 1
case MMRegister:
return byte(r>>3) & 1
case XMMRegister:
return byte(r>>3) & 1
case YMMRegister:
return byte(r>>3) & 1
case ZMMRegister:
return byte(r>>3) & 1
case MaskedRegister:
return hcode(r.Reg)
default:
panic("v is not a register")
}
}
func ecode(v interface{}) byte {
switch r := v.(type) {
case Register8:
return byte(r>>4) & 1
case Register16:
return byte(r>>4) & 1
case Register32:
return byte(r>>4) & 1
case Register64:
return byte(r>>4) & 1
case KRegister:
return byte(r>>4) & 1
case MMRegister:
return byte(r>>4) & 1
case XMMRegister:
return byte(r>>4) & 1
case YMMRegister:
return byte(r>>4) & 1
case ZMMRegister:
return byte(r>>4) & 1
case MaskedRegister:
return ecode(r.Reg)
default:
panic("v is not a register")
}
}
func hlcode(v interface{}) byte {
switch r := v.(type) {
case Register8:
return toHLcodeReg8(r)
case Register16:
return byte(r & 0x0f)
case Register32:
return byte(r & 0x0f)
case Register64:
return byte(r & 0x0f)
case KRegister:
return byte(r & 0x0f)
case MMRegister:
return byte(r & 0x0f)
case XMMRegister:
return byte(r & 0x0f)
case YMMRegister:
return byte(r & 0x0f)
case ZMMRegister:
return byte(r & 0x0f)
case MaskedRegister:
return hlcode(r.Reg)
default:
panic("v is not a register")
}
}
func ehcode(v interface{}) byte {
switch r := v.(type) {
case Register8:
return byte(r>>3) & 0x03
case Register16:
return byte(r>>3) & 0x03
case Register32:
return byte(r>>3) & 0x03
case Register64:
return byte(r>>3) & 0x03
case KRegister:
return byte(r>>3) & 0x03
case MMRegister:
return byte(r>>3) & 0x03
case XMMRegister:
return byte(r>>3) & 0x03
case YMMRegister:
return byte(r>>3) & 0x03
case ZMMRegister:
return byte(r>>3) & 0x03
case MaskedRegister:
return ehcode(r.Reg)
default:
panic("v is not a register")
}
}
func toImmAny(v interface{}) int64 {
if x, ok := asInt64(v); ok {
return x
} else {
panic("value is not an integer")
}
}
func toHcodeOpt(v interface{}) byte {
if v == nil {
return 0
} else {
return hcode(v)
}
}
func toEcodeVMM(v interface{}, x byte) byte {
switch r := v.(type) {
case XMMRegister:
return ecode(r)
case YMMRegister:
return ecode(r)
case ZMMRegister:
return ecode(r)
default:
return x
}
}
func toKcodeMem(v *MemoryOperand) byte {
if !v.Masked {
return 0
} else {
return byte(v.Mask.K)
}
}
func toZcodeMem(v *MemoryOperand) byte {
if !v.Masked || v.Mask.Z {
return 0
} else {
return 1
}
}
func toZcodeRegM(v RegisterMask) byte {
if v.Z {
return 1
} else {
return 0
}
}
func toHLcodeReg8(v Register8) byte {
switch v {
case AH:
fallthrough
case BH:
fallthrough
case CH:
fallthrough
case DH:
panic("ah/bh/ch/dh registers never use 4-bit encoding")
default:
return byte(v & 0x0f)
}
}
/** Instruction Encoding Helpers **/
const (
_N_inst = 16
)
const (
_F_rel1 = 1 << iota
_F_rel4
)
type _Encoding struct {
len int
flags int
bytes [_N_inst]byte
encoder func(m *_Encoding, v []interface{})
}
// buf ensures len + n <= len(bytes).
func (self *_Encoding) buf(n int) []byte {
if i := self.len; i+n > _N_inst {
panic("instruction too long")
} else {
return self.bytes[i:]
}
}
// emit encodes a single byte.
func (self *_Encoding) emit(v byte) {
self.buf(1)[0] = v
self.len++
}
// imm1 encodes a single byte immediate value.
func (self *_Encoding) imm1(v int64) {
self.emit(byte(v))
}
// imm2 encodes a two-byte immediate value in little-endian.
func (self *_Encoding) imm2(v int64) {
binary.LittleEndian.PutUint16(self.buf(2), uint16(v))
self.len += 2
}
// imm4 encodes a 4-byte immediate value in little-endian.
func (self *_Encoding) imm4(v int64) {
binary.LittleEndian.PutUint32(self.buf(4), uint32(v))
self.len += 4
}
// imm8 encodes an 8-byte immediate value in little-endian.
func (self *_Encoding) imm8(v int64) {
binary.LittleEndian.PutUint64(self.buf(8), uint64(v))
self.len += 8
}
// vex2 encodes a 2-byte or 3-byte VEX prefix.
//
// 2-byte VEX prefix:
//
// Requires: VEX.W = 0, VEX.mmmmm = 0b00001 and VEX.B = VEX.X = 0
//
// +----------------+
//
// Byte 0: | Bits 0-7: 0xc5 |
//
// +----------------+
//
// +-----------+----------------+----------+--------------+
//
// Byte 1: | Bit 7: ~R | Bits 3-6 ~vvvv | Bit 2: L | Bits 0-1: pp |
//
// +-----------+----------------+----------+--------------+
//
// 3-byte VEX prefix:
// +----------------+
//
// Byte 0: | Bits 0-7: 0xc4 |
//
// +----------------+
//
// +-----------+-----------+-----------+-------------------+
//
// Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: 0b00001 |
//
// +-----------+-----------+-----------+-------------------+
//
// +----------+-----------------+----------+--------------+
//
// Byte 2: | Bit 7: 0 | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
//
// +----------+-----------------+----------+--------------+
func (self *_Encoding) vex2(lpp byte, r byte, rm interface{}, vvvv byte) {
var b byte
var x byte
/* VEX.R must be a single-bit mask */
if r > 1 {
panic("VEX.R must be a 1-bit mask")
}
/* VEX.Lpp must be a 3-bit mask */
if lpp&^0b111 != 0 {
panic("VEX.Lpp must be a 3-bit mask")
}
/* VEX.vvvv must be a 4-bit mask */
if vvvv&^0b1111 != 0 {
panic("VEX.vvvv must be a 4-bit mask")
}
/* encode the RM bits if any */
if rm != nil {
switch v := rm.(type) {
case *Label:
break
case Register:
b = hcode(v)
case MemoryAddress:
b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset:
break
default:
panic("rm is expected to be a register or a memory address")
}
}
/* if VEX.B and VEX.X are zeroes, 2-byte VEX prefix can be used */
if x == 0 && b == 0 {
self.emit(0xc5)
self.emit(0xf8 ^ (r << 7) ^ (vvvv << 3) ^ lpp)
} else {
self.emit(0xc4)
self.emit(0xe1 ^ (r << 7) ^ (x << 6) ^ (b << 5))
self.emit(0x78 ^ (vvvv << 3) ^ lpp)
}
}
// vex3 encodes a 3-byte VEX or XOP prefix.
//
// 3-byte VEX/XOP prefix
// +-----------------------------------+
//
// Byte 0: | Bits 0-7: 0xc4 (VEX) / 0x8f (XOP) |
//
// +-----------------------------------+
//
// +-----------+-----------+-----------+-----------------+
//
// Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: mmmmm |
//
// +-----------+-----------+-----------+-----------------+
//
// +----------+-----------------+----------+--------------+
//
// Byte 2: | Bit 7: W | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
//
// +----------+-----------------+----------+--------------+
func (self *_Encoding) vex3(esc byte, mmmmm byte, wlpp byte, r byte, rm interface{}, vvvv byte) {
var b byte
var x byte
/* VEX.R must be a single-bit mask */
if r > 1 {
panic("VEX.R must be a 1-bit mask")
}
/* VEX.vvvv must be a 4-bit mask */
if vvvv&^0b1111 != 0 {
panic("VEX.vvvv must be a 4-bit mask")
}
/* escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix */
if esc != 0xc4 && esc != 0x8f {
panic("escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix")
}
/* VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7 */
if wlpp&^0b10000111 != 0 {
panic("VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7")
}
/* VEX.m-mmmm is expected to be a 5-bit mask */
if mmmmm&^0b11111 != 0 {
panic("VEX.m-mmmm is expected to be a 5-bit mask")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label:
break
case MemoryAddress:
b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset:
break
default:
panic("rm is expected to be a register or a memory address")
}
/* encode the 3-byte VEX or XOP prefix */
self.emit(esc)
self.emit(0xe0 ^ (r << 7) ^ (x << 6) ^ (b << 5) ^ mmmmm)
self.emit(0x78 ^ (vvvv << 3) ^ wlpp)
}
// evex encodes a 4-byte EVEX prefix.
func (self *_Encoding) evex(mm byte, w1pp byte, ll byte, rr byte, rm interface{}, vvvvv byte, aaa byte, zz byte, bb byte) {
var b byte
var x byte
/* EVEX.b must be a single-bit mask */
if bb > 1 {
panic("EVEX.b must be a 1-bit mask")
}
/* EVEX.z must be a single-bit mask */
if zz > 1 {
panic("EVEX.z must be a 1-bit mask")
}
/* EVEX.mm must be a 2-bit mask */
if mm&^0b11 != 0 {
panic("EVEX.mm must be a 2-bit mask")
}
/* EVEX.L'L must be a 2-bit mask */
if ll&^0b11 != 0 {
panic("EVEX.L'L must be a 2-bit mask")
}
/* EVEX.R'R must be a 2-bit mask */
if rr&^0b11 != 0 {
panic("EVEX.R'R must be a 2-bit mask")
}
/* EVEX.aaa must be a 3-bit mask */
if aaa&^0b111 != 0 {
panic("EVEX.aaa must be a 3-bit mask")
}
/* EVEX.v'vvvv must be a 5-bit mask */
if vvvvv&^0b11111 != 0 {
panic("EVEX.v'vvvv must be a 5-bit mask")
}
/* EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7 */
if w1pp&^0b10000011 != 0b100 {
panic("EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7")
}
/* extract bits from EVEX.R'R and EVEX.v'vvvv */
r1, r0 := rr>>1, rr&1
v1, v0 := vvvvv>>4, vvvvv&0b1111
/* encode the RM bits if any */
if rm != nil {
switch m := rm.(type) {
case *Label:
break
case Register:
b, x = hcode(m), ecode(m)
case MemoryAddress:
b, x, v1 = toHcodeOpt(m.Base), toHcodeOpt(m.Index), toEcodeVMM(m.Index, v1)
case RelativeOffset:
break
default:
panic("rm is expected to be a register or a memory address")
}
}
/* EVEX prefix bytes */
p0 := (r0 << 7) | (x << 6) | (b << 5) | (r1 << 4) | mm
p1 := (v0 << 3) | w1pp
p2 := (zz << 7) | (ll << 5) | (b << 4) | (v1 << 3) | aaa
/* p0: invert RXBR' (bits 4-7)
* p1: invert vvvv (bits 3-6)
* p2: invert V' (bit 3) */
self.emit(0x62)
self.emit(p0 ^ 0xf0)
self.emit(p1 ^ 0x78)
self.emit(p2 ^ 0x08)
}
// rexm encodes a mandatory REX prefix.
func (self *_Encoding) rexm(w byte, r byte, rm interface{}) {
var b byte
var x byte
/* REX.R must be 0 or 1 */
if r != 0 && r != 1 {
panic("REX.R must be 0 or 1")
}
/* REX.W must be 0 or 1 */
if w != 0 && w != 1 {
panic("REX.W must be 0 or 1")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label:
break
case MemoryAddress:
b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset:
break
default:
panic("rm is expected to be a register or a memory address")
}
/* encode the REX prefix */
self.emit(0x40 | (w << 3) | (r << 2) | (x << 1) | b)
}
// rexo encodes an optional REX prefix.
func (self *_Encoding) rexo(r byte, rm interface{}, force bool) {
var b byte
var x byte
/* REX.R must be 0 or 1 */
if r != 0 && r != 1 {
panic("REX.R must be 0 or 1")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label:
break
case Register:
b = hcode(v)
case MemoryAddress:
b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset:
break
default:
panic("rm is expected to be a register or a memory address")
}
/* if REX.R, REX.X, and REX.B are all zeroes, REX prefix can be omitted */
if force || r != 0 || x != 0 || b != 0 {
self.emit(0x40 | (r << 2) | (x << 1) | b)
}
}
// mrsd encodes ModR/M, SIB and Displacement.
//
// ModR/M byte
//
// +----------------+---------------+---------------+
// | Bits 6-7: Mode | Bits 3-5: Reg | Bits 0-2: R/M |
// +----------------+---------------+---------------+
//
// SIB byte
//
// +-----------------+-----------------+----------------+
// | Bits 6-7: Scale | Bits 3-5: Index | Bits 0-2: Base |
// +-----------------+-----------------+----------------+
func (self *_Encoding) mrsd(reg byte, rm interface{}, disp8v int32) {
var ok bool
var mm MemoryAddress
var ro RelativeOffset
/* ModRM encodes the lower 3-bit of the register */
if reg > 7 {
panic("invalid register bits")
}
/* check the displacement scale */
switch disp8v {
case 1:
break
case 2:
break
case 4:
break
case 8:
break
case 16:
break
case 32:
break
case 64:
break
default:
panic("invalid displacement size")
}
/* special case: unresolved labels, assuming a zero offset */
if _, ok = rm.(*Label); ok {
self.emit(0x05 | (reg << 3))
self.imm4(0)
return
}
/* special case: RIP-relative offset
* ModRM.Mode == 0 and ModeRM.R/M == 5 indicates (rip + disp32) addressing */
if ro, ok = rm.(RelativeOffset); ok {
self.emit(0x05 | (reg << 3))
self.imm4(int64(ro))
return
}
/* must be a generic memory address */
if mm, ok = rm.(MemoryAddress); !ok {
panic("rm must be a memory address")
}
/* absolute addressing, encoded as disp(%rbp,%rsp,1) */
if mm.Base == nil && mm.Index == nil {
self.emit(0x04 | (reg << 3))
self.emit(0x25)
self.imm4(int64(mm.Displacement))
return
}
/* no SIB byte */
if mm.Index == nil && lcode(mm.Base) != 0b100 {
cc := lcode(mm.Base)
dv := mm.Displacement
/* ModRM.Mode == 0 (no displacement) */
if dv == 0 && mm.Base != RBP && mm.Base != R13 {
if cc == 0b101 {
panic("rbp/r13 is not encodable as a base register (interpreted as disp32 address)")
} else {
self.emit((reg << 3) | cc)
return
}
}
/* ModRM.Mode == 1 (8-bit displacement) */
if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv%disp8v == 0 {
self.emit(0x40 | (reg << 3) | cc)
self.imm1(int64(dq))
return
}
/* ModRM.Mode == 2 (32-bit displacement) */
self.emit(0x80 | (reg << 3) | cc)
self.imm4(int64(mm.Displacement))
return
}
/* all encodings below use ModRM.R/M = 4 (0b100) to indicate the presence of SIB */
if mm.Index == RSP {
panic("rsp is not encodable as an index register (interpreted as no index)")
}
/* index = 4 (0b100) denotes no-index encoding */
var scale byte
var index byte = 0x04
/* encode the scale byte */
if mm.Scale != 0 {
switch mm.Scale {
case 1:
scale = 0
case 2:
scale = 1
case 4:
scale = 2
case 8:
scale = 3
default:
panic("invalid scale value")
}
}
/* encode the index byte */
if mm.Index != nil {
index = lcode(mm.Index)
}
/* SIB.Base = 5 (0b101) and ModRM.Mode = 0 indicates no-base encoding with disp32 */
if mm.Base == nil {
self.emit((reg << 3) | 0b100)
self.emit((scale << 6) | (index << 3) | 0b101)
self.imm4(int64(mm.Displacement))
return
}
/* base L-code & displacement value */
cc := lcode(mm.Base)
dv := mm.Displacement
/* ModRM.Mode == 0 (no displacement) */
if dv == 0 && cc != 0b101 {
self.emit((reg << 3) | 0b100)
self.emit((scale << 6) | (index << 3) | cc)
return
}
/* ModRM.Mode == 1 (8-bit displacement) */
if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv%disp8v == 0 {
self.emit(0x44 | (reg << 3))
self.emit((scale << 6) | (index << 3) | cc)
self.imm1(int64(dq))
return
}
/* ModRM.Mode == 2 (32-bit displacement) */
self.emit(0x84 | (reg << 3))
self.emit((scale << 6) | (index << 3) | cc)
self.imm4(int64(mm.Displacement))
}
// encode invokes the encoder to encode this instruction.
func (self *_Encoding) encode(v []interface{}) int {
self.len = 0
self.encoder(self, v)
return self.len
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
//
// Copyright 2024 CloudWeGo 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.
//
// Code generated by "mkasm_amd64.py", DO NOT EDIT.
package x86_64
const (
_N_args = 5
_N_forms = 23
)

View file

@ -21,7 +21,7 @@
"math" "math"
"math/bits" "math/bits"
"github.com/cloudwego/iasm/expr" "github.com/bytedance/sonic/loader/internal/iasm/expr"
) )
type ( type (

View file

@ -0,0 +1,747 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
"fmt"
)
// Register represents a hardware register.
type Register interface {
fmt.Stringer
implRegister()
}
type (
Register8 byte
Register16 byte
Register32 byte
Register64 byte
)
type (
KRegister byte
MMRegister byte
XMMRegister byte
YMMRegister byte
ZMMRegister byte
)
// RegisterMask is a KRegister used to mask another register.
type RegisterMask struct {
Z bool
K KRegister
}
// String implements the fmt.Stringer interface.
func (self RegisterMask) String() string {
if !self.Z {
return fmt.Sprintf("{%%%s}", self.K)
} else {
return fmt.Sprintf("{%%%s}{z}", self.K)
}
}
// MaskedRegister is a Register masked by a RegisterMask.
type MaskedRegister struct {
Reg Register
Mask RegisterMask
}
// String implements the fmt.Stringer interface.
func (self MaskedRegister) String() string {
return self.Reg.String() + self.Mask.String()
}
const (
AL Register8 = iota
CL
DL
BL
SPL
BPL
SIL
DIL
R8b
R9b
R10b
R11b
R12b
R13b
R14b
R15b
)
const (
AH = SPL | 0x80
CH = BPL | 0x80
DH = SIL | 0x80
BH = DIL | 0x80
)
const (
AX Register16 = iota
CX
DX
BX
SP
BP
SI
DI
R8w
R9w
R10w
R11w
R12w
R13w
R14w
R15w
)
const (
EAX Register32 = iota
ECX
EDX
EBX
ESP
EBP
ESI
EDI
R8d
R9d
R10d
R11d
R12d
R13d
R14d
R15d
)
const (
RAX Register64 = iota
RCX
RDX
RBX
RSP
RBP
RSI
RDI
R8
R9
R10
R11
R12
R13
R14
R15
)
const (
K0 KRegister = iota
K1
K2
K3
K4
K5
K6
K7
)
const (
MM0 MMRegister = iota
MM1
MM2
MM3
MM4
MM5
MM6
MM7
)
const (
XMM0 XMMRegister = iota
XMM1
XMM2
XMM3
XMM4
XMM5
XMM6
XMM7
XMM8
XMM9
XMM10
XMM11
XMM12
XMM13
XMM14
XMM15
XMM16
XMM17
XMM18
XMM19
XMM20
XMM21
XMM22
XMM23
XMM24
XMM25
XMM26
XMM27
XMM28
XMM29
XMM30
XMM31
)
const (
YMM0 YMMRegister = iota
YMM1
YMM2
YMM3
YMM4
YMM5
YMM6
YMM7
YMM8
YMM9
YMM10
YMM11
YMM12
YMM13
YMM14
YMM15
YMM16
YMM17
YMM18
YMM19
YMM20
YMM21
YMM22
YMM23
YMM24
YMM25
YMM26
YMM27
YMM28
YMM29
YMM30
YMM31
)
const (
ZMM0 ZMMRegister = iota
ZMM1
ZMM2
ZMM3
ZMM4
ZMM5
ZMM6
ZMM7
ZMM8
ZMM9
ZMM10
ZMM11
ZMM12
ZMM13
ZMM14
ZMM15
ZMM16
ZMM17
ZMM18
ZMM19
ZMM20
ZMM21
ZMM22
ZMM23
ZMM24
ZMM25
ZMM26
ZMM27
ZMM28
ZMM29
ZMM30
ZMM31
)
func (self Register8) implRegister() {}
func (self Register16) implRegister() {}
func (self Register32) implRegister() {}
func (self Register64) implRegister() {}
func (self KRegister) implRegister() {}
func (self MMRegister) implRegister() {}
func (self XMMRegister) implRegister() {}
func (self YMMRegister) implRegister() {}
func (self ZMMRegister) implRegister() {}
func (self Register8) String() string {
if int(self) >= len(r8names) {
return "???"
} else {
return r8names[self]
}
}
func (self Register16) String() string {
if int(self) >= len(r16names) {
return "???"
} else {
return r16names[self]
}
}
func (self Register32) String() string {
if int(self) >= len(r32names) {
return "???"
} else {
return r32names[self]
}
}
func (self Register64) String() string {
if int(self) >= len(r64names) {
return "???"
} else {
return r64names[self]
}
}
func (self KRegister) String() string {
if int(self) >= len(knames) {
return "???"
} else {
return knames[self]
}
}
func (self MMRegister) String() string {
if int(self) >= len(mmnames) {
return "???"
} else {
return mmnames[self]
}
}
func (self XMMRegister) String() string {
if int(self) >= len(xmmnames) {
return "???"
} else {
return xmmnames[self]
}
}
func (self YMMRegister) String() string {
if int(self) >= len(ymmnames) {
return "???"
} else {
return ymmnames[self]
}
}
func (self ZMMRegister) String() string {
if int(self) >= len(zmmnames) {
return "???"
} else {
return zmmnames[self]
}
}
// Registers maps register name into Register instances.
var Registers = map[string]Register{
"al": AL,
"cl": CL,
"dl": DL,
"bl": BL,
"spl": SPL,
"bpl": BPL,
"sil": SIL,
"dil": DIL,
"r8b": R8b,
"r9b": R9b,
"r10b": R10b,
"r11b": R11b,
"r12b": R12b,
"r13b": R13b,
"r14b": R14b,
"r15b": R15b,
"ah": AH,
"ch": CH,
"dh": DH,
"bh": BH,
"ax": AX,
"cx": CX,
"dx": DX,
"bx": BX,
"sp": SP,
"bp": BP,
"si": SI,
"di": DI,
"r8w": R8w,
"r9w": R9w,
"r10w": R10w,
"r11w": R11w,
"r12w": R12w,
"r13w": R13w,
"r14w": R14w,
"r15w": R15w,
"eax": EAX,
"ecx": ECX,
"edx": EDX,
"ebx": EBX,
"esp": ESP,
"ebp": EBP,
"esi": ESI,
"edi": EDI,
"r8d": R8d,
"r9d": R9d,
"r10d": R10d,
"r11d": R11d,
"r12d": R12d,
"r13d": R13d,
"r14d": R14d,
"r15d": R15d,
"rax": RAX,
"rcx": RCX,
"rdx": RDX,
"rbx": RBX,
"rsp": RSP,
"rbp": RBP,
"rsi": RSI,
"rdi": RDI,
"r8": R8,
"r9": R9,
"r10": R10,
"r11": R11,
"r12": R12,
"r13": R13,
"r14": R14,
"r15": R15,
"k0": K0,
"k1": K1,
"k2": K2,
"k3": K3,
"k4": K4,
"k5": K5,
"k6": K6,
"k7": K7,
"mm0": MM0,
"mm1": MM1,
"mm2": MM2,
"mm3": MM3,
"mm4": MM4,
"mm5": MM5,
"mm6": MM6,
"mm7": MM7,
"xmm0": XMM0,
"xmm1": XMM1,
"xmm2": XMM2,
"xmm3": XMM3,
"xmm4": XMM4,
"xmm5": XMM5,
"xmm6": XMM6,
"xmm7": XMM7,
"xmm8": XMM8,
"xmm9": XMM9,
"xmm10": XMM10,
"xmm11": XMM11,
"xmm12": XMM12,
"xmm13": XMM13,
"xmm14": XMM14,
"xmm15": XMM15,
"xmm16": XMM16,
"xmm17": XMM17,
"xmm18": XMM18,
"xmm19": XMM19,
"xmm20": XMM20,
"xmm21": XMM21,
"xmm22": XMM22,
"xmm23": XMM23,
"xmm24": XMM24,
"xmm25": XMM25,
"xmm26": XMM26,
"xmm27": XMM27,
"xmm28": XMM28,
"xmm29": XMM29,
"xmm30": XMM30,
"xmm31": XMM31,
"ymm0": YMM0,
"ymm1": YMM1,
"ymm2": YMM2,
"ymm3": YMM3,
"ymm4": YMM4,
"ymm5": YMM5,
"ymm6": YMM6,
"ymm7": YMM7,
"ymm8": YMM8,
"ymm9": YMM9,
"ymm10": YMM10,
"ymm11": YMM11,
"ymm12": YMM12,
"ymm13": YMM13,
"ymm14": YMM14,
"ymm15": YMM15,
"ymm16": YMM16,
"ymm17": YMM17,
"ymm18": YMM18,
"ymm19": YMM19,
"ymm20": YMM20,
"ymm21": YMM21,
"ymm22": YMM22,
"ymm23": YMM23,
"ymm24": YMM24,
"ymm25": YMM25,
"ymm26": YMM26,
"ymm27": YMM27,
"ymm28": YMM28,
"ymm29": YMM29,
"ymm30": YMM30,
"ymm31": YMM31,
"zmm0": ZMM0,
"zmm1": ZMM1,
"zmm2": ZMM2,
"zmm3": ZMM3,
"zmm4": ZMM4,
"zmm5": ZMM5,
"zmm6": ZMM6,
"zmm7": ZMM7,
"zmm8": ZMM8,
"zmm9": ZMM9,
"zmm10": ZMM10,
"zmm11": ZMM11,
"zmm12": ZMM12,
"zmm13": ZMM13,
"zmm14": ZMM14,
"zmm15": ZMM15,
"zmm16": ZMM16,
"zmm17": ZMM17,
"zmm18": ZMM18,
"zmm19": ZMM19,
"zmm20": ZMM20,
"zmm21": ZMM21,
"zmm22": ZMM22,
"zmm23": ZMM23,
"zmm24": ZMM24,
"zmm25": ZMM25,
"zmm26": ZMM26,
"zmm27": ZMM27,
"zmm28": ZMM28,
"zmm29": ZMM29,
"zmm30": ZMM30,
"zmm31": ZMM31,
}
/** Register Name Tables **/
var r8names = [...]string{
AL: "al",
CL: "cl",
DL: "dl",
BL: "bl",
SPL: "spl",
BPL: "bpl",
SIL: "sil",
DIL: "dil",
R8b: "r8b",
R9b: "r9b",
R10b: "r10b",
R11b: "r11b",
R12b: "r12b",
R13b: "r13b",
R14b: "r14b",
R15b: "r15b",
AH: "ah",
CH: "ch",
DH: "dh",
BH: "bh",
}
var r16names = [...]string{
AX: "ax",
CX: "cx",
DX: "dx",
BX: "bx",
SP: "sp",
BP: "bp",
SI: "si",
DI: "di",
R8w: "r8w",
R9w: "r9w",
R10w: "r10w",
R11w: "r11w",
R12w: "r12w",
R13w: "r13w",
R14w: "r14w",
R15w: "r15w",
}
var r32names = [...]string{
EAX: "eax",
ECX: "ecx",
EDX: "edx",
EBX: "ebx",
ESP: "esp",
EBP: "ebp",
ESI: "esi",
EDI: "edi",
R8d: "r8d",
R9d: "r9d",
R10d: "r10d",
R11d: "r11d",
R12d: "r12d",
R13d: "r13d",
R14d: "r14d",
R15d: "r15d",
}
var r64names = [...]string{
RAX: "rax",
RCX: "rcx",
RDX: "rdx",
RBX: "rbx",
RSP: "rsp",
RBP: "rbp",
RSI: "rsi",
RDI: "rdi",
R8: "r8",
R9: "r9",
R10: "r10",
R11: "r11",
R12: "r12",
R13: "r13",
R14: "r14",
R15: "r15",
}
var knames = [...]string{
K0: "k0",
K1: "k1",
K2: "k2",
K3: "k3",
K4: "k4",
K5: "k5",
K6: "k6",
K7: "k7",
}
var mmnames = [...]string{
MM0: "mm0",
MM1: "mm1",
MM2: "mm2",
MM3: "mm3",
MM4: "mm4",
MM5: "mm5",
MM6: "mm6",
MM7: "mm7",
}
var xmmnames = [...]string{
XMM0: "xmm0",
XMM1: "xmm1",
XMM2: "xmm2",
XMM3: "xmm3",
XMM4: "xmm4",
XMM5: "xmm5",
XMM6: "xmm6",
XMM7: "xmm7",
XMM8: "xmm8",
XMM9: "xmm9",
XMM10: "xmm10",
XMM11: "xmm11",
XMM12: "xmm12",
XMM13: "xmm13",
XMM14: "xmm14",
XMM15: "xmm15",
XMM16: "xmm16",
XMM17: "xmm17",
XMM18: "xmm18",
XMM19: "xmm19",
XMM20: "xmm20",
XMM21: "xmm21",
XMM22: "xmm22",
XMM23: "xmm23",
XMM24: "xmm24",
XMM25: "xmm25",
XMM26: "xmm26",
XMM27: "xmm27",
XMM28: "xmm28",
XMM29: "xmm29",
XMM30: "xmm30",
XMM31: "xmm31",
}
var ymmnames = [...]string{
YMM0: "ymm0",
YMM1: "ymm1",
YMM2: "ymm2",
YMM3: "ymm3",
YMM4: "ymm4",
YMM5: "ymm5",
YMM6: "ymm6",
YMM7: "ymm7",
YMM8: "ymm8",
YMM9: "ymm9",
YMM10: "ymm10",
YMM11: "ymm11",
YMM12: "ymm12",
YMM13: "ymm13",
YMM14: "ymm14",
YMM15: "ymm15",
YMM16: "ymm16",
YMM17: "ymm17",
YMM18: "ymm18",
YMM19: "ymm19",
YMM20: "ymm20",
YMM21: "ymm21",
YMM22: "ymm22",
YMM23: "ymm23",
YMM24: "ymm24",
YMM25: "ymm25",
YMM26: "ymm26",
YMM27: "ymm27",
YMM28: "ymm28",
YMM29: "ymm29",
YMM30: "ymm30",
YMM31: "ymm31",
}
var zmmnames = [...]string{
ZMM0: "zmm0",
ZMM1: "zmm1",
ZMM2: "zmm2",
ZMM3: "zmm3",
ZMM4: "zmm4",
ZMM5: "zmm5",
ZMM6: "zmm6",
ZMM7: "zmm7",
ZMM8: "zmm8",
ZMM9: "zmm9",
ZMM10: "zmm10",
ZMM11: "zmm11",
ZMM12: "zmm12",
ZMM13: "zmm13",
ZMM14: "zmm14",
ZMM15: "zmm15",
ZMM16: "zmm16",
ZMM17: "zmm17",
ZMM18: "zmm18",
ZMM19: "zmm19",
ZMM20: "zmm20",
ZMM21: "zmm21",
ZMM22: "zmm22",
ZMM23: "zmm23",
ZMM24: "zmm24",
ZMM25: "zmm25",
ZMM26: "zmm26",
ZMM27: "zmm27",
ZMM28: "zmm28",
ZMM29: "zmm29",
ZMM30: "zmm30",
ZMM31: "zmm31",
}

View file

@ -0,0 +1,147 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
"encoding/binary"
"errors"
"reflect"
"strconv"
"unicode/utf8"
"unsafe"
)
const (
_CC_digit = 1 << iota
_CC_ident
_CC_ident0
_CC_number
)
func ispow2(v uint64) bool {
return (v & (v - 1)) == 0
}
func isdigit(cc rune) bool {
return '0' <= cc && cc <= '9'
}
func isalpha(cc rune) bool {
return (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')
}
func isident(cc rune) bool {
return cc == '_' || isalpha(cc) || isdigit(cc)
}
func isident0(cc rune) bool {
return cc == '_' || isalpha(cc)
}
func isnumber(cc rune) bool {
return (cc == 'b' || cc == 'B') ||
(cc == 'o' || cc == 'O') ||
(cc == 'x' || cc == 'X') ||
(cc >= '0' && cc <= '9') ||
(cc >= 'a' && cc <= 'f') ||
(cc >= 'A' && cc <= 'F')
}
func align(v int, n int) int {
return (((v - 1) >> n) + 1) << n
}
func append8(m *[]byte, v byte) {
*m = append(*m, v)
}
func append16(m *[]byte, v uint16) {
p := len(*m)
*m = append(*m, 0, 0)
binary.LittleEndian.PutUint16((*m)[p:], v)
}
func append32(m *[]byte, v uint32) {
p := len(*m)
*m = append(*m, 0, 0, 0, 0)
binary.LittleEndian.PutUint32((*m)[p:], v)
}
func append64(m *[]byte, v uint64) {
p := len(*m)
*m = append(*m, 0, 0, 0, 0, 0, 0, 0, 0)
binary.LittleEndian.PutUint64((*m)[p:], v)
}
func expandmm(m *[]byte, n int, v byte) {
sl := (*_GoSlice)(unsafe.Pointer(m))
nb := sl.len + n
/* grow as needed */
if nb > cap(*m) {
*m = growslice(byteType, *m, nb)
}
/* fill the new area */
memset(unsafe.Pointer(uintptr(sl.ptr)+uintptr(sl.len)), v, uintptr(n))
sl.len = nb
}
func memset(p unsafe.Pointer, c byte, n uintptr) {
if c != 0 {
memsetv(p, c, n)
} else {
memclrNoHeapPointers(p, n)
}
}
func memsetv(p unsafe.Pointer, c byte, n uintptr) {
for i := uintptr(0); i < n; i++ {
*(*byte)(unsafe.Pointer(uintptr(p) + i)) = c
}
}
func literal64(v string) (uint64, error) {
var nb int
var ch rune
var ex error
var mm [12]byte
/* unquote the runes */
for v != "" {
if ch, _, v, ex = strconv.UnquoteChar(v, '\''); ex != nil {
return 0, ex
} else if nb += utf8.EncodeRune(mm[nb:], ch); nb > 8 {
return 0, errors.New("multi-char constant too large")
}
}
/* convert to uint64 */
return *(*uint64)(unsafe.Pointer(&mm)), nil
}
var (
byteWrap = reflect.TypeOf(byte(0))
byteType = (*_GoType)(efaceOf(byteWrap).ptr)
)
//go:linkname growslice runtime.growslice
func growslice(_ *_GoType, _ []byte, _ int) []byte
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
func memclrNoHeapPointers(_ unsafe.Pointer, _ uintptr)

View file

@ -68,7 +68,7 @@ func DefaultCompileOptions() CompileOptions {
// //
// For deep nested struct (depth exceeds MaxInlineDepth), // For deep nested struct (depth exceeds MaxInlineDepth),
// try to set more loops to completely compile, // try to set more loops to completely compile,
// thus reduce JIT unstability in the first hit. // thus reduce JIT instability in the first hit.
func WithCompileRecursiveDepth(loop int) CompileOption { func WithCompileRecursiveDepth(loop int) CompileOption {
return func(o *CompileOptions) { return func(o *CompileOptions) {
if loop < 0 { if loop < 0 {

View file

@ -25,7 +25,7 @@
`github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/internal/rt`
) )
// String unescapes a escaped string (not including `"` at begining and end) // String unescapes an escaped string (not including `"` at beginning and end)
// It validates invalid UTF8 and replace with `\ufffd` // It validates invalid UTF8 and replace with `\ufffd`
func String(s string) (ret string, err types.ParsingError) { func String(s string) (ret string, err types.ParsingError) {
mm := make([]byte, 0, len(s)) mm := make([]byte, 0, len(s))
@ -43,7 +43,7 @@ func IntoBytes(s string, m *[]byte) types.ParsingError {
} }
} }
// String unescapes a escaped string (not including `"` at begining and end) // String unescapes an escaped string (not including `"` at beginning and end)
// - replace enables replacing invalid utf8 escaped char with `\uffd` // - replace enables replacing invalid utf8 escaped char with `\uffd`
func _String(s string, replace bool) (ret string, err error) { func _String(s string, replace bool) (ret string, err error) {
mm := make([]byte, 0, len(s)) mm := make([]byte, 0, len(s))

View file

@ -29,7 +29,7 @@ func CorrectWith(dst []byte, src []byte, repl string) []byte {
sstr := rt.Mem2Str(src) sstr := rt.Mem2Str(src)
sidx := 0 sidx := 0
/* state machine records the invalid postions */ /* state machine records the invalid positions */
m := types.NewStateMachine() m := types.NewStateMachine()
m.Sp = 0 // invalid utf8 numbers m.Sp = 0 // invalid utf8 numbers

View file

@ -1,177 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View file

@ -1,261 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
`fmt`
)
// Type is tyep expression type.
type Type int
const (
// CONST indicates that the expression is a constant.
CONST Type = iota
// TERM indicates that the expression is a Term reference.
TERM
// EXPR indicates that the expression is a unary or binary expression.
EXPR
)
var typeNames = map[Type]string {
EXPR : "Expr",
TERM : "Term",
CONST : "Const",
}
// String returns the string representation of a Type.
func (self Type) String() string {
if v, ok := typeNames[self]; ok {
return v
} else {
return fmt.Sprintf("expr.Type(%d)", self)
}
}
// Operator represents an operation to perform when Type is EXPR.
type Operator uint8
const (
// ADD performs "Add Expr.Left and Expr.Right".
ADD Operator = iota
// SUB performs "Subtract Expr.Left by Expr.Right".
SUB
// MUL performs "Multiply Expr.Left by Expr.Right".
MUL
// DIV performs "Divide Expr.Left by Expr.Right".
DIV
// MOD performs "Modulo Expr.Left by Expr.Right".
MOD
// AND performs "Bitwise AND Expr.Left and Expr.Right".
AND
// OR performs "Bitwise OR Expr.Left and Expr.Right".
OR
// XOR performs "Bitwise XOR Expr.Left and Expr.Right".
XOR
// SHL performs "Bitwise Shift Expr.Left to the Left by Expr.Right Bits".
SHL
// SHR performs "Bitwise Shift Expr.Left to the Right by Expr.Right Bits".
SHR
// POW performs "Raise Expr.Left to the power of Expr.Right"
POW
// NOT performs "Bitwise Invert Expr.Left".
NOT
// NEG performs "Negate Expr.Left".
NEG
)
var operatorNames = map[Operator]string {
ADD : "Add",
SUB : "Subtract",
MUL : "Multiply",
DIV : "Divide",
MOD : "Modulo",
AND : "And",
OR : "Or",
XOR : "ExclusiveOr",
SHL : "ShiftLeft",
SHR : "ShiftRight",
POW : "Power",
NOT : "Invert",
NEG : "Negate",
}
// String returns the string representation of a Type.
func (self Operator) String() string {
if v, ok := operatorNames[self]; ok {
return v
} else {
return fmt.Sprintf("expr.Operator(%d)", self)
}
}
// Expr represents an expression node.
type Expr struct {
Type Type
Term Term
Op Operator
Left *Expr
Right *Expr
Const int64
}
// Ref creates an expression from a Term.
func Ref(t Term) (p *Expr) {
p = newExpression()
p.Term = t
p.Type = TERM
return
}
// Int creates an expression from an integer.
func Int(v int64) (p *Expr) {
p = newExpression()
p.Type = CONST
p.Const = v
return
}
func (self *Expr) clear() {
if self.Term != nil { self.Term.Free() }
if self.Left != nil { self.Left.Free() }
if self.Right != nil { self.Right.Free() }
}
// Free returns the Expr into pool.
// Any operation performed after Free is undefined behavior.
func (self *Expr) Free() {
self.clear()
freeExpression(self)
}
// Evaluate evaluates the expression into an integer.
// It also implements the Term interface.
func (self *Expr) Evaluate() (int64, error) {
switch self.Type {
case EXPR : return self.eval()
case TERM : return self.Term.Evaluate()
case CONST : return self.Const, nil
default : panic("invalid expression type: " + self.Type.String())
}
}
/** Expression Combinator **/
func combine(a *Expr, op Operator, b *Expr) (r *Expr) {
r = newExpression()
r.Op = op
r.Type = EXPR
r.Left = a
r.Right = b
return
}
func (self *Expr) Add(v *Expr) *Expr { return combine(self, ADD, v) }
func (self *Expr) Sub(v *Expr) *Expr { return combine(self, SUB, v) }
func (self *Expr) Mul(v *Expr) *Expr { return combine(self, MUL, v) }
func (self *Expr) Div(v *Expr) *Expr { return combine(self, DIV, v) }
func (self *Expr) Mod(v *Expr) *Expr { return combine(self, MOD, v) }
func (self *Expr) And(v *Expr) *Expr { return combine(self, AND, v) }
func (self *Expr) Or (v *Expr) *Expr { return combine(self, OR , v) }
func (self *Expr) Xor(v *Expr) *Expr { return combine(self, XOR, v) }
func (self *Expr) Shl(v *Expr) *Expr { return combine(self, SHL, v) }
func (self *Expr) Shr(v *Expr) *Expr { return combine(self, SHR, v) }
func (self *Expr) Pow(v *Expr) *Expr { return combine(self, POW, v) }
func (self *Expr) Not() *Expr { return combine(self, NOT, nil) }
func (self *Expr) Neg() *Expr { return combine(self, NEG, nil) }
/** Expression Evaluator **/
var binaryEvaluators = [256]func(int64, int64) (int64, error) {
ADD: func(a, b int64) (int64, error) { return a + b, nil },
SUB: func(a, b int64) (int64, error) { return a - b, nil },
MUL: func(a, b int64) (int64, error) { return a * b, nil },
DIV: idiv,
MOD: imod,
AND: func(a, b int64) (int64, error) { return a & b, nil },
OR: func(a, b int64) (int64, error) { return a | b, nil },
XOR: func(a, b int64) (int64, error) { return a ^ b, nil },
SHL: func(a, b int64) (int64, error) { return a << b, nil },
SHR: func(a, b int64) (int64, error) { return a >> b, nil },
POW: ipow,
}
func (self *Expr) eval() (int64, error) {
var lhs int64
var rhs int64
var err error
var vfn func(int64, int64) (int64, error)
/* evaluate LHS */
if lhs, err = self.Left.Evaluate(); err != nil {
return 0, err
}
/* check for unary operators */
switch self.Op {
case NOT: return self.unaryNot(lhs)
case NEG: return self.unaryNeg(lhs)
}
/* check for operators */
if vfn = binaryEvaluators[self.Op]; vfn == nil {
panic("invalid operator: " + self.Op.String())
}
/* must be a binary expression */
if self.Right == nil {
panic("operator " + self.Op.String() + " is a binary operator")
}
/* evaluate RHS, and call the operator */
if rhs, err = self.Right.Evaluate(); err != nil {
return 0, err
} else {
return vfn(lhs, rhs)
}
}
func (self *Expr) unaryNot(v int64) (int64, error) {
if self.Right == nil {
return ^v, nil
} else {
panic("operator Invert is an unary operator")
}
}
func (self *Expr) unaryNeg(v int64) (int64, error) {
if self.Right == nil {
return -v, nil
} else {
panic("operator Negate is an unary operator")
}
}

View file

@ -1,67 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
`fmt`
)
func idiv(v int64, d int64) (int64, error) {
if d != 0 {
return v / d, nil
} else {
return 0, newRuntimeError("division by zero")
}
}
func imod(v int64, d int64) (int64, error) {
if d != 0 {
return v % d, nil
} else {
return 0, newRuntimeError("division by zero")
}
}
func ipow(v int64, e int64) (int64, error) {
mul := v
ret := int64(1)
/* value must be 0 or positive */
if v < 0 {
return 0, newRuntimeError(fmt.Sprintf("negative base value: %d", v))
}
/* exponent must be non-negative */
if e < 0 {
return 0, newRuntimeError(fmt.Sprintf("negative exponent: %d", e))
}
/* fast power first round */
if (e & 1) != 0 {
ret *= mul
}
/* fast power remaining rounds */
for e >>= 1; e != 0; e >>= 1 {
if mul *= mul; (e & 1) != 0 {
ret *= mul
}
}
/* all done */
return ret, nil
}

View file

@ -1,329 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 expr
import (
`strconv`
`unicode`
`unsafe`
)
type _TokenKind uint8
const (
_T_end _TokenKind = iota + 1
_T_int
_T_punc
_T_name
)
const (
_OP2 = 0x80
_POW = _OP2 | '*'
_SHL = _OP2 | '<'
_SHR = _OP2 | '>'
)
type _Slice struct {
p unsafe.Pointer
n int
c int
}
type _Token struct {
pos int
ptr *rune
u64 uint64
tag _TokenKind
}
func (self _Token) str() (v string) {
return string(self.rbuf())
}
func (self _Token) rbuf() (v []rune) {
(*_Slice)(unsafe.Pointer(&v)).c = int(self.u64)
(*_Slice)(unsafe.Pointer(&v)).n = int(self.u64)
(*_Slice)(unsafe.Pointer(&v)).p = unsafe.Pointer(self.ptr)
return
}
func tokenEnd(p int) _Token {
return _Token {
pos: p,
tag: _T_end,
}
}
func tokenInt(p int, v uint64) _Token {
return _Token {
pos: p,
u64: v,
tag: _T_int,
}
}
func tokenPunc(p int, v rune) _Token {
return _Token {
pos: p,
tag: _T_punc,
u64: uint64(v),
}
}
func tokenName(p int, v []rune) _Token {
return _Token {
pos: p,
ptr: &v[0],
tag: _T_name,
u64: uint64(len(v)),
}
}
// Repository represents a repository of Term's.
type Repository interface {
Get(name string) (Term, error)
}
// Parser parses an expression string to it's AST representation.
type Parser struct {
pos int
src []rune
}
var binaryOps = [...]func(*Expr, *Expr) *Expr {
'+' : (*Expr).Add,
'-' : (*Expr).Sub,
'*' : (*Expr).Mul,
'/' : (*Expr).Div,
'%' : (*Expr).Mod,
'&' : (*Expr).And,
'^' : (*Expr).Xor,
'|' : (*Expr).Or,
_SHL : (*Expr).Shl,
_SHR : (*Expr).Shr,
_POW : (*Expr).Pow,
}
var precedence = [...]map[int]bool {
{_SHL: true, _SHR: true},
{'|' : true},
{'^' : true},
{'&' : true},
{'+' : true, '-': true},
{'*' : true, '/': true, '%': true},
{_POW: true},
}
func (self *Parser) ch() rune {
return self.src[self.pos]
}
func (self *Parser) eof() bool {
return self.pos >= len(self.src)
}
func (self *Parser) rch() (v rune) {
v, self.pos = self.src[self.pos], self.pos + 1
return
}
func (self *Parser) hex(ss []rune) bool {
if len(ss) == 1 && ss[0] == '0' {
return unicode.ToLower(self.ch()) == 'x'
} else if len(ss) <= 1 || unicode.ToLower(ss[1]) != 'x' {
return unicode.IsDigit(self.ch())
} else {
return ishexdigit(self.ch())
}
}
func (self *Parser) int(p int, ss []rune) (_Token, error) {
var err error
var val uint64
/* find all the digits */
for !self.eof() && self.hex(ss) {
ss = append(ss, self.rch())
}
/* parse the value */
if val, err = strconv.ParseUint(string(ss), 0, 64); err != nil {
return _Token{}, err
} else {
return tokenInt(p, val), nil
}
}
func (self *Parser) name(p int, ss []rune) _Token {
for !self.eof() && isident(self.ch()) { ss = append(ss, self.rch()) }
return tokenName(p, ss)
}
func (self *Parser) read(p int, ch rune) (_Token, error) {
if isdigit(ch) {
return self.int(p, []rune { ch })
} else if isident0(ch) {
return self.name(p, []rune { ch }), nil
} else if isop2ch(ch) && !self.eof() && self.ch() == ch {
return tokenPunc(p, _OP2 | self.rch()), nil
} else if isop1ch(ch) {
return tokenPunc(p, ch), nil
} else {
return _Token{}, newSyntaxError(self.pos, "invalid character " + strconv.QuoteRuneToASCII(ch))
}
}
func (self *Parser) next() (_Token, error) {
for {
var p int
var c rune
/* check for EOF */
if self.eof() {
return tokenEnd(self.pos), nil
}
/* read the next char */
p = self.pos
c = self.rch()
/* parse the token if not a space */
if !unicode.IsSpace(c) {
return self.read(p, c)
}
}
}
func (self *Parser) grab(tk _Token, repo Repository) (*Expr, error) {
if repo == nil {
return nil, newSyntaxError(tk.pos, "unresolved symbol: " + tk.str())
} else if term, err := repo.Get(tk.str()); err != nil {
return nil, err
} else {
return Ref(term), nil
}
}
func (self *Parser) nest(nest int, repo Repository) (*Expr, error) {
var err error
var ret *Expr
var ntk _Token
/* evaluate the nested expression */
if ret, err = self.expr(0, nest + 1, repo); err != nil {
return nil, err
}
/* must follows with a ')' */
if ntk, err = self.next(); err != nil {
return nil, err
} else if ntk.tag != _T_punc || ntk.u64 != ')' {
return nil, newSyntaxError(ntk.pos, "')' expected")
} else {
return ret, nil
}
}
func (self *Parser) unit(nest int, repo Repository) (*Expr, error) {
if tk, err := self.next(); err != nil {
return nil, err
} else if tk.tag == _T_int {
return Int(int64(tk.u64)), nil
} else if tk.tag == _T_name {
return self.grab(tk, repo)
} else if tk.tag == _T_punc && tk.u64 == '(' {
return self.nest(nest, repo)
} else if tk.tag == _T_punc && tk.u64 == '+' {
return self.unit(nest, repo)
} else if tk.tag == _T_punc && tk.u64 == '-' {
return neg2(self.unit(nest, repo))
} else if tk.tag == _T_punc && tk.u64 == '~' {
return not2(self.unit(nest, repo))
} else {
return nil, newSyntaxError(tk.pos, "integer, unary operator or nested expression expected")
}
}
func (self *Parser) term(prec int, nest int, repo Repository) (*Expr, error) {
var err error
var val *Expr
/* parse the LHS operand */
if val, err = self.expr(prec + 1, nest, repo); err != nil {
return nil, err
}
/* parse all the operators of the same precedence */
for {
var op int
var rv *Expr
var tk _Token
/* peek the next token */
pp := self.pos
tk, err = self.next()
/* check for errors */
if err != nil {
return nil, err
}
/* encountered EOF */
if tk.tag == _T_end {
return val, nil
}
/* must be an operator */
if tk.tag != _T_punc {
return nil, newSyntaxError(tk.pos, "operators expected")
}
/* check for the operator precedence */
if op = int(tk.u64); !precedence[prec][op] {
self.pos = pp
return val, nil
}
/* evaluate the RHS operand, and combine the value */
if rv, err = self.expr(prec + 1, nest, repo); err != nil {
return nil, err
} else {
val = binaryOps[op](val, rv)
}
}
}
func (self *Parser) expr(prec int, nest int, repo Repository) (*Expr, error) {
if prec >= len(precedence) {
return self.unit(nest, repo)
} else {
return self.term(prec, nest, repo)
}
}
// Parse parses the expression, and returns it's AST tree.
func (self *Parser) Parse(repo Repository) (*Expr, error) {
return self.expr(0, 0, repo)
}
// SetSource resets the expression parser and sets the expression source.
func (self *Parser) SetSource(src string) *Parser {
self.pos = 0
self.src = []rune(src)
return self
}

View file

@ -1,251 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
`fmt`
)
// ISA represents an extension to x86-64 instruction set.
type ISA uint64
const (
ISA_CPUID ISA = 1 << iota
ISA_RDTSC
ISA_RDTSCP
ISA_CMOV
ISA_MOVBE
ISA_POPCNT
ISA_LZCNT
ISA_TBM
ISA_BMI
ISA_BMI2
ISA_ADX
ISA_MMX
ISA_MMX_PLUS
ISA_FEMMS
ISA_3DNOW
ISA_3DNOW_PLUS
ISA_SSE
ISA_SSE2
ISA_SSE3
ISA_SSSE3
ISA_SSE4A
ISA_SSE4_1
ISA_SSE4_2
ISA_FMA3
ISA_FMA4
ISA_XOP
ISA_F16C
ISA_AVX
ISA_AVX2
ISA_AVX512F
ISA_AVX512BW
ISA_AVX512DQ
ISA_AVX512VL
ISA_AVX512PF
ISA_AVX512ER
ISA_AVX512CD
ISA_AVX512VBMI
ISA_AVX512IFMA
ISA_AVX512VPOPCNTDQ
ISA_AVX512_4VNNIW
ISA_AVX512_4FMAPS
ISA_PREFETCH
ISA_PREFETCHW
ISA_PREFETCHWT1
ISA_CLFLUSH
ISA_CLFLUSHOPT
ISA_CLWB
ISA_CLZERO
ISA_RDRAND
ISA_RDSEED
ISA_PCLMULQDQ
ISA_AES
ISA_SHA
ISA_MONITOR
ISA_MONITORX
ISA_ALL = ^ISA(0)
)
var _ISA_NAMES = map[ISA]string {
ISA_CPUID : "CPUID",
ISA_RDTSC : "RDTSC",
ISA_RDTSCP : "RDTSCP",
ISA_CMOV : "CMOV",
ISA_MOVBE : "MOVBE",
ISA_POPCNT : "POPCNT",
ISA_LZCNT : "LZCNT",
ISA_TBM : "TBM",
ISA_BMI : "BMI",
ISA_BMI2 : "BMI2",
ISA_ADX : "ADX",
ISA_MMX : "MMX",
ISA_MMX_PLUS : "MMX+",
ISA_FEMMS : "FEMMS",
ISA_3DNOW : "3dnow!",
ISA_3DNOW_PLUS : "3dnow!+",
ISA_SSE : "SSE",
ISA_SSE2 : "SSE2",
ISA_SSE3 : "SSE3",
ISA_SSSE3 : "SSSE3",
ISA_SSE4A : "SSE4A",
ISA_SSE4_1 : "SSE4.1",
ISA_SSE4_2 : "SSE4.2",
ISA_FMA3 : "FMA3",
ISA_FMA4 : "FMA4",
ISA_XOP : "XOP",
ISA_F16C : "F16C",
ISA_AVX : "AVX",
ISA_AVX2 : "AVX2",
ISA_AVX512F : "AVX512F",
ISA_AVX512BW : "AVX512BW",
ISA_AVX512DQ : "AVX512DQ",
ISA_AVX512VL : "AVX512VL",
ISA_AVX512PF : "AVX512PF",
ISA_AVX512ER : "AVX512ER",
ISA_AVX512CD : "AVX512CD",
ISA_AVX512VBMI : "AVX512VBMI",
ISA_AVX512IFMA : "AVX512IFMA",
ISA_AVX512VPOPCNTDQ : "AVX512VPOPCNTDQ",
ISA_AVX512_4VNNIW : "AVX512_4VNNIW",
ISA_AVX512_4FMAPS : "AVX512_4FMAPS",
ISA_PREFETCH : "PREFETCH",
ISA_PREFETCHW : "PREFETCHW",
ISA_PREFETCHWT1 : "PREFETCHWT1",
ISA_CLFLUSH : "CLFLUSH",
ISA_CLFLUSHOPT : "CLFLUSHOPT",
ISA_CLWB : "CLWB",
ISA_CLZERO : "CLZERO",
ISA_RDRAND : "RDRAND",
ISA_RDSEED : "RDSEED",
ISA_PCLMULQDQ : "PCLMULQDQ",
ISA_AES : "AES",
ISA_SHA : "SHA",
ISA_MONITOR : "MONITOR",
ISA_MONITORX : "MONITORX",
}
var _ISA_MAPPING = map[string]ISA {
"CPUID" : ISA_CPUID,
"RDTSC" : ISA_RDTSC,
"RDTSCP" : ISA_RDTSCP,
"CMOV" : ISA_CMOV,
"MOVBE" : ISA_MOVBE,
"POPCNT" : ISA_POPCNT,
"LZCNT" : ISA_LZCNT,
"TBM" : ISA_TBM,
"BMI" : ISA_BMI,
"BMI2" : ISA_BMI2,
"ADX" : ISA_ADX,
"MMX" : ISA_MMX,
"MMX+" : ISA_MMX_PLUS,
"FEMMS" : ISA_FEMMS,
"3dnow!" : ISA_3DNOW,
"3dnow!+" : ISA_3DNOW_PLUS,
"SSE" : ISA_SSE,
"SSE2" : ISA_SSE2,
"SSE3" : ISA_SSE3,
"SSSE3" : ISA_SSSE3,
"SSE4A" : ISA_SSE4A,
"SSE4.1" : ISA_SSE4_1,
"SSE4.2" : ISA_SSE4_2,
"FMA3" : ISA_FMA3,
"FMA4" : ISA_FMA4,
"XOP" : ISA_XOP,
"F16C" : ISA_F16C,
"AVX" : ISA_AVX,
"AVX2" : ISA_AVX2,
"AVX512F" : ISA_AVX512F,
"AVX512BW" : ISA_AVX512BW,
"AVX512DQ" : ISA_AVX512DQ,
"AVX512VL" : ISA_AVX512VL,
"AVX512PF" : ISA_AVX512PF,
"AVX512ER" : ISA_AVX512ER,
"AVX512CD" : ISA_AVX512CD,
"AVX512VBMI" : ISA_AVX512VBMI,
"AVX512IFMA" : ISA_AVX512IFMA,
"AVX512VPOPCNTDQ" : ISA_AVX512VPOPCNTDQ,
"AVX512_4VNNIW" : ISA_AVX512_4VNNIW,
"AVX512_4FMAPS" : ISA_AVX512_4FMAPS,
"PREFETCH" : ISA_PREFETCH,
"PREFETCHW" : ISA_PREFETCHW,
"PREFETCHWT1" : ISA_PREFETCHWT1,
"CLFLUSH" : ISA_CLFLUSH,
"CLFLUSHOPT" : ISA_CLFLUSHOPT,
"CLWB" : ISA_CLWB,
"CLZERO" : ISA_CLZERO,
"RDRAND" : ISA_RDRAND,
"RDSEED" : ISA_RDSEED,
"PCLMULQDQ" : ISA_PCLMULQDQ,
"AES" : ISA_AES,
"SHA" : ISA_SHA,
"MONITOR" : ISA_MONITOR,
"MONITORX" : ISA_MONITORX,
}
func (self ISA) String() string {
if v, ok := _ISA_NAMES[self]; ok {
return v
} else {
return fmt.Sprintf("(invalid: %#x)", uint64(self))
}
}
// ParseISA parses name into ISA, it will panic if the name is invalid.
func ParseISA(name string) ISA {
if v, ok := _ISA_MAPPING[name]; ok {
return v
} else {
panic("invalid ISA name: " + name)
}
}
// Arch represents the x86_64 architecture.
type Arch struct {
isa ISA
}
// DefaultArch is the default architecture with all ISA enabled.
var DefaultArch = CreateArch()
// CreateArch creates a new Arch with all ISA enabled.
func CreateArch() *Arch {
return new(Arch).EnableISA(ISA_ALL)
}
// HasISA checks if a particular ISA was enabled.
func (self *Arch) HasISA(isa ISA) bool {
return (self.isa & isa) != 0
}
// EnableISA enables a particular ISA.
func (self *Arch) EnableISA(isa ISA) *Arch {
self.isa |= isa
return self
}
// DisableISA disables a particular ISA.
func (self *Arch) DisableISA(isa ISA) *Arch {
self.isa &^= isa
return self
}
// CreateProgram creates a new empty program.
func (self *Arch) CreateProgram() *Program {
return newProgram(self)
}

File diff suppressed because it is too large Load diff

View file

@ -1,49 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
func alias_INT3(p *Program, vv ...interface{}) *Instruction {
if len(vv) == 0 {
return p.INT(3)
} else {
panic("instruction INT3 takes no operands")
}
}
func alias_VCMPEQPS(p *Program, vv ...interface{}) *Instruction {
if len(vv) >= 3 {
return p.VCMPPS(0x00, vv[0], vv[1], vv[2], vv[3:]...)
} else {
panic("instruction VCMPEQPS takes 3 or 4 operands")
}
}
func alias_VCMPTRUEPS(p *Program, vv ...interface{}) *Instruction {
if len(vv) >= 3 {
return p.VCMPPS(0x0f, vv[0], vv[1], vv[2], vv[3:]...)
} else {
panic("instruction VCMPTRUEPS takes 3 or 4 operands")
}
}
var _InstructionAliases = map[string]_InstructionEncoder {
"int3" : alias_INT3,
"retq" : Instructions["ret"],
"movabsq" : Instructions["movq"],
"vcmpeqps" : alias_VCMPEQPS,
"vcmptrueps" : alias_VCMPTRUEPS,
}

View file

@ -1,691 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
`encoding/binary`
`math`
)
/** Operand Encoding Helpers **/
func imml(v interface{}) byte {
return byte(toImmAny(v) & 0x0f)
}
func relv(v interface{}) int64 {
switch r := v.(type) {
case *Label : return 0
case RelativeOffset : return int64(r)
default : panic("invalid relative offset")
}
}
func addr(v interface{}) interface{} {
switch a := v.(*MemoryOperand).Addr; a.Type {
case Memory : return a.Memory
case Offset : return a.Offset
case Reference : return a.Reference
default : panic("invalid memory operand type")
}
}
func bcode(v interface{}) byte {
if m, ok := v.(*MemoryOperand); !ok {
panic("v is not a memory operand")
} else if m.Broadcast == 0 {
return 0
} else {
return 1
}
}
func vcode(v interface{}) byte {
switch r := v.(type) {
case XMMRegister : return byte(r)
case YMMRegister : return byte(r)
case ZMMRegister : return byte(r)
case MaskedRegister : return vcode(r.Reg)
default : panic("v is not a vector register")
}
}
func kcode(v interface{}) byte {
switch r := v.(type) {
case KRegister : return byte(r)
case XMMRegister : return 0
case YMMRegister : return 0
case ZMMRegister : return 0
case RegisterMask : return byte(r.K)
case MaskedRegister : return byte(r.Mask.K)
case *MemoryOperand : return toKcodeMem(r)
default : panic("v is not a maskable operand")
}
}
func zcode(v interface{}) byte {
switch r := v.(type) {
case KRegister : return 0
case XMMRegister : return 0
case YMMRegister : return 0
case ZMMRegister : return 0
case RegisterMask : return toZcodeRegM(r)
case MaskedRegister : return toZcodeRegM(r.Mask)
case *MemoryOperand : return toZcodeMem(r)
default : panic("v is not a maskable operand")
}
}
func lcode(v interface{}) byte {
switch r := v.(type) {
case Register8 : return byte(r & 0x07)
case Register16 : return byte(r & 0x07)
case Register32 : return byte(r & 0x07)
case Register64 : return byte(r & 0x07)
case KRegister : return byte(r & 0x07)
case MMRegister : return byte(r & 0x07)
case XMMRegister : return byte(r & 0x07)
case YMMRegister : return byte(r & 0x07)
case ZMMRegister : return byte(r & 0x07)
case MaskedRegister : return lcode(r.Reg)
default : panic("v is not a register")
}
}
func hcode(v interface{}) byte {
switch r := v.(type) {
case Register8 : return byte(r >> 3) & 1
case Register16 : return byte(r >> 3) & 1
case Register32 : return byte(r >> 3) & 1
case Register64 : return byte(r >> 3) & 1
case KRegister : return byte(r >> 3) & 1
case MMRegister : return byte(r >> 3) & 1
case XMMRegister : return byte(r >> 3) & 1
case YMMRegister : return byte(r >> 3) & 1
case ZMMRegister : return byte(r >> 3) & 1
case MaskedRegister : return hcode(r.Reg)
default : panic("v is not a register")
}
}
func ecode(v interface{}) byte {
switch r := v.(type) {
case Register8 : return byte(r >> 4) & 1
case Register16 : return byte(r >> 4) & 1
case Register32 : return byte(r >> 4) & 1
case Register64 : return byte(r >> 4) & 1
case KRegister : return byte(r >> 4) & 1
case MMRegister : return byte(r >> 4) & 1
case XMMRegister : return byte(r >> 4) & 1
case YMMRegister : return byte(r >> 4) & 1
case ZMMRegister : return byte(r >> 4) & 1
case MaskedRegister : return ecode(r.Reg)
default : panic("v is not a register")
}
}
func hlcode(v interface{}) byte {
switch r := v.(type) {
case Register8 : return toHLcodeReg8(r)
case Register16 : return byte(r & 0x0f)
case Register32 : return byte(r & 0x0f)
case Register64 : return byte(r & 0x0f)
case KRegister : return byte(r & 0x0f)
case MMRegister : return byte(r & 0x0f)
case XMMRegister : return byte(r & 0x0f)
case YMMRegister : return byte(r & 0x0f)
case ZMMRegister : return byte(r & 0x0f)
case MaskedRegister : return hlcode(r.Reg)
default : panic("v is not a register")
}
}
func ehcode(v interface{}) byte {
switch r := v.(type) {
case Register8 : return byte(r >> 3) & 0x03
case Register16 : return byte(r >> 3) & 0x03
case Register32 : return byte(r >> 3) & 0x03
case Register64 : return byte(r >> 3) & 0x03
case KRegister : return byte(r >> 3) & 0x03
case MMRegister : return byte(r >> 3) & 0x03
case XMMRegister : return byte(r >> 3) & 0x03
case YMMRegister : return byte(r >> 3) & 0x03
case ZMMRegister : return byte(r >> 3) & 0x03
case MaskedRegister : return ehcode(r.Reg)
default : panic("v is not a register")
}
}
func toImmAny(v interface{}) int64 {
if x, ok := asInt64(v); ok {
return x
} else {
panic("value is not an integer")
}
}
func toHcodeOpt(v interface{}) byte {
if v == nil {
return 0
} else {
return hcode(v)
}
}
func toEcodeVMM(v interface{}, x byte) byte {
switch r := v.(type) {
case XMMRegister : return ecode(r)
case YMMRegister : return ecode(r)
case ZMMRegister : return ecode(r)
default : return x
}
}
func toKcodeMem(v *MemoryOperand) byte {
if !v.Masked {
return 0
} else {
return byte(v.Mask.K)
}
}
func toZcodeMem(v *MemoryOperand) byte {
if !v.Masked || v.Mask.Z {
return 0
} else {
return 1
}
}
func toZcodeRegM(v RegisterMask) byte {
if v.Z {
return 1
} else {
return 0
}
}
func toHLcodeReg8(v Register8) byte {
switch v {
case AH: fallthrough
case BH: fallthrough
case CH: fallthrough
case DH: panic("ah/bh/ch/dh registers never use 4-bit encoding")
default: return byte(v & 0x0f)
}
}
/** Instruction Encoding Helpers **/
const (
_N_inst = 16
)
const (
_F_rel1 = 1 << iota
_F_rel4
)
type _Encoding struct {
len int
flags int
bytes [_N_inst]byte
encoder func(m *_Encoding, v []interface{})
}
// buf ensures len + n <= len(bytes).
func (self *_Encoding) buf(n int) []byte {
if i := self.len; i + n > _N_inst {
panic("instruction too long")
} else {
return self.bytes[i:]
}
}
// emit encodes a single byte.
func (self *_Encoding) emit(v byte) {
self.buf(1)[0] = v
self.len++
}
// imm1 encodes a single byte immediate value.
func (self *_Encoding) imm1(v int64) {
self.emit(byte(v))
}
// imm2 encodes a two-byte immediate value in little-endian.
func (self *_Encoding) imm2(v int64) {
binary.LittleEndian.PutUint16(self.buf(2), uint16(v))
self.len += 2
}
// imm4 encodes a 4-byte immediate value in little-endian.
func (self *_Encoding) imm4(v int64) {
binary.LittleEndian.PutUint32(self.buf(4), uint32(v))
self.len += 4
}
// imm8 encodes an 8-byte immediate value in little-endian.
func (self *_Encoding) imm8(v int64) {
binary.LittleEndian.PutUint64(self.buf(8), uint64(v))
self.len += 8
}
// vex2 encodes a 2-byte or 3-byte VEX prefix.
//
// 2-byte VEX prefix:
// Requires: VEX.W = 0, VEX.mmmmm = 0b00001 and VEX.B = VEX.X = 0
// +----------------+
// Byte 0: | Bits 0-7: 0xc5 |
// +----------------+
//
// +-----------+----------------+----------+--------------+
// Byte 1: | Bit 7: ~R | Bits 3-6 ~vvvv | Bit 2: L | Bits 0-1: pp |
// +-----------+----------------+----------+--------------+
//
// 3-byte VEX prefix:
// +----------------+
// Byte 0: | Bits 0-7: 0xc4 |
// +----------------+
//
// +-----------+-----------+-----------+-------------------+
// Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: 0b00001 |
// +-----------+-----------+-----------+-------------------+
//
// +----------+-----------------+----------+--------------+
// Byte 2: | Bit 7: 0 | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
// +----------+-----------------+----------+--------------+
//
func (self *_Encoding) vex2(lpp byte, r byte, rm interface{}, vvvv byte) {
var b byte
var x byte
/* VEX.R must be a single-bit mask */
if r > 1 {
panic("VEX.R must be a 1-bit mask")
}
/* VEX.Lpp must be a 3-bit mask */
if lpp &^ 0b111 != 0 {
panic("VEX.Lpp must be a 3-bit mask")
}
/* VEX.vvvv must be a 4-bit mask */
if vvvv &^ 0b1111 != 0 {
panic("VEX.vvvv must be a 4-bit mask")
}
/* encode the RM bits if any */
if rm != nil {
switch v := rm.(type) {
case *Label : break
case Register : b = hcode(v)
case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset : break
default : panic("rm is expected to be a register or a memory address")
}
}
/* if VEX.B and VEX.X are zeroes, 2-byte VEX prefix can be used */
if x == 0 && b == 0 {
self.emit(0xc5)
self.emit(0xf8 ^ (r << 7) ^ (vvvv << 3) ^ lpp)
} else {
self.emit(0xc4)
self.emit(0xe1 ^ (r << 7) ^ (x << 6) ^ (b << 5))
self.emit(0x78 ^ (vvvv << 3) ^ lpp)
}
}
// vex3 encodes a 3-byte VEX or XOP prefix.
//
// 3-byte VEX/XOP prefix
// +-----------------------------------+
// Byte 0: | Bits 0-7: 0xc4 (VEX) / 0x8f (XOP) |
// +-----------------------------------+
//
// +-----------+-----------+-----------+-----------------+
// Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: mmmmm |
// +-----------+-----------+-----------+-----------------+
//
// +----------+-----------------+----------+--------------+
// Byte 2: | Bit 7: W | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
// +----------+-----------------+----------+--------------+
//
func (self *_Encoding) vex3(esc byte, mmmmm byte, wlpp byte, r byte, rm interface{}, vvvv byte) {
var b byte
var x byte
/* VEX.R must be a single-bit mask */
if r > 1 {
panic("VEX.R must be a 1-bit mask")
}
/* VEX.vvvv must be a 4-bit mask */
if vvvv &^ 0b1111 != 0 {
panic("VEX.vvvv must be a 4-bit mask")
}
/* escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix */
if esc != 0xc4 && esc != 0x8f {
panic("escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix")
}
/* VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7 */
if wlpp &^ 0b10000111 != 0 {
panic("VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7")
}
/* VEX.m-mmmm is expected to be a 5-bit mask */
if mmmmm &^ 0b11111 != 0 {
panic("VEX.m-mmmm is expected to be a 5-bit mask")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label : break
case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset : break
default : panic("rm is expected to be a register or a memory address")
}
/* encode the 3-byte VEX or XOP prefix */
self.emit(esc)
self.emit(0xe0 ^ (r << 7) ^ (x << 6) ^ (b << 5) ^ mmmmm)
self.emit(0x78 ^ (vvvv << 3) ^ wlpp)
}
// evex encodes a 4-byte EVEX prefix.
func (self *_Encoding) evex(mm byte, w1pp byte, ll byte, rr byte, rm interface{}, vvvvv byte, aaa byte, zz byte, bb byte) {
var b byte
var x byte
/* EVEX.b must be a single-bit mask */
if bb > 1 {
panic("EVEX.b must be a 1-bit mask")
}
/* EVEX.z must be a single-bit mask */
if zz > 1 {
panic("EVEX.z must be a 1-bit mask")
}
/* EVEX.mm must be a 2-bit mask */
if mm &^ 0b11 != 0 {
panic("EVEX.mm must be a 2-bit mask")
}
/* EVEX.L'L must be a 2-bit mask */
if ll &^ 0b11 != 0 {
panic("EVEX.L'L must be a 2-bit mask")
}
/* EVEX.R'R must be a 2-bit mask */
if rr &^ 0b11 != 0 {
panic("EVEX.R'R must be a 2-bit mask")
}
/* EVEX.aaa must be a 3-bit mask */
if aaa &^ 0b111 != 0 {
panic("EVEX.aaa must be a 3-bit mask")
}
/* EVEX.v'vvvv must be a 5-bit mask */
if vvvvv &^ 0b11111 != 0 {
panic("EVEX.v'vvvv must be a 5-bit mask")
}
/* EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7 */
if w1pp &^ 0b10000011 != 0b100 {
panic("EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7")
}
/* extract bits from EVEX.R'R and EVEX.v'vvvv */
r1, r0 := rr >> 1, rr & 1
v1, v0 := vvvvv >> 4, vvvvv & 0b1111
/* encode the RM bits if any */
if rm != nil {
switch m := rm.(type) {
case *Label : break
case Register : b, x = hcode(m), ecode(m)
case MemoryAddress : b, x, v1 = toHcodeOpt(m.Base), toHcodeOpt(m.Index), toEcodeVMM(m.Index, v1)
case RelativeOffset : break
default : panic("rm is expected to be a register or a memory address")
}
}
/* EVEX prefix bytes */
p0 := (r0 << 7) | (x << 6) | (b << 5) | (r1 << 4) | mm
p1 := (v0 << 3) | w1pp
p2 := (zz << 7) | (ll << 5) | (b << 4) | (v1 << 3) | aaa
/* p0: invert RXBR' (bits 4-7)
* p1: invert vvvv (bits 3-6)
* p2: invert V' (bit 3) */
self.emit(0x62)
self.emit(p0 ^ 0xf0)
self.emit(p1 ^ 0x78)
self.emit(p2 ^ 0x08)
}
// rexm encodes a mandatory REX prefix.
func (self *_Encoding) rexm(w byte, r byte, rm interface{}) {
var b byte
var x byte
/* REX.R must be 0 or 1 */
if r != 0 && r != 1 {
panic("REX.R must be 0 or 1")
}
/* REX.W must be 0 or 1 */
if w != 0 && w != 1 {
panic("REX.W must be 0 or 1")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label : break
case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset : break
default : panic("rm is expected to be a register or a memory address")
}
/* encode the REX prefix */
self.emit(0x40 | (w << 3) | (r << 2) | (x << 1) | b)
}
// rexo encodes an optional REX prefix.
func (self *_Encoding) rexo(r byte, rm interface{}, force bool) {
var b byte
var x byte
/* REX.R must be 0 or 1 */
if r != 0 && r != 1 {
panic("REX.R must be 0 or 1")
}
/* encode the RM bits */
switch v := rm.(type) {
case *Label : break
case Register : b = hcode(v)
case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
case RelativeOffset : break
default : panic("rm is expected to be a register or a memory address")
}
/* if REX.R, REX.X, and REX.B are all zeroes, REX prefix can be omitted */
if force || r != 0 || x != 0 || b != 0 {
self.emit(0x40 | (r << 2) | (x << 1) | b)
}
}
// mrsd encodes ModR/M, SIB and Displacement.
//
// ModR/M byte
// +----------------+---------------+---------------+
// | Bits 6-7: Mode | Bits 3-5: Reg | Bits 0-2: R/M |
// +----------------+---------------+---------------+
//
// SIB byte
// +-----------------+-----------------+----------------+
// | Bits 6-7: Scale | Bits 3-5: Index | Bits 0-2: Base |
// +-----------------+-----------------+----------------+
//
func (self *_Encoding) mrsd(reg byte, rm interface{}, disp8v int32) {
var ok bool
var mm MemoryAddress
var ro RelativeOffset
/* ModRM encodes the lower 3-bit of the register */
if reg > 7 {
panic("invalid register bits")
}
/* check the displacement scale */
switch disp8v {
case 1: break
case 2: break
case 4: break
case 8: break
case 16: break
case 32: break
case 64: break
default: panic("invalid displacement size")
}
/* special case: unresolved labels, assuming a zero offset */
if _, ok = rm.(*Label); ok {
self.emit(0x05 | (reg << 3))
self.imm4(0)
return
}
/* special case: RIP-relative offset
* ModRM.Mode == 0 and ModeRM.R/M == 5 indicates (rip + disp32) addressing */
if ro, ok = rm.(RelativeOffset); ok {
self.emit(0x05 | (reg << 3))
self.imm4(int64(ro))
return
}
/* must be a generic memory address */
if mm, ok = rm.(MemoryAddress); !ok {
panic("rm must be a memory address")
}
/* absolute addressing, encoded as disp(%rbp,%rsp,1) */
if mm.Base == nil && mm.Index == nil {
self.emit(0x04 | (reg << 3))
self.emit(0x25)
self.imm4(int64(mm.Displacement))
return
}
/* no SIB byte */
if mm.Index == nil && lcode(mm.Base) != 0b100 {
cc := lcode(mm.Base)
dv := mm.Displacement
/* ModRM.Mode == 0 (no displacement) */
if dv == 0 && mm.Base != RBP && mm.Base != R13 {
if cc == 0b101 {
panic("rbp/r13 is not encodable as a base register (interpreted as disp32 address)")
} else {
self.emit((reg << 3) | cc)
return
}
}
/* ModRM.Mode == 1 (8-bit displacement) */
if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
self.emit(0x40 | (reg << 3) | cc)
self.imm1(int64(dq))
return
}
/* ModRM.Mode == 2 (32-bit displacement) */
self.emit(0x80 | (reg << 3) | cc)
self.imm4(int64(mm.Displacement))
return
}
/* all encodings below use ModRM.R/M = 4 (0b100) to indicate the presence of SIB */
if mm.Index == RSP {
panic("rsp is not encodable as an index register (interpreted as no index)")
}
/* index = 4 (0b100) denotes no-index encoding */
var scale byte
var index byte = 0x04
/* encode the scale byte */
if mm.Scale != 0 {
switch mm.Scale {
case 1 : scale = 0
case 2 : scale = 1
case 4 : scale = 2
case 8 : scale = 3
default : panic("invalid scale value")
}
}
/* encode the index byte */
if mm.Index != nil {
index = lcode(mm.Index)
}
/* SIB.Base = 5 (0b101) and ModRM.Mode = 0 indicates no-base encoding with disp32 */
if mm.Base == nil {
self.emit((reg << 3) | 0b100)
self.emit((scale << 6) | (index << 3) | 0b101)
self.imm4(int64(mm.Displacement))
return
}
/* base L-code & displacement value */
cc := lcode(mm.Base)
dv := mm.Displacement
/* ModRM.Mode == 0 (no displacement) */
if dv == 0 && cc != 0b101 {
self.emit((reg << 3) | 0b100)
self.emit((scale << 6) | (index << 3) | cc)
return
}
/* ModRM.Mode == 1 (8-bit displacement) */
if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
self.emit(0x44 | (reg << 3))
self.emit((scale << 6) | (index << 3) | cc)
self.imm1(int64(dq))
return
}
/* ModRM.Mode == 2 (32-bit displacement) */
self.emit(0x84 | (reg << 3))
self.emit((scale << 6) | (index << 3) | cc)
self.imm4(int64(mm.Displacement))
}
// encode invokes the encoder to encode this instruction.
func (self *_Encoding) encode(v []interface{}) int {
self.len = 0
self.encoder(self, v)
return self.len
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,693 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
`fmt`
)
// Register represents a hardware register.
type Register interface {
fmt.Stringer
implRegister()
}
type (
Register8 byte
Register16 byte
Register32 byte
Register64 byte
)
type (
KRegister byte
MMRegister byte
XMMRegister byte
YMMRegister byte
ZMMRegister byte
)
// RegisterMask is a KRegister used to mask another register.
type RegisterMask struct {
Z bool
K KRegister
}
// String implements the fmt.Stringer interface.
func (self RegisterMask) String() string {
if !self.Z {
return fmt.Sprintf("{%%%s}", self.K)
} else {
return fmt.Sprintf("{%%%s}{z}", self.K)
}
}
// MaskedRegister is a Register masked by a RegisterMask.
type MaskedRegister struct {
Reg Register
Mask RegisterMask
}
// String implements the fmt.Stringer interface.
func (self MaskedRegister) String() string {
return self.Reg.String() + self.Mask.String()
}
const (
AL Register8 = iota
CL
DL
BL
SPL
BPL
SIL
DIL
R8b
R9b
R10b
R11b
R12b
R13b
R14b
R15b
)
const (
AH = SPL | 0x80
CH = BPL | 0x80
DH = SIL | 0x80
BH = DIL | 0x80
)
const (
AX Register16 = iota
CX
DX
BX
SP
BP
SI
DI
R8w
R9w
R10w
R11w
R12w
R13w
R14w
R15w
)
const (
EAX Register32 = iota
ECX
EDX
EBX
ESP
EBP
ESI
EDI
R8d
R9d
R10d
R11d
R12d
R13d
R14d
R15d
)
const (
RAX Register64 = iota
RCX
RDX
RBX
RSP
RBP
RSI
RDI
R8
R9
R10
R11
R12
R13
R14
R15
)
const (
K0 KRegister = iota
K1
K2
K3
K4
K5
K6
K7
)
const (
MM0 MMRegister = iota
MM1
MM2
MM3
MM4
MM5
MM6
MM7
)
const (
XMM0 XMMRegister = iota
XMM1
XMM2
XMM3
XMM4
XMM5
XMM6
XMM7
XMM8
XMM9
XMM10
XMM11
XMM12
XMM13
XMM14
XMM15
XMM16
XMM17
XMM18
XMM19
XMM20
XMM21
XMM22
XMM23
XMM24
XMM25
XMM26
XMM27
XMM28
XMM29
XMM30
XMM31
)
const (
YMM0 YMMRegister = iota
YMM1
YMM2
YMM3
YMM4
YMM5
YMM6
YMM7
YMM8
YMM9
YMM10
YMM11
YMM12
YMM13
YMM14
YMM15
YMM16
YMM17
YMM18
YMM19
YMM20
YMM21
YMM22
YMM23
YMM24
YMM25
YMM26
YMM27
YMM28
YMM29
YMM30
YMM31
)
const (
ZMM0 ZMMRegister = iota
ZMM1
ZMM2
ZMM3
ZMM4
ZMM5
ZMM6
ZMM7
ZMM8
ZMM9
ZMM10
ZMM11
ZMM12
ZMM13
ZMM14
ZMM15
ZMM16
ZMM17
ZMM18
ZMM19
ZMM20
ZMM21
ZMM22
ZMM23
ZMM24
ZMM25
ZMM26
ZMM27
ZMM28
ZMM29
ZMM30
ZMM31
)
func (self Register8) implRegister() {}
func (self Register16) implRegister() {}
func (self Register32) implRegister() {}
func (self Register64) implRegister() {}
func (self KRegister) implRegister() {}
func (self MMRegister) implRegister() {}
func (self XMMRegister) implRegister() {}
func (self YMMRegister) implRegister() {}
func (self ZMMRegister) implRegister() {}
func (self Register8) String() string { if int(self) >= len(r8names) { return "???" } else { return r8names[self] } }
func (self Register16) String() string { if int(self) >= len(r16names) { return "???" } else { return r16names[self] } }
func (self Register32) String() string { if int(self) >= len(r32names) { return "???" } else { return r32names[self] } }
func (self Register64) String() string { if int(self) >= len(r64names) { return "???" } else { return r64names[self] } }
func (self KRegister) String() string { if int(self) >= len(knames) { return "???" } else { return knames[self] } }
func (self MMRegister) String() string { if int(self) >= len(mmnames) { return "???" } else { return mmnames[self] } }
func (self XMMRegister) String() string { if int(self) >= len(xmmnames) { return "???" } else { return xmmnames[self] } }
func (self YMMRegister) String() string { if int(self) >= len(ymmnames) { return "???" } else { return ymmnames[self] } }
func (self ZMMRegister) String() string { if int(self) >= len(zmmnames) { return "???" } else { return zmmnames[self] } }
// Registers maps register name into Register instances.
var Registers = map[string]Register {
"al" : AL,
"cl" : CL,
"dl" : DL,
"bl" : BL,
"spl" : SPL,
"bpl" : BPL,
"sil" : SIL,
"dil" : DIL,
"r8b" : R8b,
"r9b" : R9b,
"r10b" : R10b,
"r11b" : R11b,
"r12b" : R12b,
"r13b" : R13b,
"r14b" : R14b,
"r15b" : R15b,
"ah" : AH,
"ch" : CH,
"dh" : DH,
"bh" : BH,
"ax" : AX,
"cx" : CX,
"dx" : DX,
"bx" : BX,
"sp" : SP,
"bp" : BP,
"si" : SI,
"di" : DI,
"r8w" : R8w,
"r9w" : R9w,
"r10w" : R10w,
"r11w" : R11w,
"r12w" : R12w,
"r13w" : R13w,
"r14w" : R14w,
"r15w" : R15w,
"eax" : EAX,
"ecx" : ECX,
"edx" : EDX,
"ebx" : EBX,
"esp" : ESP,
"ebp" : EBP,
"esi" : ESI,
"edi" : EDI,
"r8d" : R8d,
"r9d" : R9d,
"r10d" : R10d,
"r11d" : R11d,
"r12d" : R12d,
"r13d" : R13d,
"r14d" : R14d,
"r15d" : R15d,
"rax" : RAX,
"rcx" : RCX,
"rdx" : RDX,
"rbx" : RBX,
"rsp" : RSP,
"rbp" : RBP,
"rsi" : RSI,
"rdi" : RDI,
"r8" : R8,
"r9" : R9,
"r10" : R10,
"r11" : R11,
"r12" : R12,
"r13" : R13,
"r14" : R14,
"r15" : R15,
"k0" : K0,
"k1" : K1,
"k2" : K2,
"k3" : K3,
"k4" : K4,
"k5" : K5,
"k6" : K6,
"k7" : K7,
"mm0" : MM0,
"mm1" : MM1,
"mm2" : MM2,
"mm3" : MM3,
"mm4" : MM4,
"mm5" : MM5,
"mm6" : MM6,
"mm7" : MM7,
"xmm0" : XMM0,
"xmm1" : XMM1,
"xmm2" : XMM2,
"xmm3" : XMM3,
"xmm4" : XMM4,
"xmm5" : XMM5,
"xmm6" : XMM6,
"xmm7" : XMM7,
"xmm8" : XMM8,
"xmm9" : XMM9,
"xmm10" : XMM10,
"xmm11" : XMM11,
"xmm12" : XMM12,
"xmm13" : XMM13,
"xmm14" : XMM14,
"xmm15" : XMM15,
"xmm16" : XMM16,
"xmm17" : XMM17,
"xmm18" : XMM18,
"xmm19" : XMM19,
"xmm20" : XMM20,
"xmm21" : XMM21,
"xmm22" : XMM22,
"xmm23" : XMM23,
"xmm24" : XMM24,
"xmm25" : XMM25,
"xmm26" : XMM26,
"xmm27" : XMM27,
"xmm28" : XMM28,
"xmm29" : XMM29,
"xmm30" : XMM30,
"xmm31" : XMM31,
"ymm0" : YMM0,
"ymm1" : YMM1,
"ymm2" : YMM2,
"ymm3" : YMM3,
"ymm4" : YMM4,
"ymm5" : YMM5,
"ymm6" : YMM6,
"ymm7" : YMM7,
"ymm8" : YMM8,
"ymm9" : YMM9,
"ymm10" : YMM10,
"ymm11" : YMM11,
"ymm12" : YMM12,
"ymm13" : YMM13,
"ymm14" : YMM14,
"ymm15" : YMM15,
"ymm16" : YMM16,
"ymm17" : YMM17,
"ymm18" : YMM18,
"ymm19" : YMM19,
"ymm20" : YMM20,
"ymm21" : YMM21,
"ymm22" : YMM22,
"ymm23" : YMM23,
"ymm24" : YMM24,
"ymm25" : YMM25,
"ymm26" : YMM26,
"ymm27" : YMM27,
"ymm28" : YMM28,
"ymm29" : YMM29,
"ymm30" : YMM30,
"ymm31" : YMM31,
"zmm0" : ZMM0,
"zmm1" : ZMM1,
"zmm2" : ZMM2,
"zmm3" : ZMM3,
"zmm4" : ZMM4,
"zmm5" : ZMM5,
"zmm6" : ZMM6,
"zmm7" : ZMM7,
"zmm8" : ZMM8,
"zmm9" : ZMM9,
"zmm10" : ZMM10,
"zmm11" : ZMM11,
"zmm12" : ZMM12,
"zmm13" : ZMM13,
"zmm14" : ZMM14,
"zmm15" : ZMM15,
"zmm16" : ZMM16,
"zmm17" : ZMM17,
"zmm18" : ZMM18,
"zmm19" : ZMM19,
"zmm20" : ZMM20,
"zmm21" : ZMM21,
"zmm22" : ZMM22,
"zmm23" : ZMM23,
"zmm24" : ZMM24,
"zmm25" : ZMM25,
"zmm26" : ZMM26,
"zmm27" : ZMM27,
"zmm28" : ZMM28,
"zmm29" : ZMM29,
"zmm30" : ZMM30,
"zmm31" : ZMM31,
}
/** Register Name Tables **/
var r8names = [...]string {
AL : "al",
CL : "cl",
DL : "dl",
BL : "bl",
SPL : "spl",
BPL : "bpl",
SIL : "sil",
DIL : "dil",
R8b : "r8b",
R9b : "r9b",
R10b : "r10b",
R11b : "r11b",
R12b : "r12b",
R13b : "r13b",
R14b : "r14b",
R15b : "r15b",
AH : "ah",
CH : "ch",
DH : "dh",
BH : "bh",
}
var r16names = [...]string {
AX : "ax",
CX : "cx",
DX : "dx",
BX : "bx",
SP : "sp",
BP : "bp",
SI : "si",
DI : "di",
R8w : "r8w",
R9w : "r9w",
R10w : "r10w",
R11w : "r11w",
R12w : "r12w",
R13w : "r13w",
R14w : "r14w",
R15w : "r15w",
}
var r32names = [...]string {
EAX : "eax",
ECX : "ecx",
EDX : "edx",
EBX : "ebx",
ESP : "esp",
EBP : "ebp",
ESI : "esi",
EDI : "edi",
R8d : "r8d",
R9d : "r9d",
R10d : "r10d",
R11d : "r11d",
R12d : "r12d",
R13d : "r13d",
R14d : "r14d",
R15d : "r15d",
}
var r64names = [...]string {
RAX : "rax",
RCX : "rcx",
RDX : "rdx",
RBX : "rbx",
RSP : "rsp",
RBP : "rbp",
RSI : "rsi",
RDI : "rdi",
R8 : "r8",
R9 : "r9",
R10 : "r10",
R11 : "r11",
R12 : "r12",
R13 : "r13",
R14 : "r14",
R15 : "r15",
}
var knames = [...]string {
K0: "k0",
K1: "k1",
K2: "k2",
K3: "k3",
K4: "k4",
K5: "k5",
K6: "k6",
K7: "k7",
}
var mmnames = [...]string {
MM0: "mm0",
MM1: "mm1",
MM2: "mm2",
MM3: "mm3",
MM4: "mm4",
MM5: "mm5",
MM6: "mm6",
MM7: "mm7",
}
var xmmnames = [...]string {
XMM0 : "xmm0",
XMM1 : "xmm1",
XMM2 : "xmm2",
XMM3 : "xmm3",
XMM4 : "xmm4",
XMM5 : "xmm5",
XMM6 : "xmm6",
XMM7 : "xmm7",
XMM8 : "xmm8",
XMM9 : "xmm9",
XMM10 : "xmm10",
XMM11 : "xmm11",
XMM12 : "xmm12",
XMM13 : "xmm13",
XMM14 : "xmm14",
XMM15 : "xmm15",
XMM16 : "xmm16",
XMM17 : "xmm17",
XMM18 : "xmm18",
XMM19 : "xmm19",
XMM20 : "xmm20",
XMM21 : "xmm21",
XMM22 : "xmm22",
XMM23 : "xmm23",
XMM24 : "xmm24",
XMM25 : "xmm25",
XMM26 : "xmm26",
XMM27 : "xmm27",
XMM28 : "xmm28",
XMM29 : "xmm29",
XMM30 : "xmm30",
XMM31 : "xmm31",
}
var ymmnames = [...]string {
YMM0 : "ymm0",
YMM1 : "ymm1",
YMM2 : "ymm2",
YMM3 : "ymm3",
YMM4 : "ymm4",
YMM5 : "ymm5",
YMM6 : "ymm6",
YMM7 : "ymm7",
YMM8 : "ymm8",
YMM9 : "ymm9",
YMM10 : "ymm10",
YMM11 : "ymm11",
YMM12 : "ymm12",
YMM13 : "ymm13",
YMM14 : "ymm14",
YMM15 : "ymm15",
YMM16 : "ymm16",
YMM17 : "ymm17",
YMM18 : "ymm18",
YMM19 : "ymm19",
YMM20 : "ymm20",
YMM21 : "ymm21",
YMM22 : "ymm22",
YMM23 : "ymm23",
YMM24 : "ymm24",
YMM25 : "ymm25",
YMM26 : "ymm26",
YMM27 : "ymm27",
YMM28 : "ymm28",
YMM29 : "ymm29",
YMM30 : "ymm30",
YMM31 : "ymm31",
}
var zmmnames = [...]string {
ZMM0 : "zmm0",
ZMM1 : "zmm1",
ZMM2 : "zmm2",
ZMM3 : "zmm3",
ZMM4 : "zmm4",
ZMM5 : "zmm5",
ZMM6 : "zmm6",
ZMM7 : "zmm7",
ZMM8 : "zmm8",
ZMM9 : "zmm9",
ZMM10 : "zmm10",
ZMM11 : "zmm11",
ZMM12 : "zmm12",
ZMM13 : "zmm13",
ZMM14 : "zmm14",
ZMM15 : "zmm15",
ZMM16 : "zmm16",
ZMM17 : "zmm17",
ZMM18 : "zmm18",
ZMM19 : "zmm19",
ZMM20 : "zmm20",
ZMM21 : "zmm21",
ZMM22 : "zmm22",
ZMM23 : "zmm23",
ZMM24 : "zmm24",
ZMM25 : "zmm25",
ZMM26 : "zmm26",
ZMM27 : "zmm27",
ZMM28 : "zmm28",
ZMM29 : "zmm29",
ZMM30 : "zmm30",
ZMM31 : "zmm31",
}

View file

@ -1,147 +0,0 @@
//
// Copyright 2024 CloudWeGo 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 x86_64
import (
`encoding/binary`
`errors`
`reflect`
`strconv`
`unicode/utf8`
`unsafe`
)
const (
_CC_digit = 1 << iota
_CC_ident
_CC_ident0
_CC_number
)
func ispow2(v uint64) bool {
return (v & (v - 1)) == 0
}
func isdigit(cc rune) bool {
return '0' <= cc && cc <= '9'
}
func isalpha(cc rune) bool {
return (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')
}
func isident(cc rune) bool {
return cc == '_' || isalpha(cc) || isdigit(cc)
}
func isident0(cc rune) bool {
return cc == '_' || isalpha(cc)
}
func isnumber(cc rune) bool {
return (cc == 'b' || cc == 'B') ||
(cc == 'o' || cc == 'O') ||
(cc == 'x' || cc == 'X') ||
(cc >= '0' && cc <= '9') ||
(cc >= 'a' && cc <= 'f') ||
(cc >= 'A' && cc <= 'F')
}
func align(v int, n int) int {
return (((v - 1) >> n) + 1) << n
}
func append8(m *[]byte, v byte) {
*m = append(*m, v)
}
func append16(m *[]byte, v uint16) {
p := len(*m)
*m = append(*m, 0, 0)
binary.LittleEndian.PutUint16((*m)[p:], v)
}
func append32(m *[]byte, v uint32) {
p := len(*m)
*m = append(*m, 0, 0, 0, 0)
binary.LittleEndian.PutUint32((*m)[p:], v)
}
func append64(m *[]byte, v uint64) {
p := len(*m)
*m = append(*m, 0, 0, 0, 0, 0, 0, 0, 0)
binary.LittleEndian.PutUint64((*m)[p:], v)
}
func expandmm(m *[]byte, n int, v byte) {
sl := (*_GoSlice)(unsafe.Pointer(m))
nb := sl.len + n
/* grow as needed */
if nb > cap(*m) {
*m = growslice(byteType, *m, nb)
}
/* fill the new area */
memset(unsafe.Pointer(uintptr(sl.ptr) + uintptr(sl.len)), v, uintptr(n))
sl.len = nb
}
func memset(p unsafe.Pointer, c byte, n uintptr) {
if c != 0 {
memsetv(p, c, n)
} else {
memclrNoHeapPointers(p, n)
}
}
func memsetv(p unsafe.Pointer, c byte, n uintptr) {
for i := uintptr(0); i < n; i++ {
*(*byte)(unsafe.Pointer(uintptr(p) + i)) = c
}
}
func literal64(v string) (uint64, error) {
var nb int
var ch rune
var ex error
var mm [12]byte
/* unquote the runes */
for v != "" {
if ch, _, v, ex = strconv.UnquoteChar(v, '\''); ex != nil {
return 0, ex
} else if nb += utf8.EncodeRune(mm[nb:], ch); nb > 8 {
return 0, errors.New("multi-char constant too large")
}
}
/* convert to uint64 */
return *(*uint64)(unsafe.Pointer(&mm)), nil
}
var (
byteWrap = reflect.TypeOf(byte(0))
byteType = (*_GoType)(efaceOf(byteWrap).ptr)
)
//go:linkname growslice runtime.growslice
func growslice(_ *_GoType, _ []byte, _ int) []byte
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
func memclrNoHeapPointers(_ unsafe.Pointer, _ uintptr)

View file

@ -52,10 +52,15 @@ func InstallShieldCab(raw []byte, _ uint32) bool {
} }
// Zstd matches a Zstandard archive file. // Zstd matches a Zstandard archive file.
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md
func Zstd(raw []byte, limit uint32) bool { func Zstd(raw []byte, limit uint32) bool {
return len(raw) >= 4 && if len(raw) < 4 {
(0x22 <= raw[0] && raw[0] <= 0x28 || raw[0] == 0x1E) && // Different Zstandard versions. return false
bytes.HasPrefix(raw[1:], []byte{0xB5, 0x2F, 0xFD}) }
sig := binary.LittleEndian.Uint32(raw)
// Check for Zstandard frames and skippable frames.
return (sig >= 0xFD2FB522 && sig <= 0xFD2FB528) ||
(sig >= 0x184D2A50 && sig <= 0x184D2A5F)
} }
// CRX matches a Chrome extension file: a zip archive prepended by a package header. // CRX matches a Chrome extension file: a zip archive prepended by a package header.

View file

@ -110,3 +110,22 @@ func zipContains(raw, sig []byte, msoCheck bool) bool {
} }
return false return false
} }
// APK matches an Android Package Archive.
// The source of signatures is https://github.com/file/file/blob/1778642b8ba3d947a779a36fcd81f8e807220a19/magic/Magdir/archive#L1820-L1887
func APK(raw []byte, _ uint32) bool {
apkSignatures := [][]byte{
[]byte("AndroidManifest.xml"),
[]byte("META-INF/com/android/build/gradle/app-metadata.properties"),
[]byte("classes.dex"),
[]byte("resources.arsc"),
[]byte("res/drawable"),
}
for _, sig := range apkSignatures {
if zipContains(raw, sig, false) {
return true
}
}
return false
}

View file

@ -1,4 +1,4 @@
## 177 Supported MIME types ## 178 Supported MIME types
This file is automatically generated when running tests. Do not edit manually. This file is automatically generated when running tests. Do not edit manually.
Extension | MIME type | Aliases Extension | MIME type | Aliases
@ -11,6 +11,7 @@ Extension | MIME type | Aliases
**.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | - **.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | -
**.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | - **.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | -
**.epub** | application/epub+zip | - **.epub** | application/epub+zip | -
**.apk** | application/vnd.android.package-archive | -
**.jar** | application/jar | - **.jar** | application/jar | -
**.odt** | application/vnd.oasis.opendocument.text | application/x-vnd.oasis.opendocument.text **.odt** | application/vnd.oasis.opendocument.text | application/x-vnd.oasis.opendocument.text
**.ott** | application/vnd.oasis.opendocument.text-template | application/x-vnd.oasis.opendocument.text-template **.ott** | application/vnd.oasis.opendocument.text-template | application/x-vnd.oasis.opendocument.text-template

View file

@ -44,7 +44,11 @@ func([]byte, uint32) bool { return true },
"application/gzip-compressed", "application/x-gzip-compressed", "application/gzip-compressed", "application/x-gzip-compressed",
"gzip/document") "gzip/document")
sevenZ = newMIME("application/x-7z-compressed", ".7z", magic.SevenZ) sevenZ = newMIME("application/x-7z-compressed", ".7z", magic.SevenZ)
zip = newMIME("application/zip", ".zip", magic.Zip, xlsx, docx, pptx, epub, jar, odt, ods, odp, odg, odf, odc, sxc). // APK must be checked before JAR because APK is a subset of JAR.
// This means APK should be a child of JAR detector, but in practice,
// the decisive signature for JAR might be located at the end of the file
// and not reachable because of library readLimit.
zip = newMIME("application/zip", ".zip", magic.Zip, xlsx, docx, pptx, epub, apk, jar, odt, ods, odp, odg, odf, odc, sxc).
alias("application/x-zip", "application/x-zip-compressed") alias("application/x-zip", "application/x-zip-compressed")
tar = newMIME("application/x-tar", ".tar", magic.Tar) tar = newMIME("application/x-tar", ".tar", magic.Tar)
xar = newMIME("application/x-xar", ".xar", magic.Xar) xar = newMIME("application/x-xar", ".xar", magic.Xar)
@ -57,6 +61,7 @@ func([]byte, uint32) bool { return true },
pptx = newMIME("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx", magic.Pptx) pptx = newMIME("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx", magic.Pptx)
epub = newMIME("application/epub+zip", ".epub", magic.Epub) epub = newMIME("application/epub+zip", ".epub", magic.Epub)
jar = newMIME("application/jar", ".jar", magic.Jar) jar = newMIME("application/jar", ".jar", magic.Jar)
apk = newMIME("application/vnd.android.package-archive", ".apk", magic.APK)
ole = newMIME("application/x-ole-storage", "", magic.Ole, msi, aaf, msg, xls, pub, ppt, doc) ole = newMIME("application/x-ole-storage", "", magic.Ole, msi, aaf, msg, xls, pub, ppt, doc)
msi = newMIME("application/x-ms-installer", ".msi", magic.Msi). msi = newMIME("application/x-ms-installer", ".msi", magic.Msi).
alias("application/x-windows-installer", "application/x-msi") alias("application/x-windows-installer", "application/x-msi")

View file

@ -49,7 +49,7 @@ func main() {
} }
``` ```
Customized Excluded Extensions ### Customized Excluded Extensions
```go ```go
package main package main
@ -77,7 +77,7 @@ func main() {
} }
``` ```
Customized Excluded Paths ### Customized Excluded Paths
```go ```go
package main package main
@ -105,7 +105,7 @@ func main() {
} }
``` ```
Customized Excluded Paths ### Customized Excluded Paths with Regex
```go ```go
package main package main
@ -132,3 +132,38 @@ func main() {
} }
} }
``` ```
### Server Push
```go
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(gzip.Gzip(gzip.DefaultCompression))
r.GET("/stream", func(c *gin.Context) {
c.Header("Content-Type", "text/event-stream")
c.Header("Connection", "keep-alive")
for i := 0; i < 10; i++ {
fmt.Fprintf(c.Writer, "id: %d\ndata: tick %d\n\n", i, time.Now().Unix())
c.Writer.Flush()
time.Sleep(1 * time.Second)
}
})
// Listen and Server in 0.0.0.0:8080
if err := r.Run(":8080"); err != nil {
log.Fatal(err)
}
}
```

View file

@ -1,7 +1,11 @@
package gzip package gzip
import ( import (
"bufio"
"compress/gzip" "compress/gzip"
"errors"
"net"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -11,6 +15,7 @@
BestSpeed = gzip.BestSpeed BestSpeed = gzip.BestSpeed
DefaultCompression = gzip.DefaultCompression DefaultCompression = gzip.DefaultCompression
NoCompression = gzip.NoCompression NoCompression = gzip.NoCompression
HuffmanOnly = gzip.HuffmanOnly
) )
func Gzip(level int, options ...Option) gin.HandlerFunc { func Gzip(level int, options ...Option) gin.HandlerFunc {
@ -32,8 +37,31 @@ func (g *gzipWriter) Write(data []byte) (int, error) {
return g.writer.Write(data) return g.writer.Write(data)
} }
func (g *gzipWriter) Flush() {
_ = g.writer.Flush()
g.ResponseWriter.Flush()
}
// Fix: https://github.com/mholt/caddy/issues/38 // Fix: https://github.com/mholt/caddy/issues/38
func (g *gzipWriter) WriteHeader(code int) { func (g *gzipWriter) WriteHeader(code int) {
g.Header().Del("Content-Length") g.Header().Del("Content-Length")
g.ResponseWriter.WriteHeader(code) g.ResponseWriter.WriteHeader(code)
} }
// Ensure gzipWriter implements the http.Hijacker interface.
// This will cause a compile-time error if gzipWriter does not implement all methods of the http.Hijacker interface.
var _ http.Hijacker = (*gzipWriter)(nil)
// Hijack allows the caller to take over the connection from the HTTP server.
// After a call to Hijack, the HTTP server library will not do anything else with the connection.
// It becomes the caller's responsibility to manage and close the connection.
//
// It returns the underlying net.Conn, a buffered reader/writer for the connection, and an error
// if the ResponseWriter does not support the Hijacker interface.
func (g *gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := g.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface")
}
return hijacker.Hijack()
}

View file

@ -2,84 +2,114 @@
import ( import (
"compress/gzip" "compress/gzip"
"fmt"
"io" "io"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"sync" "sync"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
const (
headerAcceptEncoding = "Accept-Encoding"
headerContentEncoding = "Content-Encoding"
headerVary = "Vary"
)
type gzipHandler struct { type gzipHandler struct {
*Options *config
gzPool sync.Pool gzPool sync.Pool
} }
func newGzipHandler(level int, options ...Option) *gzipHandler { func isCompressionLevelValid(level int) bool {
return level == gzip.DefaultCompression ||
level == gzip.NoCompression ||
(level >= gzip.BestSpeed && level <= gzip.BestCompression)
}
func newGzipHandler(level int, opts ...Option) *gzipHandler {
cfg := &config{
excludedExtensions: DefaultExcludedExtentions,
}
// Apply each option to the config
for _, o := range opts {
o.apply(cfg)
}
if !isCompressionLevelValid(level) {
// For web content, level 4 seems to be a sweet spot.
level = 4
}
handler := &gzipHandler{ handler := &gzipHandler{
Options: DefaultOptions, config: cfg,
gzPool: sync.Pool{ gzPool: sync.Pool{
New: func() interface{} { New: func() interface{} {
gz, err := gzip.NewWriterLevel(io.Discard, level) gz, _ := gzip.NewWriterLevel(io.Discard, level)
if err != nil {
panic(err)
}
return gz return gz
}, },
}, },
} }
for _, setter := range options {
setter(handler.Options)
}
return handler return handler
} }
// Handle is a middleware function for handling gzip compression in HTTP requests and responses.
// It first checks if the request has a "Content-Encoding" header set to "gzip" and if a decompression
// function is provided, it will call the decompression function. If the handler is set to decompress only,
// or if the custom compression decision function indicates not to compress, it will return early.
// Otherwise, it retrieves a gzip.Writer from the pool, sets the necessary response headers for gzip encoding,
// and wraps the response writer with a gzipWriter. After the request is processed, it ensures the gzip.Writer
// is properly closed and the "Content-Length" header is set based on the response size.
func (g *gzipHandler) Handle(c *gin.Context) { func (g *gzipHandler) Handle(c *gin.Context) {
if fn := g.DecompressFn; fn != nil && c.Request.Header.Get("Content-Encoding") == "gzip" { if fn := g.decompressFn; fn != nil && strings.Contains(c.Request.Header.Get("Content-Encoding"), "gzip") {
fn(c) fn(c)
} }
if !g.shouldCompress(c.Request) { if g.decompressOnly ||
(g.customShouldCompressFn != nil && !g.customShouldCompressFn(c)) ||
(g.customShouldCompressFn == nil && !g.shouldCompress(c.Request)) {
return return
} }
gz := g.gzPool.Get().(*gzip.Writer) gz := g.gzPool.Get().(*gzip.Writer)
defer g.gzPool.Put(gz)
defer gz.Reset(io.Discard)
gz.Reset(c.Writer) gz.Reset(c.Writer)
c.Header("Content-Encoding", "gzip") c.Header(headerContentEncoding, "gzip")
c.Header("Vary", "Accept-Encoding") c.Writer.Header().Add(headerVary, headerAcceptEncoding)
// check ETag Header
originalEtag := c.GetHeader("ETag")
if originalEtag != "" && !strings.HasPrefix(originalEtag, "W/") {
c.Header("ETag", "W/"+originalEtag)
}
c.Writer = &gzipWriter{c.Writer, gz} c.Writer = &gzipWriter{c.Writer, gz}
defer func() { defer func() {
if c.Writer.Size() < 0 { if c.Writer.Size() < 0 {
// do not write gzip footer when nothing is written to the response body // do not write gzip footer when nothing is written to the response body
gz.Reset(io.Discard) gz.Reset(io.Discard)
} }
gz.Close() _ = gz.Close()
c.Header("Content-Length", fmt.Sprint(c.Writer.Size())) if c.Writer.Size() > -1 {
c.Header("Content-Length", strconv.Itoa(c.Writer.Size()))
}
g.gzPool.Put(gz)
}() }()
c.Next() c.Next()
} }
func (g *gzipHandler) shouldCompress(req *http.Request) bool { func (g *gzipHandler) shouldCompress(req *http.Request) bool {
if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") || if !strings.Contains(req.Header.Get(headerAcceptEncoding), "gzip") ||
strings.Contains(req.Header.Get("Connection"), "Upgrade") || strings.Contains(req.Header.Get("Connection"), "Upgrade") {
strings.Contains(req.Header.Get("Accept"), "text/event-stream") {
return false return false
} }
// Check if the request path is excluded from compression
extension := filepath.Ext(req.URL.Path) extension := filepath.Ext(req.URL.Path)
if g.ExcludedExtensions.Contains(extension) { if g.excludedExtensions.Contains(extension) ||
return false g.excludedPaths.Contains(req.URL.Path) ||
} g.excludedPathesRegexs.Contains(req.URL.Path) {
if g.ExcludedPaths.Contains(req.URL.Path) {
return false
}
if g.ExcludedPathesRegexs.Contains(req.URL.Path) {
return false return false
} }

View file

@ -2,6 +2,8 @@
import ( import (
"compress/gzip" "compress/gzip"
"errors"
"io"
"net/http" "net/http"
"regexp" "regexp"
"strings" "strings"
@ -10,58 +12,134 @@
) )
var ( var (
// DefaultExcludedExtentions is a predefined list of file extensions that should be excluded from gzip compression.
// These extensions typically represent image files that are already compressed
// and do not benefit from additional compression.
DefaultExcludedExtentions = NewExcludedExtensions([]string{ DefaultExcludedExtentions = NewExcludedExtensions([]string{
".png", ".gif", ".jpeg", ".jpg", ".png", ".gif", ".jpeg", ".jpg",
}) })
DefaultOptions = &Options{ // ErrUnsupportedContentEncoding is an error that indicates the content encoding
ExcludedExtensions: DefaultExcludedExtentions, // is not supported by the application.
} ErrUnsupportedContentEncoding = errors.New("unsupported content encoding")
) )
type Options struct { // Option is an interface that defines a method to apply a configuration
ExcludedExtensions ExcludedExtensions // to a given config instance. Implementations of this interface can be
ExcludedPaths ExcludedPaths // used to modify the configuration settings of the logger.
ExcludedPathesRegexs ExcludedPathesRegexs type Option interface {
DecompressFn func(c *gin.Context) apply(*config)
} }
type Option func(*Options) // Ensures that optionFunc implements the Option interface at compile time.
// If optionFunc does not implement Option, a compile-time error will occur.
var _ Option = (*optionFunc)(nil)
type optionFunc func(*config)
func (o optionFunc) apply(c *config) {
o(c)
}
type config struct {
excludedExtensions ExcludedExtensions
excludedPaths ExcludedPaths
excludedPathesRegexs ExcludedPathesRegexs
decompressFn func(c *gin.Context)
decompressOnly bool
customShouldCompressFn func(c *gin.Context) bool
}
// WithExcludedExtensions returns an Option that sets the ExcludedExtensions field of the Options struct.
// Parameters:
// - args: []string - A slice of file extensions to exclude from gzip compression.
func WithExcludedExtensions(args []string) Option { func WithExcludedExtensions(args []string) Option {
return func(o *Options) { return optionFunc(func(o *config) {
o.ExcludedExtensions = NewExcludedExtensions(args) o.excludedExtensions = NewExcludedExtensions(args)
} })
} }
// WithExcludedPaths returns an Option that sets the ExcludedPaths field of the Options struct.
// Parameters:
// - args: []string - A slice of paths to exclude from gzip compression.
func WithExcludedPaths(args []string) Option { func WithExcludedPaths(args []string) Option {
return func(o *Options) { return optionFunc(func(o *config) {
o.ExcludedPaths = NewExcludedPaths(args) o.excludedPaths = NewExcludedPaths(args)
} })
} }
// WithExcludedPathsRegexs returns an Option that sets the ExcludedPathesRegexs field of the Options struct.
// Parameters:
// - args: []string - A slice of regex patterns to exclude paths from gzip compression.
func WithExcludedPathsRegexs(args []string) Option { func WithExcludedPathsRegexs(args []string) Option {
return func(o *Options) { return optionFunc(func(o *config) {
o.ExcludedPathesRegexs = NewExcludedPathesRegexs(args) o.excludedPathesRegexs = NewExcludedPathesRegexs(args)
} })
} }
// WithDecompressFn returns an Option that sets the DecompressFn field of the Options struct.
// Parameters:
// - decompressFn: func(c *gin.Context) - A function to handle decompression of incoming requests.
func WithDecompressFn(decompressFn func(c *gin.Context)) Option { func WithDecompressFn(decompressFn func(c *gin.Context)) Option {
return func(o *Options) { return optionFunc(func(o *config) {
o.DecompressFn = decompressFn o.decompressFn = decompressFn
} })
}
// WithDecompressOnly is an option that configures the gzip middleware to only
// decompress incoming requests without compressing the responses. When this
// option is enabled, the middleware will set the DecompressOnly field of the
// Options struct to true.
func WithDecompressOnly() Option {
return optionFunc(func(o *config) {
o.decompressOnly = true
})
}
// WithCustomShouldCompressFn returns an Option that sets the CustomShouldCompressFn field of the Options struct.
// Parameters:
// - fn: func(c *gin.Context) bool - A function to determine if a request should be compressed.
// The function should return true if the request should be compressed, false otherwise.
// If the function returns false, the middleware will not compress the response.
// If the function is nil, the middleware will use the default logic to determine
// if the response should be compressed.
//
// Returns:
// - Option - An option that sets the CustomShouldCompressFn field of the Options struct.
//
// Example:
//
// router.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithCustomShouldCompressFn(func(c *gin.Context) bool {
// return c.Request.URL.Path != "/no-compress"
// })))
func WithCustomShouldCompressFn(fn func(c *gin.Context) bool) Option {
return optionFunc(func(o *config) {
o.customShouldCompressFn = fn
})
} }
// Using map for better lookup performance // Using map for better lookup performance
type ExcludedExtensions map[string]struct{} type ExcludedExtensions map[string]struct{}
// NewExcludedExtensions creates a new ExcludedExtensions map from a slice of file extensions.
// Parameters:
// - extensions: []string - A slice of file extensions to exclude from gzip compression.
//
// Returns:
// - ExcludedExtensions - A map of excluded file extensions.
func NewExcludedExtensions(extensions []string) ExcludedExtensions { func NewExcludedExtensions(extensions []string) ExcludedExtensions {
res := make(ExcludedExtensions) res := make(ExcludedExtensions, len(extensions))
for _, e := range extensions { for _, e := range extensions {
res[e] = struct{}{} res[e] = struct{}{}
} }
return res return res
} }
// Contains checks if a given file extension is in the ExcludedExtensions map.
// Parameters:
// - target: string - The file extension to check.
//
// Returns:
// - bool - True if the extension is excluded, false otherwise.
func (e ExcludedExtensions) Contains(target string) bool { func (e ExcludedExtensions) Contains(target string) bool {
_, ok := e[target] _, ok := e[target]
return ok return ok
@ -69,10 +147,22 @@ func (e ExcludedExtensions) Contains(target string) bool {
type ExcludedPaths []string type ExcludedPaths []string
// NewExcludedPaths creates a new ExcludedPaths slice from a slice of paths.
// Parameters:
// - paths: []string - A slice of paths to exclude from gzip compression.
//
// Returns:
// - ExcludedPaths - A slice of excluded paths.
func NewExcludedPaths(paths []string) ExcludedPaths { func NewExcludedPaths(paths []string) ExcludedPaths {
return ExcludedPaths(paths) return ExcludedPaths(paths)
} }
// Contains checks if a given request URI starts with any of the excluded paths.
// Parameters:
// - requestURI: string - The request URI to check.
//
// Returns:
// - bool - True if the URI starts with an excluded path, false otherwise.
func (e ExcludedPaths) Contains(requestURI string) bool { func (e ExcludedPaths) Contains(requestURI string) bool {
for _, path := range e { for _, path := range e {
if strings.HasPrefix(requestURI, path) { if strings.HasPrefix(requestURI, path) {
@ -84,14 +174,26 @@ func (e ExcludedPaths) Contains(requestURI string) bool {
type ExcludedPathesRegexs []*regexp.Regexp type ExcludedPathesRegexs []*regexp.Regexp
// NewExcludedPathesRegexs creates a new ExcludedPathesRegexs slice from a slice of regex patterns.
// Parameters:
// - regexs: []string - A slice of regex patterns to exclude paths from gzip compression.
//
// Returns:
// - ExcludedPathesRegexs - A slice of excluded path regex patterns.
func NewExcludedPathesRegexs(regexs []string) ExcludedPathesRegexs { func NewExcludedPathesRegexs(regexs []string) ExcludedPathesRegexs {
result := make([]*regexp.Regexp, len(regexs)) result := make(ExcludedPathesRegexs, len(regexs))
for i, reg := range regexs { for i, reg := range regexs {
result[i] = regexp.MustCompile(reg) result[i] = regexp.MustCompile(reg)
} }
return result return result
} }
// Contains checks if a given request URI matches any of the excluded path regex patterns.
// Parameters:
// - requestURI: string - The request URI to check.
//
// Returns:
// - bool - True if the URI matches an excluded path regex pattern, false otherwise.
func (e ExcludedPathesRegexs) Contains(requestURI string) bool { func (e ExcludedPathesRegexs) Contains(requestURI string) bool {
for _, reg := range e { for _, reg := range e {
if reg.MatchString(requestURI) { if reg.MatchString(requestURI) {
@ -101,16 +203,68 @@ func (e ExcludedPathesRegexs) Contains(requestURI string) bool {
return false return false
} }
// DefaultDecompressHandle is a middleware function for the Gin framework that
// decompresses the request body if it is gzip encoded. It checks if the request
// body is nil and returns immediately if it is. Otherwise, it attempts to create
// a new gzip reader from the request body. If an error occurs during this process,
// it aborts the request with a 400 Bad Request status and the error. If successful,
// it removes the "Content-Encoding" and "Content-Length" headers from the request
// and replaces the request body with the decompressed reader.
//
// Parameters:
// - c: *gin.Context - The Gin context for the current request.
func DefaultDecompressHandle(c *gin.Context) { func DefaultDecompressHandle(c *gin.Context) {
if c.Request.Body == nil { if c.Request.Body == nil {
return return
} }
contentEncodingField := strings.Split(strings.ToLower(c.GetHeader("Content-Encoding")), ",")
if len(contentEncodingField) == 0 { // nothing to decompress
c.Next()
return
}
toClose := make([]io.Closer, 0, len(contentEncodingField))
defer func() {
for i := len(toClose); i > 0; i-- {
toClose[i-1].Close()
}
}()
// parses multiply gzips like
// Content-Encoding: gzip, gzip, gzip
// allowed by RFC
for i := 0; i < len(contentEncodingField); i++ {
trimmedValue := strings.TrimSpace(contentEncodingField[i])
if trimmedValue == "" {
continue
}
if trimmedValue != "gzip" {
// According to RFC 7231, Section 3.1.2.2:
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.2
// An origin server MAY respond with a status code of 415 (Unsupported
// Media Type) if a representation in the request message has a content
// coding that is not acceptable.
_ = c.AbortWithError(http.StatusUnsupportedMediaType, ErrUnsupportedContentEncoding)
}
r, err := gzip.NewReader(c.Request.Body) r, err := gzip.NewReader(c.Request.Body)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err) _ = c.AbortWithError(http.StatusBadRequest, err)
return return
} }
toClose = append(toClose, c.Request.Body)
c.Request.Body = r
}
c.Request.Header.Del("Content-Encoding") c.Request.Header.Del("Content-Encoding")
c.Request.Header.Del("Content-Length") c.Request.Header.Del("Content-Length")
c.Request.Body = r
c.Next()
} }

3
vendor/github.com/gin-contrib/sse/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,3 @@
linters:
disable:
- errcheck

29
vendor/github.com/gin-contrib/sse/.goreleaser.yaml generated vendored Normal file
View file

@ -0,0 +1,29 @@
builds:
- # If true, skip the build.
# Useful for library projects.
# Default is false
skip: true
changelog:
use: github
groups:
- title: Features
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: "Bug fixes"
regexp: "^.*fix[(\\w)]*:+.*$"
order: 1
- title: "Enhancements"
regexp: "^.*chore[(\\w)]*:+.*$"
order: 2
- title: "Refactor"
regexp: "^.*refactor[(\\w)]*:+.*$"
order: 3
- title: "Build process updates"
regexp: ^.*?(build|ci)(\(.+\))??!?:.+$
order: 4
- title: "Documentation updates"
regexp: ^.*?docs?(\(.+\))??!?:.+$
order: 4
- title: Others
order: 999

View file

@ -1,26 +0,0 @@
language: go
sudo: false
go:
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- master
git:
depth: 10
matrix:
fast_finish: true
include:
- go: 1.11.x
env: GO111MODULE=on
- go: 1.12.x
env: GO111MODULE=on
script:
- go test -v -covermode=count -coverprofile=coverage.out
after_success:
- bash <(curl -s https://codecov.io/bash)

View file

@ -1,7 +1,7 @@
# Server-Sent Events # Server-Sent Events
[![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse) [![Go Reference](https://pkg.go.dev/badge/github.com/gin-contrib/sse.svg)](https://pkg.go.dev/github.com/gin-contrib/sse)
[![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/gin-contrib/sse) [![Run Tests](https://github.com/gin-contrib/sse/actions/workflows/go.yml/badge.svg)](https://github.com/gin-contrib/sse/actions/workflows/go.yml)
[![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse) [![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse)
@ -34,7 +34,8 @@ func httpHandler(w http.ResponseWriter, req *http.Request) {
}) })
} }
``` ```
```
```sh
event: message event: message
data: some data\\nmore data data: some data\\nmore data
@ -49,7 +50,8 @@ data: {"content":"hi!","date":1431540810,"user":"manu"}
```go ```go
fmt.Println(sse.ContentType) fmt.Println(sse.ContentType)
``` ```
```
```sh
text/event-stream text/event-stream
``` ```

View file

@ -18,7 +18,7 @@
// W3C Working Draft 29 October 2009 // W3C Working Draft 29 October 2009
// http://www.w3.org/TR/2009/WD-eventsource-20091029/ // http://www.w3.org/TR/2009/WD-eventsource-20091029/
const ContentType = "text/event-stream" const ContentType = "text/event-stream;charset=utf-8"
var contentType = []string{ContentType} var contentType = []string{ContentType}
var noCache = []string{"no-cache"} var noCache = []string{"no-cache"}
@ -72,6 +72,14 @@ func writeRetry(w stringWriter, retry uint) {
func writeData(w stringWriter, data interface{}) error { func writeData(w stringWriter, data interface{}) error {
w.WriteString("data:") w.WriteString("data:")
bData, ok := data.([]byte)
if ok {
dataReplacer.WriteString(w, string(bData))
w.WriteString("\n\n")
return nil
}
switch kindOfData(data) { switch kindOfData(data) {
case reflect.Struct, reflect.Slice, reflect.Map: case reflect.Struct, reflect.Slice, reflect.Map:
err := json.NewEncoder(w).Encode(data) err := json.NewEncoder(w).Encode(data)

View file

@ -1,7 +1,7 @@
Package validator Package validator
================= =================
<img align="right" src="logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <img align="right" src="logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-10.23.0-green.svg) ![Project status](https://img.shields.io/badge/version-10.24.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@ -22,6 +22,11 @@ It has the following **unique** features:
- Customizable i18n aware error messages. - Customizable i18n aware error messages.
- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) - Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding)
A Call for Maintainers
----------------------
Please read the discussiong started [here](https://github.com/go-playground/validator/discussions/1330) if you are interested in contributing/helping maintain this package.
Installation Installation
------------ ------------
@ -266,74 +271,75 @@ validate := validator.New(validator.WithRequiredStructEnabled())
Benchmarks Benchmarks
------ ------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 ###### Run on MacBook Pro Max M3
```go ```go
go version go1.21.0 darwin/arm64 go version go1.23.3 darwin/arm64
goos: darwin goos: darwin
goarch: arm64 goarch: arm64
cpu: Apple M3 Max
pkg: github.com/go-playground/validator/v10 pkg: github.com/go-playground/validator/v10
BenchmarkFieldSuccess-8 33142266 35.94 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccess-16 42461943 27.88 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 200816191 6.568 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccessParallel-16 486632887 2.289 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 6779707 175.1 ns/op 200 B/op 4 allocs/op BenchmarkFieldFailure-16 9566167 121.3 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 11044147 108.4 ns/op 200 B/op 4 allocs/op BenchmarkFieldFailureParallel-16 17551471 83.68 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 6054232 194.4 ns/op 97 B/op 5 allocs/op BenchmarkFieldArrayDiveSuccess-16 7602306 155.6 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 12523388 94.07 ns/op 97 B/op 5 allocs/op BenchmarkFieldArrayDiveSuccessParallel-16 20664610 59.80 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-8 3587043 334.3 ns/op 300 B/op 10 allocs/op BenchmarkFieldArrayDiveFailure-16 4659756 252.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5816665 200.8 ns/op 300 B/op 10 allocs/op BenchmarkFieldArrayDiveFailureParallel-16 8010116 152.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-8 2217910 540.1 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveSuccess-16 2834575 421.2 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 4446698 258.7 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveSuccessParallel-16 7179700 171.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-8 2392759 504.6 ns/op 376 B/op 13 allocs/op BenchmarkFieldMapDiveFailure-16 3081728 384.4 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 4244199 286.9 ns/op 376 B/op 13 allocs/op BenchmarkFieldMapDiveFailureParallel-16 6058137 204.0 ns/op 377 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 2005857 592.1 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveWithKeysSuccess-16 2544975 464.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 4400850 296.9 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveWithKeysSuccessParallel-16 6661954 181.4 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1850227 643.8 ns/op 553 B/op 16 allocs/op BenchmarkFieldMapDiveWithKeysFailure-16 2435484 490.7 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3293233 375.1 ns/op 553 B/op 16 allocs/op BenchmarkFieldMapDiveWithKeysFailureParallel-16 4249617 282.0 ns/op 554 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 12174412 98.25 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccess-16 14943525 77.35 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 34389907 35.49 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccessParallel-16 64051954 20.61 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 7582524 156.6 ns/op 184 B/op 3 allocs/op BenchmarkFieldCustomTypeFailure-16 10721384 107.1 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 13019902 92.79 ns/op 184 B/op 3 allocs/op BenchmarkFieldCustomTypeFailureParallel-16 18714495 69.77 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-8 3427260 349.4 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccess-16 4063124 294.3 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 15144128 81.25 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccessParallel-16 31903756 41.22 ns/op 18 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 5913546 201.9 ns/op 216 B/op 5 allocs/op BenchmarkFieldOrTagFailure-16 7748558 146.8 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 9810212 113.7 ns/op 216 B/op 5 allocs/op BenchmarkFieldOrTagFailureParallel-16 13139854 92.05 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 13456327 87.66 ns/op 16 B/op 1 allocs/op BenchmarkStructLevelValidationSuccess-16 16808389 70.25 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 41818888 27.77 ns/op 16 B/op 1 allocs/op BenchmarkStructLevelValidationSuccessParallel-16 90686955 14.47 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-8 4166284 272.6 ns/op 264 B/op 7 allocs/op BenchmarkStructLevelValidationFailure-16 5818791 200.2 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 7594581 152.1 ns/op 264 B/op 7 allocs/op BenchmarkStructLevelValidationFailureParallel-16 11115874 107.5 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 6508082 182.6 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccess-16 7764956 151.9 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 23078605 54.78 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccessParallel-16 52316265 30.37 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 3118352 381.0 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleCustomTypeFailure-16 4195429 277.2 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 5300738 224.1 ns/op 432 B/op 10 allocs/op BenchmarkStructSimpleCustomTypeFailureParallel-16 7305661 164.6 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 4761807 251.1 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredSuccess-16 6312625 186.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-8 8792598 128.6 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredSuccessParallel-16 13684459 93.42 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-8 5202573 232.1 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredFailure-16 6751482 171.2 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-8 9591267 121.4 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredFailureParallel-16 14146070 86.93 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-8 5188512 231.6 ns/op 224 B/op 4 allocs/op BenchmarkStructPartialSuccess-16 6544448 177.3 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-8 9179776 123.1 ns/op 224 B/op 4 allocs/op BenchmarkStructPartialSuccessParallel-16 13951946 88.73 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-8 3071212 392.5 ns/op 440 B/op 9 allocs/op BenchmarkStructPartialFailure-16 4075833 287.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-8 5344261 223.7 ns/op 440 B/op 9 allocs/op BenchmarkStructPartialFailureParallel-16 7490805 161.3 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-8 3184230 375.0 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptSuccess-16 4107187 281.4 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-8 10090130 108.9 ns/op 208 B/op 3 allocs/op BenchmarkStructExceptSuccessParallel-16 15979173 80.86 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-8 3347226 357.7 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptFailure-16 4434372 264.3 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-8 5654923 209.5 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptFailureParallel-16 8081367 154.1 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5232265 229.1 ns/op 56 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccess-16 6459542 183.4 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 17436674 64.75 ns/op 56 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccessParallel-16 41013781 37.95 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 3128613 383.6 ns/op 272 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailure-16 4034998 292.1 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 6994113 168.8 ns/op 272 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailureParallel-16 11348446 115.3 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3506487 340.9 ns/op 64 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccess-16 4448528 267.7 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 13431300 91.77 ns/op 64 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-16 26813619 48.33 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2410566 500.9 ns/op 288 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailure-16 3090646 384.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 6344510 188.2 ns/op 288 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-16 9870906 129.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 8922726 133.8 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccess-16 10675562 109.5 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 55291153 23.63 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccessParallel-16 131159784 8.932 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 3171553 378.4 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleFailure-16 4094979 286.6 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 5571692 212.0 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleFailureParallel-16 7606663 157.9 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1683750 714.5 ns/op 224 B/op 5 allocs/op BenchmarkStructComplexSuccess-16 2073470 576.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-8 4578046 257.0 ns/op 224 B/op 5 allocs/op BenchmarkStructComplexSuccessParallel-16 7821831 161.3 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-8 481585 2547 ns/op 3041 B/op 48 allocs/op BenchmarkStructComplexFailure-16 576358 2001 ns/op 3042 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-8 965764 1577 ns/op 3040 B/op 48 allocs/op BenchmarkStructComplexFailureParallel-16 1000000 1171 ns/op 3041 B/op 48 allocs/op
BenchmarkOneof-8 17380881 68.50 ns/op 0 B/op 0 allocs/op BenchmarkOneof-16 22503973 52.82 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-8 8084733 153.5 ns/op 0 B/op 0 allocs/op BenchmarkOneofParallel-16 8538474 140.4 ns/op 0 B/op 0 allocs/op
``` ```
Complementary Software Complementary Software
@ -349,6 +355,20 @@ How to Contribute
Make a pull request... Make a pull request...
Maintenance and support for SDK major versions
----------------------------------------------
See prior discussion [here](https://github.com/go-playground/validator/discussions/1342) for more details.
This package is aligned with the [Go release policy](https://go.dev/doc/devel/release) in that support is guaranteed for
the two most recent major versions.
This does not mean the package will not work with older versions of Go, only that we reserve the right to increase the
MSGV(Minimum Supported Go Version) when the need arises to address Security issues/patches, OS issues & support or newly
introduced functionality that would greatly benefit the maintenance and/or usage of this package.
If and when the MSGV is increased it will be done so in a minimum of a `Minor` release bump.
License License
------- -------
Distributed under MIT License, please see license file within the code for more details. Distributed under MIT License, please see license file within the code for more details.

View file

@ -88,9 +88,7 @@ func opaqueInitHook(mi *MessageInfo) bool {
mi.oneofs = map[protoreflect.Name]*oneofInfo{} mi.oneofs = map[protoreflect.Name]*oneofInfo{}
for i := 0; i < mi.Desc.Oneofs().Len(); i++ { for i := 0; i < mi.Desc.Oneofs().Len(); i++ {
od := mi.Desc.Oneofs().Get(i) od := mi.Desc.Oneofs().Get(i)
if !od.IsSynthetic() { mi.oneofs[od.Name()] = makeOneofInfoOpaque(mi, od, si.structInfo, mi.Exporter)
mi.oneofs[od.Name()] = makeOneofInfo(od, si.structInfo, mi.Exporter)
}
} }
mi.denseFields = make([]*fieldInfo, fds.Len()*2) mi.denseFields = make([]*fieldInfo, fds.Len()*2)
@ -119,6 +117,26 @@ func opaqueInitHook(mi *MessageInfo) bool {
return true return true
} }
func makeOneofInfoOpaque(mi *MessageInfo, od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
oi := &oneofInfo{oneofDesc: od}
if od.IsSynthetic() {
fd := od.Fields().Get(0)
index, _ := presenceIndex(mi.Desc, fd)
oi.which = func(p pointer) protoreflect.FieldNumber {
if p.IsNil() {
return 0
}
if !mi.present(p, index) {
return 0
}
return od.Fields().Get(0).Number()
}
return oi
}
// Dispatch to non-opaque oneof implementation for non-synthetic oneofs.
return makeOneofInfo(od, si, x)
}
func (mi *MessageInfo) fieldInfoForMapOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo { func (mi *MessageInfo) fieldInfoForMapOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
ft := fs.Type ft := fs.Type
if ft.Kind() != reflect.Map { if ft.Kind() != reflect.Map {

View file

@ -52,7 +52,7 @@
const ( const (
Major = 1 Major = 1
Minor = 36 Minor = 36
Patch = 1 Patch = 2
PreRelease = "" PreRelease = ""
) )

26
vendor/modules.txt vendored
View file

@ -101,7 +101,7 @@ github.com/beorn7/perks/quantile
## explicit; go 1.14 ## explicit; go 1.14
github.com/buckket/go-blurhash github.com/buckket/go-blurhash
github.com/buckket/go-blurhash/base83 github.com/buckket/go-blurhash/base83
# github.com/bytedance/sonic v1.12.6 # github.com/bytedance/sonic v1.12.7
## explicit; go 1.17 ## explicit; go 1.17
github.com/bytedance/sonic github.com/bytedance/sonic
github.com/bytedance/sonic/ast github.com/bytedance/sonic/ast
@ -135,10 +135,12 @@ github.com/bytedance/sonic/internal/utils
github.com/bytedance/sonic/option github.com/bytedance/sonic/option
github.com/bytedance/sonic/unquote github.com/bytedance/sonic/unquote
github.com/bytedance/sonic/utf8 github.com/bytedance/sonic/utf8
# github.com/bytedance/sonic/loader v0.2.1 # github.com/bytedance/sonic/loader v0.2.2
## explicit; go 1.16 ## explicit; go 1.16
github.com/bytedance/sonic/loader github.com/bytedance/sonic/loader
github.com/bytedance/sonic/loader/internal/abi github.com/bytedance/sonic/loader/internal/abi
github.com/bytedance/sonic/loader/internal/iasm/expr
github.com/bytedance/sonic/loader/internal/iasm/x86_64
github.com/bytedance/sonic/loader/internal/rt github.com/bytedance/sonic/loader/internal/rt
# github.com/cenkalti/backoff/v4 v4.3.0 # github.com/cenkalti/backoff/v4 v4.3.0
## explicit; go 1.18 ## explicit; go 1.18
@ -158,10 +160,6 @@ github.com/cilium/ebpf/link
# github.com/cloudwego/base64x v0.1.4 # github.com/cloudwego/base64x v0.1.4
## explicit; go 1.16 ## explicit; go 1.16
github.com/cloudwego/base64x github.com/cloudwego/base64x
# github.com/cloudwego/iasm v0.2.0
## explicit; go 1.16
github.com/cloudwego/iasm/expr
github.com/cloudwego/iasm/x86_64
# github.com/containerd/cgroups/v3 v3.0.1 # github.com/containerd/cgroups/v3 v3.0.1
## explicit; go 1.17 ## explicit; go 1.17
github.com/containerd/cgroups/v3 github.com/containerd/cgroups/v3
@ -208,7 +206,7 @@ github.com/felixge/httpsnoop
# github.com/fsnotify/fsnotify v1.7.0 # github.com/fsnotify/fsnotify v1.7.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify
# github.com/gabriel-vasile/mimetype v1.4.7 # github.com/gabriel-vasile/mimetype v1.4.8
## explicit; go 1.20 ## explicit; go 1.20
github.com/gabriel-vasile/mimetype github.com/gabriel-vasile/mimetype
github.com/gabriel-vasile/mimetype/internal/charset github.com/gabriel-vasile/mimetype/internal/charset
@ -217,15 +215,15 @@ github.com/gabriel-vasile/mimetype/internal/magic
# github.com/gin-contrib/cors v1.7.3 # github.com/gin-contrib/cors v1.7.3
## explicit; go 1.21.0 ## explicit; go 1.21.0
github.com/gin-contrib/cors github.com/gin-contrib/cors
# github.com/gin-contrib/gzip v1.1.0 # github.com/gin-contrib/gzip v1.2.2
## explicit; go 1.21.0 ## explicit; go 1.21.0
github.com/gin-contrib/gzip github.com/gin-contrib/gzip
# github.com/gin-contrib/sessions v1.0.2 # github.com/gin-contrib/sessions v1.0.2
## explicit; go 1.20 ## explicit; go 1.20
github.com/gin-contrib/sessions github.com/gin-contrib/sessions
github.com/gin-contrib/sessions/memstore github.com/gin-contrib/sessions/memstore
# github.com/gin-contrib/sse v0.1.0 # github.com/gin-contrib/sse v1.0.0
## explicit; go 1.12 ## explicit; go 1.13
github.com/gin-contrib/sse github.com/gin-contrib/sse
# github.com/gin-gonic/gin v1.10.0 # github.com/gin-gonic/gin v1.10.0
## explicit; go 1.20 ## explicit; go 1.20
@ -312,8 +310,8 @@ github.com/go-playground/locales/currency
# github.com/go-playground/universal-translator v0.18.1 # github.com/go-playground/universal-translator v0.18.1
## explicit; go 1.18 ## explicit; go 1.18
github.com/go-playground/universal-translator github.com/go-playground/universal-translator
# github.com/go-playground/validator/v10 v10.23.0 # github.com/go-playground/validator/v10 v10.24.0
## explicit; go 1.18 ## explicit; go 1.20
github.com/go-playground/validator/v10 github.com/go-playground/validator/v10
# github.com/go-swagger/go-swagger v0.31.0 => github.com/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix # github.com/go-swagger/go-swagger v0.31.0 => github.com/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix
## explicit; go 1.21 ## explicit; go 1.21
@ -1077,7 +1075,7 @@ go.uber.org/automaxprocs/maxprocs
# go.uber.org/multierr v1.11.0 # go.uber.org/multierr v1.11.0
## explicit; go 1.19 ## explicit; go 1.19
go.uber.org/multierr go.uber.org/multierr
# golang.org/x/arch v0.12.0 # golang.org/x/arch v0.13.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/arch/x86/x86asm golang.org/x/arch/x86/x86asm
# golang.org/x/crypto v0.32.0 # golang.org/x/crypto v0.32.0
@ -1263,7 +1261,7 @@ google.golang.org/grpc/serviceconfig
google.golang.org/grpc/stats google.golang.org/grpc/stats
google.golang.org/grpc/status google.golang.org/grpc/status
google.golang.org/grpc/tap google.golang.org/grpc/tap
# google.golang.org/protobuf v1.36.1 # google.golang.org/protobuf v1.36.2
## explicit; go 1.21 ## explicit; go 1.21
google.golang.org/protobuf/encoding/protodelim google.golang.org/protobuf/encoding/protodelim
google.golang.org/protobuf/encoding/protojson google.golang.org/protobuf/encoding/protojson