[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/coreos/go-oidc/v3 v3.12.0
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-gonic/gin v1.10.0
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/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/bytedance/sonic v1.12.7 // indirect
github.com/bytedance/sonic/loader v0.2.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cilium/ebpf v0.9.1 // 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/coreos/go-systemd/v22 v22.3.2 // 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/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-fed/httpsig v1.1.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-playground/locales v0.14.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/goccy/go-json v0.10.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/proto/otlp v1.3.1 // 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/mod v0.22.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/rpc v0.0.0-20240903143218-8af14fe29dc1 // 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/yaml.v2 v2.4.0 // 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/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
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.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
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.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
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/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
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/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=
@ -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/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
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.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
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/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/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4=
github.com/gin-contrib/gzip v1.1.0 h1:kVw7Nr9M+Z6Ch4qo7aGMbiqxDeyQFru+07MgAcUF62M=
github.com/gin-contrib/gzip v1.1.0/go.mod h1:iHJXCup4CWiKyPUEl+GwkHjchl+YyYuMKbOCiXujPIA=
github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI=
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/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
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/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
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/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/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
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-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
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.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.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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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.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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
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/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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
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.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
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-20190510104115-cbcb75029529/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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
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.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
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 v1.0.0-20180628173108-788fd7840127/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
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
@ -480,9 +480,9 @@ But `ast.Visitor` is not a very handy API. You might need to write a lot of code
### 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:
@ -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`
- `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
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 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.
ValidateString bool
@ -120,7 +120,7 @@ type Config struct {
// API is a binding of specific config.
// 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 {
// MarshalToString returns the JSON encoding string of v
MarshalToString(v interface{}) (string, error)

View file

@ -34,7 +34,7 @@ func quote(buf *[]byte, val string) {
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) {
sp := rt.IndexChar(src, -1)
out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2))

View file

@ -27,7 +27,7 @@
"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')
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,
// 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.
//
// 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
//
// Deprecated: not concurent safe
// Deprecated: not concurrent safe
func (self Node) IsRaw() bool {
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.
func (self *Node) StrictString() (string, error) {
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) {
if err := self.checkRaw(); err != nil {
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
// 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 {
return false, err
}
// NOTICE: must get acurate length before deduct
// NOTICE: must get accurate length before deduct
if err := self.skipAllKey(); err != nil {
return false, err
}
@ -657,7 +657,7 @@ func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) {
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.
// Use Unset() for object or Pop() for array instead.
@ -957,7 +957,7 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) {
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
func (self *Node) MapUseNode() (map[string]Node, error) {
if self.isAny() {
@ -1102,7 +1102,7 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) {
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
func (self *Node) ArrayUseNode() ([]Node, error) {
if self.isAny() {
@ -1147,9 +1147,9 @@ func (self *Node) unsafeArray() (*linkedNodes, error) {
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.
// WARN: all numberic nodes are casted to float64
// WARN: all numeric nodes are casted to float64
func (self *Node) Interface() (interface{}, error) {
if err := self.checkRaw(); err != nil {
return nil, err
@ -1193,7 +1193,7 @@ func (self *Node) packAny() 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) {
if err := self.checkRaw(); err != nil {
return nil, err

View file

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

View file

@ -30,7 +30,7 @@
// SyntaxError represents json syntax error
type SyntaxError = api.SyntaxError
// MismatchTypeError represents dismatching between json and object
// MismatchTypeError represents mismatching between json and object
type MismatchTypeError = api.MismatchTypeError
// 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.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=

View file

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

View file

@ -67,7 +67,7 @@
*/
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_saves = 48 // 48 bytes for saving the registers before CALL instructions
_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_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_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 {
@ -1361,7 +1361,7 @@ func (self *_Assembler) _asm_OP_num(_ *_Instr) {
self.Emit("MOVQ", _R9, _VAR_pc)
self.Sjmp("JMP" , _LB_skip_one)
/* assgin string */
/* assign string */
self.Link("_num_next_{n}")
self.slice_from_r(_AX, 0)
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
/* 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)
}

View file

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

View file

@ -177,7 +177,7 @@ func (c *compiler) compilePtr(vt reflect.Type) decFunc {
c.enter(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 {
c.namedPtr = true
return &ptrDecoder{
@ -432,7 +432,7 @@ func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFun
/* check for `encoding.TextMarshaler` with pointer receiver */
if pt.Implements(encodingTextUnmarshalerType) {
/* TextUnmarshal not support ,strig tag */
/* TextUnmarshal not support, string tag */
if strOpt {
panicForInvalidStrType(vt)
}

View file

@ -11,7 +11,7 @@
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
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' {
@ -40,7 +40,7 @@ func ValidNumberFast(raw string) bool {
return false
}
// check trainling chars
// check trailing chars
for ret < len(raw) {
return false
}
@ -49,7 +49,7 @@ func ValidNumberFast(raw string) bool {
}
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)
if start < 0 {
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) {
// 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)
if start < 0 {
// TODO: details error code

View file

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

View file

@ -372,7 +372,7 @@ func (val Node) ParseF64(ctx *Context) (float64, bool) {
}
func (val Node) ParseString(ctx *Context) (string, bool) {
// shoud not use AsStrRef
// should not use AsStrRef
s, ok := val.AsStr(ctx)
if !ok {
return "", false
@ -391,7 +391,7 @@ func (val Node) ParseString(ctx *Context) (string, bool) {
func (val Node) ParseNumber(ctx *Context) (json.Number, bool) {
// shoud not use AsStrRef
// should not use AsStrRef
s, ok := val.AsStr(ctx)
if !ok {
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)]
// Native implemention:
// Native implementation:
// radixQsort(kvs[:lt], d, maxDepth)
// if p > -1 {
// 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.Link("_str_next_{n}")
/* openning quote, check for double quote */
/* opening quote, check for double quote */
if !doubleQuote {
self.check_size_r(_AX, 2) // SIZE $2
self.add_char('"') // CHAR $'"'

View file

@ -84,7 +84,7 @@ func NewSmallFieldMap (hint int) *SmallFieldMap {
func (self *SmallFieldMap) Set(fields []resolver.FieldMeta) {
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 {
@ -254,7 +254,7 @@ type keysInfo struct {
func (self *NormalFieldMap) Set(fields []resolver.FieldMeta) {
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
@ -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.lowOffset = _HdrSize + kvLen

View file

@ -153,7 +153,7 @@ func MakeSlice(oldPtr unsafe.Pointer, et *GoType, newLen int) *GoSlice {
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 {
oldlenmem := uintptr(old.Len) * et.Size
newlenmem := uintptr(newLen) * et.Size

View file

@ -329,7 +329,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab
// mmap() text and funcdata segements
// mmap() text and funcdata segments
p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size)
@ -389,7 +389,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
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.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -330,7 +330,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab
// mmap() text and funcdata segements
// mmap() text and funcdata segments
p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size)
@ -390,7 +390,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
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.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -222,7 +222,7 @@ funcs := *funcsp
funcnametab, nameOffs := makeFuncnameTab(funcs)
mod.funcnametab = funcnametab
// mmap() text and funcdata segements
// mmap() text and funcdata segments
p := os.Getpagesize()
size := int(rnd(int64(len(text)), int64(p)))
addr := mmap(size)
@ -283,7 +283,7 @@ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
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.gcbss = uintptr(unsafe.Pointer(&emptyByte))

View file

@ -17,266 +17,285 @@
package abi
import (
`fmt`
`reflect`
`unsafe`
"fmt"
"reflect"
"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 (
PtrSize = 8 // pointer size
PtrAlign = 8 // pointer alignment
RAX = x64.RAX
RSP = x64.RSP
RBP = x64.RBP
R12 = x64.R12
R14 = x64.R14
R15 = x64.R15
)
const (
PtrSize = 8 // pointer size
PtrAlign = 8 // pointer alignment
)
var iregOrderC = []Register{
RDI,
RSI,
RDX,
RCX,
R8,
R9,
x64.RDI,
x64.RSI,
x64.RDX,
x64.RCX,
x64.R8,
x64.R9,
}
var xregOrderC = []Register{
XMM0,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7,
x64.XMM0,
x64.XMM1,
x64.XMM2,
x64.XMM3,
x64.XMM4,
x64.XMM5,
x64.XMM6,
x64.XMM7,
}
var (
intType = reflect.TypeOf(0)
ptrType = reflect.TypeOf(unsafe.Pointer(nil))
intType = reflect.TypeOf(0)
ptrType = reflect.TypeOf(unsafe.Pointer(nil))
)
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
func (self *Frame) spillv(i int) *MemoryOperand {
// remain one slot for caller return pc
return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem))
// remain one slot for caller return pc
return Ptr(RSP, PtrSize+int32(self.desc.Args[i].Mem))
}
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 {
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) {
// spill all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i))
}else {
p.MOVQ(v.Reg, self.spillv(i))
}
}
}
// spill all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i))
} else {
p.MOVQ(v.Reg, self.spillv(i))
}
}
}
// call runtime.morestack_noctxt
p.MOVQ(F_morestack_noctxt, R12)
p.CALLQ(R12)
// load all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(self.spillv(i), v.Reg)
} else if v.IsFloat == floatKind32 {
p.MOVSS(self.spillv(i), v.Reg)
}else {
p.MOVQ(self.spillv(i), v.Reg)
}
}
}
// call runtime.morestack_noctxt
p.MOVQ(F_morestack_noctxt, R12)
p.CALLQ(R12)
// load all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(self.spillv(i), v.Reg)
} else if v.IsFloat == floatKind32 {
p.MOVSS(self.spillv(i), v.Reg)
} else {
p.MOVQ(self.spillv(i), v.Reg)
}
}
}
// jump back to the function entry
p.JMP(entry)
// jump back to the function entry
p.JMP(entry)
}
func (self *Frame) GrowStackTextSize() uint32 {
p := DefaultArch.CreateProgram()
// spill all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i))
}else {
p.MOVQ(v.Reg, self.spillv(i))
}
}
}
p := DefaultArch.CreateProgram()
// spill all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(v.Reg, self.spillv(i))
} else if v.IsFloat == floatKind32 {
p.MOVSS(v.Reg, self.spillv(i))
} else {
p.MOVQ(v.Reg, self.spillv(i))
}
}
}
// call runtime.morestack_noctxt
p.MOVQ(F_morestack_noctxt, R12)
p.CALLQ(R12)
// load all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(self.spillv(i), v.Reg)
} else if v.IsFloat == floatKind32 {
p.MOVSS(self.spillv(i), v.Reg)
} else {
p.MOVQ(self.spillv(i), v.Reg)
}
}
}
// call runtime.morestack_noctxt
p.MOVQ(F_morestack_noctxt, R12)
p.CALLQ(R12)
// load all register arguments
for i, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat == floatKind64 {
p.MOVSD(self.spillv(i), v.Reg)
} else if v.IsFloat == floatKind32 {
p.MOVSS(self.spillv(i), v.Reg)
} else {
p.MOVQ(self.spillv(i), v.Reg)
}
}
}
// jump back to the function entry
l := CreateLabel("")
p.Link(l)
p.JMP(l)
// jump back to the function entry
l := CreateLabel("")
p.Link(l)
p.JMP(l)
return uint32(len(p.Assemble(0)))
return uint32(len(p.Assemble(0)))
}
func (self *Frame) emitPrologue(p *Program) {
p.SUBQ(self.Size(), RSP)
p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
p.SUBQ(self.Size(), RSP)
p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
}
func (self *Frame) emitEpilogue(p *Program) {
p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
p.ADDQ(self.Size(), RSP)
p.RET()
p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
p.ADDQ(self.Size(), RSP)
p.RET()
}
func (self *Frame) emitReserveRegs(p *Program) {
// spill reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(r, self.resv(i))
case XMMRegister:
p.MOVSD(r, self.resv(i))
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
// spill reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(r, self.resv(i))
case XMMRegister:
p.MOVSD(r, self.resv(i))
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
}
func (self *Frame) emitSpillPtrs(p *Program) {
// spill pointer argument registers
for i, r := range self.desc.Args {
if r.InRegister && r.IsPointer {
p.MOVQ(r.Reg, self.argv(i))
}
}
// spill pointer argument registers
for i, r := range self.desc.Args {
if r.InRegister && r.IsPointer {
p.MOVQ(r.Reg, self.argv(i))
}
}
}
func (self *Frame) emitClearPtrs(p *Program) {
// spill pointer argument registers
for i, r := range self.desc.Args {
if r.InRegister && r.IsPointer {
p.MOVQ(int64(0), self.argv(i))
}
}
// spill pointer argument registers
for i, r := range self.desc.Args {
if r.InRegister && r.IsPointer {
p.MOVQ(int64(0), self.argv(i))
}
}
}
func (self *Frame) emitCallC(p *Program, addr uintptr) {
p.MOVQ(addr, RAX)
p.CALLQ(RAX)
p.MOVQ(addr, RAX)
p.CALLQ(RAX)
}
type floatKind uint8
const (
notFloatKind floatKind = iota
floatKind32
floatKind64
notFloatKind floatKind = iota
floatKind32
floatKind64
)
type Parameter struct {
InRegister bool
IsPointer bool
IsFloat floatKind
Reg Register
Mem uint32
Type reflect.Type
InRegister bool
IsPointer bool
IsFloat floatKind
Reg Register
Mem uint32
Type reflect.Type
}
func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
p.Reg = reg
p.Type = vt
p.InRegister = true
p.IsPointer = isPointer(vt)
return
p.Reg = reg
p.Type = vt
p.InRegister = true
p.IsPointer = isPointer(vt)
return
}
func isFloat(vt reflect.Type) floatKind {
switch vt.Kind() {
case reflect.Float32:
return floatKind32
case reflect.Float64:
return floatKind64
default:
return notFloatKind
}
switch vt.Kind() {
case reflect.Float32:
return floatKind32
case reflect.Float64:
return floatKind64
default:
return notFloatKind
}
}
func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
p.Reg = reg
p.Type = vt
p.InRegister = true
p.IsFloat = isFloat(vt)
return
p.Reg = reg
p.Type = vt
p.InRegister = true
p.IsFloat = isFloat(vt)
return
}
func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
p.Mem = mem
p.Type = vt
p.InRegister = false
p.IsPointer = isPointer(vt)
p.IsFloat = isFloat(vt)
return
p.Mem = mem
p.Type = vt
p.InRegister = false
p.IsPointer = isPointer(vt)
p.IsFloat = isFloat(vt)
return
}
func (self Parameter) String() string {
if self.InRegister {
return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
} else {
return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
}
if self.InRegister {
return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
} else {
return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
}
}
func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
p := DefaultArch.CreateProgram()
p := DefaultArch.CreateProgram()
stack := CreateLabel("_stack_grow")
entry := CreateLabel("_entry")
p.Link(entry)
fr.emitStackCheck(p, stack, maxStack)
fr.emitPrologue(p)
fr.emitReserveRegs(p)
fr.emitSpillPtrs(p)
fr.emitExchangeArgs(p)
fr.emitCallC(p, addr)
fr.emitExchangeRets(p)
fr.emitRestoreRegs(p)
fr.emitEpilogue(p)
p.Link(stack)
fr.emitGrowStack(p, entry)
stack := CreateLabel("_stack_grow")
entry := CreateLabel("_entry")
p.Link(entry)
fr.emitStackCheck(p, stack, maxStack)
fr.emitPrologue(p)
fr.emitReserveRegs(p)
fr.emitSpillPtrs(p)
fr.emitExchangeArgs(p)
fr.emitCallC(p, addr)
fr.emitExchangeRets(p)
fr.emitRestoreRegs(p)
fr.emitEpilogue(p)
p.Link(stack)
fr.emitGrowStack(p, entry)
return p.Assemble(0)
return p.Assemble(0)
}
func (self *Frame) emitDebug(p *Program) {
p.INT(3)
}

View file

@ -20,163 +20,196 @@
package abi
import (
`fmt`
`reflect`
`runtime`
. `github.com/cloudwego/iasm/x86_64`
"fmt"
"reflect"
"runtime"
)
func ReservedRegs(callc bool) []Register {
return nil
return nil
}
func salloc(p []Parameter, sp uint32, vt reflect.Type) (uint32, []Parameter) {
switch vt.Kind() {
case reflect.Bool : return sp + 8, append(p, mkStack(reflect.TypeOf(false), sp))
case reflect.Int : return sp + 8, append(p, mkStack(intType, sp))
case reflect.Int8 : return sp + 8, append(p, mkStack(reflect.TypeOf(int8(0)), sp))
case reflect.Int16 : return sp + 8, append(p, mkStack(reflect.TypeOf(int16(0)), sp))
case reflect.Int32 : return sp + 8, append(p, mkStack(reflect.TypeOf(int32(0)), sp))
case reflect.Int64 : return sp + 8, append(p, mkStack(reflect.TypeOf(int64(0)), sp))
case reflect.Uint : return sp + 8, append(p, mkStack(reflect.TypeOf(uint(0)), sp))
case reflect.Uint8 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint8(0)), sp))
case reflect.Uint16 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint16(0)), sp))
case reflect.Uint32 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint32(0)), sp))
case reflect.Uint64 : return sp + 8, append(p, mkStack(reflect.TypeOf(uint64(0)), sp))
case reflect.Uintptr : return sp + 8, append(p, mkStack(reflect.TypeOf(uintptr(0)), sp))
case reflect.Float32 : return sp + 8, append(p, mkStack(reflect.TypeOf(float32(0)), sp))
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")
}
switch vt.Kind() {
case reflect.Bool:
return sp + 8, append(p, mkStack(reflect.TypeOf(false), sp))
case reflect.Int:
return sp + 8, append(p, mkStack(intType, sp))
case reflect.Int8:
return sp + 8, append(p, mkStack(reflect.TypeOf(int8(0)), sp))
case reflect.Int16:
return sp + 8, append(p, mkStack(reflect.TypeOf(int16(0)), sp))
case reflect.Int32:
return sp + 8, append(p, mkStack(reflect.TypeOf(int32(0)), sp))
case reflect.Int64:
return sp + 8, append(p, mkStack(reflect.TypeOf(int64(0)), sp))
case reflect.Uint:
return sp + 8, append(p, mkStack(reflect.TypeOf(uint(0)), sp))
case reflect.Uint8:
return sp + 8, append(p, mkStack(reflect.TypeOf(uint8(0)), sp))
case reflect.Uint16:
return sp + 8, append(p, mkStack(reflect.TypeOf(uint16(0)), sp))
case reflect.Uint32:
return sp + 8, append(p, mkStack(reflect.TypeOf(uint32(0)), sp))
case reflect.Uint64:
return sp + 8, append(p, mkStack(reflect.TypeOf(uint64(0)), sp))
case reflect.Uintptr:
return sp + 8, append(p, mkStack(reflect.TypeOf(uintptr(0)), sp))
case reflect.Float32:
return sp + 8, append(p, mkStack(reflect.TypeOf(float32(0)), sp))
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")
}
}
func NewFunctionLayout(ft reflect.Type) FunctionLayout {
var sp uint32
var fn FunctionLayout
var sp uint32
var fn FunctionLayout
/* assign every arguments */
for i := 0; i < ft.NumIn(); i++ {
sp, fn.Args = salloc(fn.Args, sp, ft.In(i))
}
/* assign every arguments */
for i := 0; i < ft.NumIn(); i++ {
sp, fn.Args = salloc(fn.Args, sp, ft.In(i))
}
/* assign every return value */
for i := 0; i < ft.NumOut(); i++ {
sp, fn.Rets = salloc(fn.Rets, sp, ft.Out(i))
}
/* assign every return value */
for i := 0; i < ft.NumOut(); i++ {
sp, fn.Rets = salloc(fn.Rets, sp, ft.Out(i))
}
/* update function ID and stack pointer */
fn.FP = sp
return fn
/* update function ID and stack pointer */
fn.FP = sp
return fn
}
func (self *Frame) emitExchangeArgs(p *Program) {
iregArgs, xregArgs := 0, 0
for _, v := range self.desc.Args {
if v.IsFloat != notFloatKind {
xregArgs += 1
} else {
iregArgs += 1
}
}
iregArgs, xregArgs := 0, 0
for _, v := range self.desc.Args {
if v.IsFloat != notFloatKind {
xregArgs += 1
} else {
iregArgs += 1
}
}
if iregArgs > len(iregOrderC) {
panic("too many arguments, only support at most 6 integer arguments now")
}
if xregArgs > len(xregOrderC) {
panic("too many arguments, only support at most 8 float arguments now")
}
if iregArgs > len(iregOrderC) {
panic("too many arguments, only support at most 6 integer arguments now")
}
if xregArgs > len(xregOrderC) {
panic("too many arguments, only support at most 8 float arguments now")
}
ic, xc := iregArgs, xregArgs
for i := 0; i < len(self.desc.Args); i++ {
arg := self.desc.Args[i]
if arg.IsFloat == floatKind64 {
p.MOVSD(self.argv(i), xregOrderC[xregArgs - xc])
xc -= 1
} else if arg.IsFloat == floatKind32 {
p.MOVSS(self.argv(i), xregOrderC[xregArgs - xc])
xc -= 1
} else {
p.MOVQ(self.argv(i), iregOrderC[iregArgs - ic])
ic -= 1
}
}
ic, xc := iregArgs, xregArgs
for i := 0; i < len(self.desc.Args); i++ {
arg := self.desc.Args[i]
if arg.IsFloat == floatKind64 {
p.MOVSD(self.argv(i), xregOrderC[xregArgs-xc])
xc -= 1
} else if arg.IsFloat == floatKind32 {
p.MOVSS(self.argv(i), xregOrderC[xregArgs-xc])
xc -= 1
} else {
p.MOVQ(self.argv(i), iregOrderC[iregArgs-ic])
ic -= 1
}
}
}
func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) {
// get the current goroutine
switch runtime.GOOS {
case "linux" : p.MOVQ(Abs(-8), R14).FS()
case "darwin" : 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
p.LEAQ(Ptr(RSP, -int32(self.Size() + uint32(maxStack))), RAX)
p.CMPQ(Ptr(R14, _G_stackguard0), RAX)
p.JBE(to)
// get the current goroutine
switch runtime.GOOS {
case "linux":
p.MOVQ(Abs(-8), R14).FS()
case "darwin":
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
p.LEAQ(Ptr(RSP, -int32(self.Size()+uint32(maxStack))), RAX)
p.CMPQ(Ptr(R14, _G_stackguard0), RAX)
p.JBE(to)
}
func (self *Frame) StackCheckTextSize() uint32 {
p := DefaultArch.CreateProgram()
p := DefaultArch.CreateProgram()
// get the current goroutine
switch runtime.GOOS {
case "linux" : p.MOVQ(Abs(-8), R14).FS()
case "darwin" : 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
p.LEAQ(Ptr(RSP, -int32(self.Size())), RAX)
p.CMPQ(Ptr(R14, _G_stackguard0), RAX)
l := CreateLabel("")
p.Link(l)
p.JBE(l)
// get the current goroutine
switch runtime.GOOS {
case "linux":
p.MOVQ(Abs(-8), R14).FS()
case "darwin":
p.MOVQ(Abs(0x30), R14).GS()
case "windows":
break // windows always stores G pointer at R14
default:
panic("unsupported operating system")
}
return uint32(len(p.Assemble(0)))
// check the stack guard
p.LEAQ(Ptr(RSP, -int32(self.Size())), RAX)
p.CMPQ(Ptr(R14, _G_stackguard0), RAX)
l := CreateLabel("")
p.Link(l)
p.JBE(l)
return uint32(len(p.Assemble(0)))
}
func (self *Frame) emitExchangeRets(p *Program) {
if len(self.desc.Rets) > 1 {
panic("too many results, only support one result now")
}
// store result
if len(self.desc.Rets) ==1 {
if self.desc.Rets[0].IsFloat == floatKind64 {
p.MOVSD(xregOrderC[0], self.retv(0))
} else if self.desc.Rets[0].IsFloat == floatKind32 {
p.MOVSS(xregOrderC[0], self.retv(0))
} else {
p.MOVQ(RAX, self.retv(0))
}
}
if len(self.desc.Rets) > 1 {
panic("too many results, only support one result now")
}
// store result
if len(self.desc.Rets) == 1 {
if self.desc.Rets[0].IsFloat == floatKind64 {
p.MOVSD(xregOrderC[0], self.retv(0))
} else if self.desc.Rets[0].IsFloat == floatKind32 {
p.MOVSS(xregOrderC[0], self.retv(0))
} else {
p.MOVQ(RAX, self.retv(0))
}
}
}
func (self *Frame) emitRestoreRegs(p *Program) {
// load reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(self.resv(i), r)
case XMMRegister:
p.MOVSD(self.resv(i), r)
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
}
// load reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(self.resv(i), r)
case XMMRegister:
p.MOVSD(self.resv(i), r)
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
}

View file

@ -26,10 +26,10 @@
package abi
import (
`fmt`
`reflect`
"fmt"
"reflect"
. `github.com/cloudwego/iasm/x86_64`
x64 "github.com/bytedance/sonic/loader/internal/iasm/x86_64"
)
/** Frame Structure of the Generated Function
@ -59,258 +59,287 @@
RSP -------------------------------| lower addresses
*/
const zeroRegGo = XMM15
const zeroRegGo = x64.XMM15
var iregOrderGo = [...]Register64 {
RAX,// RDI
RBX,// RSI
RCX,// RDX
RDI,// RCX
RSI,// R8
R8, // R9
R9,
R10,
R11,
var iregOrderGo = [...]Register64{
x64.RAX, // RDI
x64.RBX, // RSI
x64.RCX, // RDX
x64.RDI, // RCX
x64.RSI, // R8
x64.R8, // R9
x64.R9,
x64.R10,
x64.R11,
}
var xregOrderGo = [...]XMMRegister {
XMM0,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7,
XMM8,
XMM9,
XMM10,
XMM11,
XMM12,
XMM13,
XMM14,
var xregOrderGo = [...]XMMRegister{
x64.XMM0,
x64.XMM1,
x64.XMM2,
x64.XMM3,
x64.XMM4,
x64.XMM5,
x64.XMM6,
x64.XMM7,
x64.XMM8,
x64.XMM9,
x64.XMM10,
x64.XMM11,
x64.XMM12,
x64.XMM13,
x64.XMM14,
}
func ReservedRegs(callc bool) []Register {
if callc {
return nil
}
return []Register {
R14, // current goroutine
R15, // GOT reference
}
if callc {
return nil
}
return []Register{
R14, // current goroutine
R15, // GOT reference
}
}
type stackAlloc struct {
s uint32
i int
x int
s uint32
i int
x int
}
func (self *stackAlloc) reset() {
self.i, self.x = 0, 0
self.i, self.x = 0, 0
}
func (self *stackAlloc) ireg(vt reflect.Type) (p Parameter) {
p = mkIReg(vt, iregOrderGo[self.i])
self.i++
return
p = mkIReg(vt, iregOrderGo[self.i])
self.i++
return
}
func (self *stackAlloc) xreg(vt reflect.Type) (p Parameter) {
p = mkXReg(vt, xregOrderGo[self.x])
self.x++
return
p = mkXReg(vt, xregOrderGo[self.x])
self.x++
return
}
func (self *stackAlloc) stack(vt reflect.Type) (p Parameter) {
p = mkStack(vt, self.s)
self.s += uint32(vt.Size())
return
p = mkStack(vt, self.s)
self.s += uint32(vt.Size())
return
}
func (self *stackAlloc) spill(n uint32, a int) uint32 {
self.s = alignUp(self.s, a) + n
return self.s
self.s = alignUp(self.s, a) + n
return self.s
}
func (self *stackAlloc) alloc(p []Parameter, vt reflect.Type) []Parameter {
nb := vt.Size()
vk := vt.Kind()
nb := vt.Size()
vk := vt.Kind()
/* zero-sized objects are allocated on stack */
if nb == 0 {
return append(p, mkStack(intType, self.s))
}
/* zero-sized objects are allocated on stack */
if nb == 0 {
return append(p, mkStack(intType, self.s))
}
/* check for value type */
switch vk {
case reflect.Bool : return self.valloc(p, reflect.TypeOf(false))
case reflect.Int : return self.valloc(p, intType)
case reflect.Int8 : return self.valloc(p, reflect.TypeOf(int8(0)))
case reflect.Int16 : return self.valloc(p, reflect.TypeOf(int16(0)))
case reflect.Int32 : return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Int64 : return self.valloc(p, reflect.TypeOf(int64(0)))
case reflect.Uint : return self.valloc(p, reflect.TypeOf(uint(0)))
case reflect.Uint8 : return self.valloc(p, reflect.TypeOf(uint8(0)))
case reflect.Uint16 : return self.valloc(p, reflect.TypeOf(uint16(0)))
case reflect.Uint32 : return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Uint64 : return self.valloc(p, reflect.TypeOf(uint64(0)))
case reflect.Uintptr : return self.valloc(p, reflect.TypeOf(uintptr(0)))
case reflect.Float32 : return self.valloc(p, reflect.TypeOf(float32(0)))
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")
}
/* check for value type */
switch vk {
case reflect.Bool:
return self.valloc(p, reflect.TypeOf(false))
case reflect.Int:
return self.valloc(p, intType)
case reflect.Int8:
return self.valloc(p, reflect.TypeOf(int8(0)))
case reflect.Int16:
return self.valloc(p, reflect.TypeOf(int16(0)))
case reflect.Int32:
return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Int64:
return self.valloc(p, reflect.TypeOf(int64(0)))
case reflect.Uint:
return self.valloc(p, reflect.TypeOf(uint(0)))
case reflect.Uint8:
return self.valloc(p, reflect.TypeOf(uint8(0)))
case reflect.Uint16:
return self.valloc(p, reflect.TypeOf(uint16(0)))
case reflect.Uint32:
return self.valloc(p, reflect.TypeOf(uint32(0)))
case reflect.Uint64:
return self.valloc(p, reflect.TypeOf(uint64(0)))
case reflect.Uintptr:
return self.valloc(p, reflect.TypeOf(uintptr(0)))
case reflect.Float32:
return self.valloc(p, reflect.TypeOf(float32(0)))
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")
}
}
func (self *stackAlloc) valloc(p []Parameter, vts ...reflect.Type) []Parameter {
for _, vt := range vts {
enum := isFloat(vt)
if enum != notFloatKind && self.x < len(xregOrderGo) {
p = append(p, self.xreg(vt))
} else if enum == notFloatKind && self.i < len(iregOrderGo) {
p = append(p, self.ireg(vt))
} else {
p = append(p, self.stack(vt))
}
}
return p
for _, vt := range vts {
enum := isFloat(vt)
if enum != notFloatKind && self.x < len(xregOrderGo) {
p = append(p, self.xreg(vt))
} else if enum == notFloatKind && self.i < len(iregOrderGo) {
p = append(p, self.ireg(vt))
} else {
p = append(p, self.stack(vt))
}
}
return p
}
func NewFunctionLayout(ft reflect.Type) FunctionLayout {
var sa stackAlloc
var fn FunctionLayout
var sa stackAlloc
var fn FunctionLayout
/* assign every arguments */
for i := 0; i < ft.NumIn(); i++ {
fn.Args = sa.alloc(fn.Args, ft.In(i))
}
/* assign every arguments */
for i := 0; i < ft.NumIn(); i++ {
fn.Args = sa.alloc(fn.Args, ft.In(i))
}
/* reset the register counter, and add a pointer alignment field */
sa.reset()
/* reset the register counter, and add a pointer alignment field */
sa.reset()
/* assign every return value */
for i := 0; i < ft.NumOut(); i++ {
fn.Rets = sa.alloc(fn.Rets, ft.Out(i))
}
/* assign every return value */
for i := 0; i < ft.NumOut(); i++ {
fn.Rets = sa.alloc(fn.Rets, ft.Out(i))
}
sa.spill(0, PtrAlign)
sa.spill(0, PtrAlign)
/* assign spill slots */
for i := 0; i < len(fn.Args); i++ {
if fn.Args[i].InRegister {
fn.Args[i].Mem = sa.spill(PtrSize, PtrAlign) - PtrSize
}
}
/* assign spill slots */
for i := 0; i < len(fn.Args); i++ {
if fn.Args[i].InRegister {
fn.Args[i].Mem = sa.spill(PtrSize, PtrAlign) - PtrSize
}
}
/* add the final pointer alignment field */
fn.FP = sa.spill(0, PtrAlign)
return fn
/* add the final pointer alignment field */
fn.FP = sa.spill(0, PtrAlign)
return fn
}
func (self *Frame) emitExchangeArgs(p *Program) {
iregArgs := make([]Parameter, 0, len(self.desc.Args))
xregArgs := 0
for _, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat != notFloatKind {
xregArgs += 1
} else {
iregArgs = append(iregArgs, v)
}
} else {
panic("not support stack-assgined arguments now")
}
}
if xregArgs > len(xregOrderC) {
panic("too many arguments, only support at most 8 integer register arguments now")
}
iregArgs := make([]Parameter, 0, len(self.desc.Args))
xregArgs := 0
for _, v := range self.desc.Args {
if v.InRegister {
if v.IsFloat != notFloatKind {
xregArgs += 1
} else {
iregArgs = append(iregArgs, v)
}
} else {
panic("not support stack-assgined arguments now")
}
}
if xregArgs > len(xregOrderC) {
panic("too many arguments, only support at most 8 integer register arguments now")
}
switch len(iregArgs) {
case 0, 1, 2, 3: {
//Fast-Path: when arguments count are less than four, just exchange the registers
for i := 0; i < len(iregArgs); i++ {
p.MOVQ(iregOrderGo[i], iregOrderC[i])
}
}
case 4, 5, 6: {
// need to spill 3th ~ regArgs registers before exchange
for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i]
// pointer args have already been spilled
if !arg.IsPointer {
p.MOVQ(iregOrderGo[i], Ptr(RSP, int32(self.Prev() + arg.Mem)))
}
}
p.MOVQ(iregOrderGo[0], iregOrderC[0])
p.MOVQ(iregOrderGo[1], iregOrderC[1])
p.MOVQ(iregOrderGo[2], iregOrderC[2])
for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i]
p.MOVQ(Ptr(RSP, int32(self.Prev() + arg.Mem)), iregOrderC[i])
}
}
default:
panic("too many arguments, only support at most 6 integer register arguments now")
}
switch len(iregArgs) {
case 0, 1, 2, 3:
{
//Fast-Path: when arguments count are less than four, just exchange the registers
for i := 0; i < len(iregArgs); i++ {
p.MOVQ(iregOrderGo[i], iregOrderC[i])
}
}
case 4, 5, 6:
{
// need to spill 3th ~ regArgs registers before exchange
for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i]
// pointer args have already been spilled
if !arg.IsPointer {
p.MOVQ(iregOrderGo[i], Ptr(RSP, int32(self.Prev()+arg.Mem)))
}
}
p.MOVQ(iregOrderGo[0], iregOrderC[0])
p.MOVQ(iregOrderGo[1], iregOrderC[1])
p.MOVQ(iregOrderGo[2], iregOrderC[2])
for i := 3; i < len(iregArgs); i++ {
arg := iregArgs[i]
p.MOVQ(Ptr(RSP, int32(self.Prev()+arg.Mem)), iregOrderC[i])
}
}
default:
panic("too many arguments, only support at most 6 integer register arguments now")
}
}
func (self *Frame) emitStackCheck(p *Program, to *Label, maxStack uintptr) {
p.LEAQ(Ptr(RSP, int32(-(self.Size() + uint32(maxStack)))), R12)
p.CMPQ(Ptr(R14, _G_stackguard0), R12)
p.JBE(to)
p.LEAQ(Ptr(RSP, int32(-(self.Size()+uint32(maxStack)))), R12)
p.CMPQ(Ptr(R14, _G_stackguard0), R12)
p.JBE(to)
}
func (self *Frame) StackCheckTextSize() uint32 {
p := DefaultArch.CreateProgram()
p.LEAQ(Ptr(RSP, int32(-(self.Size()))), R12)
p.CMPQ(Ptr(R14, _G_stackguard0), R12)
to := CreateLabel("")
p.Link(to)
p.JBE(to)
return uint32(len(p.Assemble(0)))
p := DefaultArch.CreateProgram()
p.LEAQ(Ptr(RSP, int32(-(self.Size()))), R12)
p.CMPQ(Ptr(R14, _G_stackguard0), R12)
to := CreateLabel("")
p.Link(to)
p.JBE(to)
return uint32(len(p.Assemble(0)))
}
func (self *Frame) emitExchangeRets(p *Program) {
if len(self.desc.Rets) > 1 {
panic("too many results, only support one result now")
}
// store result
if len(self.desc.Rets) == 1 && !self.desc.Rets[0].InRegister {
if self.desc.Rets[0].IsFloat == floatKind64 {
p.MOVSD(xregOrderC[0], self.retv(0))
} else if self.desc.Rets[0].IsFloat == floatKind32 {
p.MOVSS(xregOrderC[0], self.retv(0))
} else {
p.MOVQ(RAX, self.retv(0))
}
}
if len(self.desc.Rets) > 1 {
panic("too many results, only support one result now")
}
// store result
if len(self.desc.Rets) == 1 && !self.desc.Rets[0].InRegister {
if self.desc.Rets[0].IsFloat == floatKind64 {
p.MOVSD(xregOrderC[0], self.retv(0))
} else if self.desc.Rets[0].IsFloat == floatKind32 {
p.MOVSS(xregOrderC[0], self.retv(0))
} else {
p.MOVQ(RAX, self.retv(0))
}
}
}
func (self *Frame) emitRestoreRegs(p *Program) {
// load reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(self.resv(i), r)
case XMMRegister:
p.MOVSD(self.resv(i), r)
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
// zero xmm15 for go abi
p.XORPS(zeroRegGo, zeroRegGo)
}
// load reserved registers
for i, r := range ReservedRegs(self.ccall) {
switch r.(type) {
case Register64:
p.MOVQ(self.resv(i), r)
case XMMRegister:
p.MOVSD(self.resv(i), r)
default:
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
}
}
// zero xmm15 for go abi
p.XORPS(zeroRegGo, zeroRegGo)
}

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,37 +17,37 @@
package expr
import (
`fmt`
"fmt"
)
// SyntaxError represents a syntax error in the expression.
type SyntaxError struct {
Pos int
Reason string
Pos int
Reason string
}
func newSyntaxError(pos int, reason string) *SyntaxError {
return &SyntaxError {
Pos : pos,
Reason : reason,
}
return &SyntaxError{
Pos: pos,
Reason: reason,
}
}
func (self *SyntaxError) Error() string {
return fmt.Sprintf("Syntax error at position %d: %s", self.Pos, self.Reason)
return fmt.Sprintf("Syntax error at position %d: %s", self.Pos, self.Reason)
}
// RuntimeError is an error which would occure at run time.
type RuntimeError struct {
Reason string
Reason string
}
func newRuntimeError(reason string) *RuntimeError {
return &RuntimeError {
Reason: reason,
}
return &RuntimeError{
Reason: reason,
}
}
func (self *RuntimeError) Error() string {
return "Runtime error: " + self.Reason
return "Runtime error: " + self.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,26 +17,26 @@
package expr
import (
`sync`
"sync"
)
var (
expressionPool sync.Pool
expressionPool sync.Pool
)
func newExpression() *Expr {
if v := expressionPool.Get(); v == nil {
return new(Expr)
} else {
return resetExpression(v.(*Expr))
}
if v := expressionPool.Get(); v == nil {
return new(Expr)
} else {
return resetExpression(v.(*Expr))
}
}
func freeExpression(p *Expr) {
expressionPool.Put(p)
expressionPool.Put(p)
}
func resetExpression(p *Expr) *Expr {
*p = Expr{}
return p
*p = Expr{}
return p
}

View file

@ -18,6 +18,6 @@
// Term represents a value that can Evaluate() into an integer.
type Term interface {
Free()
Evaluate() (int64, error)
Free()
Evaluate() (int64, error)
}

View file

@ -16,62 +16,62 @@
package expr
var op1ch = [...]bool {
'+': true,
'-': true,
'*': true,
'/': true,
'%': true,
'&': true,
'|': true,
'^': true,
'~': true,
'(': true,
')': true,
var op1ch = [...]bool{
'+': true,
'-': true,
'*': true,
'/': true,
'%': true,
'&': true,
'|': true,
'^': true,
'~': true,
'(': true,
')': true,
}
var op2ch = [...]bool {
'*': true,
'<': true,
'>': true,
var op2ch = [...]bool{
'*': true,
'<': true,
'>': true,
}
func neg2(v *Expr, err error) (*Expr, error) {
if err != nil {
return nil, err
} else {
return v.Neg(), nil
}
if err != nil {
return nil, err
} else {
return v.Neg(), nil
}
}
func not2(v *Expr, err error) (*Expr, error) {
if err != nil {
return nil, err
} else {
return v.Not(), nil
}
if err != nil {
return nil, err
} else {
return v.Not(), nil
}
}
func isop1ch(ch rune) bool {
return ch >= 0 && int(ch) < len(op1ch) && op1ch[ch]
return ch >= 0 && int(ch) < len(op1ch) && op1ch[ch]
}
func isop2ch(ch rune) bool {
return ch >= 0 && int(ch) < len(op2ch) && op2ch[ch]
return ch >= 0 && int(ch) < len(op2ch) && op2ch[ch]
}
func isdigit(ch rune) bool {
return ch >= '0' && ch <= '9'
return ch >= '0' && ch <= '9'
}
func isident(ch rune) bool {
return isdigit(ch) || isident0(ch)
return isdigit(ch) || isident0(ch)
}
func isident0(ch rune) bool {
return (ch == '_') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
return (ch == '_') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
}
func ishexdigit(ch rune) bool {
return isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')
return isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')
}

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,63 +17,63 @@
package x86_64
import (
`reflect`
`unsafe`
"reflect"
"unsafe"
)
type _GoType struct {
size uintptr
pdata uintptr
hash uint32
flags uint8
align uint8
falign uint8
kflags uint8
traits unsafe.Pointer
gcdata *byte
str int32
ptrx int32
size uintptr
pdata uintptr
hash uint32
flags uint8
align uint8
falign uint8
kflags uint8
traits unsafe.Pointer
gcdata *byte
str int32
ptrx int32
}
const (
_KindMask = (1 << 5) - 1
_KindMask = (1 << 5) - 1
)
func (self *_GoType) kind() reflect.Kind {
return reflect.Kind(self.kflags & _KindMask)
return reflect.Kind(self.kflags & _KindMask)
}
type _GoSlice struct {
ptr unsafe.Pointer
len int
cap int
ptr unsafe.Pointer
len int
cap int
}
type _GoEface struct {
vt *_GoType
ptr unsafe.Pointer
vt *_GoType
ptr unsafe.Pointer
}
func (self *_GoEface) kind() reflect.Kind {
if self.vt != nil {
return self.vt.kind()
} else {
return reflect.Invalid
}
if self.vt != nil {
return self.vt.kind()
} else {
return reflect.Invalid
}
}
func (self *_GoEface) toInt64() int64 {
if self.vt.size == 8 {
return *(*int64)(self.ptr)
} else if self.vt.size == 4 {
return int64(*(*int32)(self.ptr))
} else if self.vt.size == 2 {
return int64(*(*int16)(self.ptr))
} else {
return int64(*(*int8)(self.ptr))
}
if self.vt.size == 8 {
return *(*int64)(self.ptr)
} else if self.vt.size == 4 {
return int64(*(*int32)(self.ptr))
} else if self.vt.size == 2 {
return int64(*(*int16)(self.ptr))
} else {
return int64(*(*int8)(self.ptr))
}
}
func efaceOf(v interface{}) _GoEface {
return *(*_GoEface)(unsafe.Pointer(&v))
return *(*_GoEface)(unsafe.Pointer(&v))
}

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/bits"
"github.com/cloudwego/iasm/expr"
"github.com/bytedance/sonic/loader/internal/iasm/expr"
)
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),
// 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 {
return func(o *CompileOptions) {
if loop < 0 {

View file

@ -25,7 +25,7 @@
`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`
func String(s string) (ret string, err types.ParsingError) {
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`
func _String(s string, replace bool) (ret string, err error) {
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)
sidx := 0
/* state machine records the invalid postions */
/* state machine records the invalid positions */
m := types.NewStateMachine()
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.
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md
func Zstd(raw []byte, limit uint32) bool {
return len(raw) >= 4 &&
(0x22 <= raw[0] && raw[0] <= 0x28 || raw[0] == 0x1E) && // Different Zstandard versions.
bytes.HasPrefix(raw[1:], []byte{0xB5, 0x2F, 0xFD})
if len(raw) < 4 {
return false
}
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.

View file

@ -110,3 +110,22 @@ func zipContains(raw, sig []byte, msoCheck bool) bool {
}
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.
Extension | MIME type | Aliases
@ -11,6 +11,7 @@ Extension | MIME type | Aliases
**.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | -
**.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | -
**.epub** | application/epub+zip | -
**.apk** | application/vnd.android.package-archive | -
**.jar** | application/jar | -
**.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

View file

@ -44,7 +44,11 @@ func([]byte, uint32) bool { return true },
"application/gzip-compressed", "application/x-gzip-compressed",
"gzip/document")
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")
tar = newMIME("application/x-tar", ".tar", magic.Tar)
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)
epub = newMIME("application/epub+zip", ".epub", magic.Epub)
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)
msi = newMIME("application/x-ms-installer", ".msi", magic.Msi).
alias("application/x-windows-installer", "application/x-msi")

View file

@ -49,7 +49,7 @@ func main() {
}
```
Customized Excluded Extensions
### Customized Excluded Extensions
```go
package main
@ -77,7 +77,7 @@ func main() {
}
```
Customized Excluded Paths
### Customized Excluded Paths
```go
package main
@ -105,7 +105,7 @@ func main() {
}
```
Customized Excluded Paths
### Customized Excluded Paths with Regex
```go
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
import (
"bufio"
"compress/gzip"
"errors"
"net"
"net/http"
"github.com/gin-gonic/gin"
)
@ -11,6 +15,7 @@
BestSpeed = gzip.BestSpeed
DefaultCompression = gzip.DefaultCompression
NoCompression = gzip.NoCompression
HuffmanOnly = gzip.HuffmanOnly
)
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)
}
func (g *gzipWriter) Flush() {
_ = g.writer.Flush()
g.ResponseWriter.Flush()
}
// Fix: https://github.com/mholt/caddy/issues/38
func (g *gzipWriter) WriteHeader(code int) {
g.Header().Del("Content-Length")
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 (
"compress/gzip"
"fmt"
"io"
"net/http"
"path/filepath"
"strconv"
"strings"
"sync"
"github.com/gin-gonic/gin"
)
const (
headerAcceptEncoding = "Accept-Encoding"
headerContentEncoding = "Content-Encoding"
headerVary = "Vary"
)
type gzipHandler struct {
*Options
*config
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{
Options: DefaultOptions,
config: cfg,
gzPool: sync.Pool{
New: func() interface{} {
gz, err := gzip.NewWriterLevel(io.Discard, level)
if err != nil {
panic(err)
}
gz, _ := gzip.NewWriterLevel(io.Discard, level)
return gz
},
},
}
for _, setter := range options {
setter(handler.Options)
}
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) {
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)
}
if !g.shouldCompress(c.Request) {
if g.decompressOnly ||
(g.customShouldCompressFn != nil && !g.customShouldCompressFn(c)) ||
(g.customShouldCompressFn == nil && !g.shouldCompress(c.Request)) {
return
}
gz := g.gzPool.Get().(*gzip.Writer)
defer g.gzPool.Put(gz)
defer gz.Reset(io.Discard)
gz.Reset(c.Writer)
c.Header("Content-Encoding", "gzip")
c.Header("Vary", "Accept-Encoding")
c.Header(headerContentEncoding, "gzip")
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}
defer func() {
if c.Writer.Size() < 0 {
// do not write gzip footer when nothing is written to the response body
gz.Reset(io.Discard)
}
gz.Close()
c.Header("Content-Length", fmt.Sprint(c.Writer.Size()))
_ = gz.Close()
if c.Writer.Size() > -1 {
c.Header("Content-Length", strconv.Itoa(c.Writer.Size()))
}
g.gzPool.Put(gz)
}()
c.Next()
}
func (g *gzipHandler) shouldCompress(req *http.Request) bool {
if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") ||
strings.Contains(req.Header.Get("Connection"), "Upgrade") ||
strings.Contains(req.Header.Get("Accept"), "text/event-stream") {
if !strings.Contains(req.Header.Get(headerAcceptEncoding), "gzip") ||
strings.Contains(req.Header.Get("Connection"), "Upgrade") {
return false
}
// Check if the request path is excluded from compression
extension := filepath.Ext(req.URL.Path)
if g.ExcludedExtensions.Contains(extension) {
return false
}
if g.ExcludedPaths.Contains(req.URL.Path) {
return false
}
if g.ExcludedPathesRegexs.Contains(req.URL.Path) {
if g.excludedExtensions.Contains(extension) ||
g.excludedPaths.Contains(req.URL.Path) ||
g.excludedPathesRegexs.Contains(req.URL.Path) {
return false
}

View file

@ -2,6 +2,8 @@
import (
"compress/gzip"
"errors"
"io"
"net/http"
"regexp"
"strings"
@ -10,58 +12,134 @@
)
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{
".png", ".gif", ".jpeg", ".jpg",
})
DefaultOptions = &Options{
ExcludedExtensions: DefaultExcludedExtentions,
}
// ErrUnsupportedContentEncoding is an error that indicates the content encoding
// is not supported by the application.
ErrUnsupportedContentEncoding = errors.New("unsupported content encoding")
)
type Options struct {
ExcludedExtensions ExcludedExtensions
ExcludedPaths ExcludedPaths
ExcludedPathesRegexs ExcludedPathesRegexs
DecompressFn func(c *gin.Context)
// Option is an interface that defines a method to apply a configuration
// to a given config instance. Implementations of this interface can be
// used to modify the configuration settings of the logger.
type Option interface {
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 {
return func(o *Options) {
o.ExcludedExtensions = NewExcludedExtensions(args)
}
return optionFunc(func(o *config) {
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 {
return func(o *Options) {
o.ExcludedPaths = NewExcludedPaths(args)
}
return optionFunc(func(o *config) {
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 {
return func(o *Options) {
o.ExcludedPathesRegexs = NewExcludedPathesRegexs(args)
}
return optionFunc(func(o *config) {
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 {
return func(o *Options) {
o.DecompressFn = decompressFn
}
return optionFunc(func(o *config) {
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
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 {
res := make(ExcludedExtensions)
res := make(ExcludedExtensions, len(extensions))
for _, e := range extensions {
res[e] = struct{}{}
}
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 {
_, ok := e[target]
return ok
@ -69,10 +147,22 @@ func (e ExcludedExtensions) Contains(target string) bool {
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 {
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 {
for _, path := range e {
if strings.HasPrefix(requestURI, path) {
@ -84,14 +174,26 @@ func (e ExcludedPaths) Contains(requestURI string) bool {
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 {
result := make([]*regexp.Regexp, len(regexs))
result := make(ExcludedPathesRegexs, len(regexs))
for i, reg := range regexs {
result[i] = regexp.MustCompile(reg)
}
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 {
for _, reg := range e {
if reg.MatchString(requestURI) {
@ -101,16 +203,68 @@ func (e ExcludedPathesRegexs) Contains(requestURI string) bool {
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) {
if c.Request.Body == nil {
return
}
r, err := gzip.NewReader(c.Request.Body)
if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)
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)
if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
toClose = append(toClose, c.Request.Body)
c.Request.Body = r
}
c.Request.Header.Del("Content-Encoding")
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
[![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse)
[![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/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)
[![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)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse)
@ -16,32 +16,33 @@ Server-sent events (SSE) is a technology where a browser receives automatic upda
import "github.com/gin-contrib/sse"
func httpHandler(w http.ResponseWriter, req *http.Request) {
// data can be a primitive like a string, an integer or a float
sse.Encode(w, sse.Event{
Event: "message",
Data: "some data\nmore data",
})
// data can be a primitive like a string, an integer or a float
sse.Encode(w, sse.Event{
Event: "message",
Data: "some data\nmore data",
})
// also a complex type, like a map, a struct or a slice
sse.Encode(w, sse.Event{
Id: "124",
Event: "message",
Data: map[string]interface{}{
"user": "manu",
"date": time.Now().Unix(),
"content": "hi!",
},
})
// also a complex type, like a map, a struct or a slice
sse.Encode(w, sse.Event{
Id: "124",
Event: "message",
Data: map[string]interface{}{
"user": "manu",
"date": time.Now().Unix(),
"content": "hi!",
},
})
}
```
```
```sh
event: message
data: some data\\nmore data
id: 124
event: message
data: {"content":"hi!","date":1431540810,"user":"manu"}
```
## Content-Type
@ -49,7 +50,8 @@ data: {"content":"hi!","date":1431540810,"user":"manu"}
```go
fmt.Println(sse.ContentType)
```
```
```sh
text/event-stream
```

View file

@ -18,7 +18,7 @@
// W3C Working Draft 29 October 2009
// 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 noCache = []string{"no-cache"}
@ -72,6 +72,14 @@ func writeRetry(w stringWriter, retry uint) {
func writeData(w stringWriter, data interface{}) error {
w.WriteString("data:")
bData, ok := data.([]byte)
if ok {
dataReplacer.WriteString(w, string(bData))
w.WriteString("\n\n")
return nil
}
switch kindOfData(data) {
case reflect.Struct, reflect.Slice, reflect.Map:
err := json.NewEncoder(w).Encode(data)

View file

@ -1,7 +1,7 @@
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)
![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)
[![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)
@ -22,6 +22,11 @@ It has the following **unique** features:
- 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)
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
------------
@ -266,74 +271,75 @@ validate := validator.New(validator.WithRequiredStructEnabled())
Benchmarks
------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64
###### Run on MacBook Pro Max M3
```go
go version go1.21.0 darwin/arm64
go version go1.23.3 darwin/arm64
goos: darwin
goarch: arm64
cpu: Apple M3 Max
pkg: github.com/go-playground/validator/v10
BenchmarkFieldSuccess-8 33142266 35.94 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 200816191 6.568 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 6779707 175.1 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 11044147 108.4 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 6054232 194.4 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 12523388 94.07 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-8 3587043 334.3 ns/op 300 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5816665 200.8 ns/op 300 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-8 2217910 540.1 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 4446698 258.7 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-8 2392759 504.6 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 4244199 286.9 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 2005857 592.1 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 4400850 296.9 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1850227 643.8 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3293233 375.1 ns/op 553 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 12174412 98.25 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 34389907 35.49 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 7582524 156.6 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 13019902 92.79 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-8 3427260 349.4 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 15144128 81.25 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 5913546 201.9 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 9810212 113.7 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 13456327 87.66 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 41818888 27.77 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-8 4166284 272.6 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 7594581 152.1 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 6508082 182.6 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 23078605 54.78 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 3118352 381.0 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 5300738 224.1 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 4761807 251.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-8 8792598 128.6 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-8 5202573 232.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-8 9591267 121.4 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-8 5188512 231.6 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-8 9179776 123.1 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-8 3071212 392.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-8 5344261 223.7 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-8 3184230 375.0 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-8 10090130 108.9 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-8 3347226 357.7 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-8 5654923 209.5 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5232265 229.1 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 17436674 64.75 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 3128613 383.6 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 6994113 168.8 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3506487 340.9 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 13431300 91.77 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2410566 500.9 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 6344510 188.2 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 8922726 133.8 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 55291153 23.63 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 3171553 378.4 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 5571692 212.0 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1683750 714.5 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-8 4578046 257.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-8 481585 2547 ns/op 3041 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-8 965764 1577 ns/op 3040 B/op 48 allocs/op
BenchmarkOneof-8 17380881 68.50 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-8 8084733 153.5 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccess-16 42461943 27.88 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-16 486632887 2.289 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-16 9566167 121.3 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-16 17551471 83.68 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-16 7602306 155.6 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-16 20664610 59.80 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-16 4659756 252.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-16 8010116 152.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-16 2834575 421.2 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-16 7179700 171.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-16 3081728 384.4 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-16 6058137 204.0 ns/op 377 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-16 2544975 464.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-16 6661954 181.4 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-16 2435484 490.7 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-16 4249617 282.0 ns/op 554 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-16 14943525 77.35 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-16 64051954 20.61 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-16 10721384 107.1 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-16 18714495 69.77 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-16 4063124 294.3 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-16 31903756 41.22 ns/op 18 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-16 7748558 146.8 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-16 13139854 92.05 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-16 16808389 70.25 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-16 90686955 14.47 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-16 5818791 200.2 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-16 11115874 107.5 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-16 7764956 151.9 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-16 52316265 30.37 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-16 4195429 277.2 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-16 7305661 164.6 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-16 6312625 186.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-16 13684459 93.42 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-16 6751482 171.2 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-16 14146070 86.93 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-16 6544448 177.3 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-16 13951946 88.73 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-16 4075833 287.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-16 7490805 161.3 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-16 4107187 281.4 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-16 15979173 80.86 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-16 4434372 264.3 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-16 8081367 154.1 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-16 6459542 183.4 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-16 41013781 37.95 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-16 4034998 292.1 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-16 11348446 115.3 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-16 4448528 267.7 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-16 26813619 48.33 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-16 3090646 384.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-16 9870906 129.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-16 10675562 109.5 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-16 131159784 8.932 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-16 4094979 286.6 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-16 7606663 157.9 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-16 2073470 576.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-16 7821831 161.3 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-16 576358 2001 ns/op 3042 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-16 1000000 1171 ns/op 3041 B/op 48 allocs/op
BenchmarkOneof-16 22503973 52.82 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-16 8538474 140.4 ns/op 0 B/op 0 allocs/op
```
Complementary Software
@ -349,6 +355,20 @@ How to Contribute
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
-------
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{}
for i := 0; i < mi.Desc.Oneofs().Len(); i++ {
od := mi.Desc.Oneofs().Get(i)
if !od.IsSynthetic() {
mi.oneofs[od.Name()] = makeOneofInfo(od, si.structInfo, mi.Exporter)
}
mi.oneofs[od.Name()] = makeOneofInfoOpaque(mi, od, si.structInfo, mi.Exporter)
}
mi.denseFields = make([]*fieldInfo, fds.Len()*2)
@ -119,6 +117,26 @@ func opaqueInitHook(mi *MessageInfo) bool {
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 {
ft := fs.Type
if ft.Kind() != reflect.Map {

View file

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

26
vendor/modules.txt vendored
View file

@ -101,7 +101,7 @@ github.com/beorn7/perks/quantile
## explicit; go 1.14
github.com/buckket/go-blurhash
github.com/buckket/go-blurhash/base83
# github.com/bytedance/sonic v1.12.6
# github.com/bytedance/sonic v1.12.7
## explicit; go 1.17
github.com/bytedance/sonic
github.com/bytedance/sonic/ast
@ -135,10 +135,12 @@ github.com/bytedance/sonic/internal/utils
github.com/bytedance/sonic/option
github.com/bytedance/sonic/unquote
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
github.com/bytedance/sonic/loader
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/cenkalti/backoff/v4 v4.3.0
## explicit; go 1.18
@ -158,10 +160,6 @@ github.com/cilium/ebpf/link
# github.com/cloudwego/base64x v0.1.4
## explicit; go 1.16
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
## explicit; go 1.17
github.com/containerd/cgroups/v3
@ -208,7 +206,7 @@ github.com/felixge/httpsnoop
# github.com/fsnotify/fsnotify v1.7.0
## explicit; go 1.17
github.com/fsnotify/fsnotify
# github.com/gabriel-vasile/mimetype v1.4.7
# github.com/gabriel-vasile/mimetype v1.4.8
## explicit; go 1.20
github.com/gabriel-vasile/mimetype
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
## explicit; go 1.21.0
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
github.com/gin-contrib/gzip
# github.com/gin-contrib/sessions v1.0.2
## explicit; go 1.20
github.com/gin-contrib/sessions
github.com/gin-contrib/sessions/memstore
# github.com/gin-contrib/sse v0.1.0
## explicit; go 1.12
# github.com/gin-contrib/sse v1.0.0
## explicit; go 1.13
github.com/gin-contrib/sse
# github.com/gin-gonic/gin v1.10.0
## explicit; go 1.20
@ -312,8 +310,8 @@ github.com/go-playground/locales/currency
# github.com/go-playground/universal-translator v0.18.1
## explicit; go 1.18
github.com/go-playground/universal-translator
# github.com/go-playground/validator/v10 v10.23.0
## explicit; go 1.18
# github.com/go-playground/validator/v10 v10.24.0
## explicit; go 1.20
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
## explicit; go 1.21
@ -1077,7 +1075,7 @@ go.uber.org/automaxprocs/maxprocs
# go.uber.org/multierr v1.11.0
## explicit; go 1.19
go.uber.org/multierr
# golang.org/x/arch v0.12.0
# golang.org/x/arch v0.13.0
## explicit; go 1.18
golang.org/x/arch/x86/x86asm
# 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/status
google.golang.org/grpc/tap
# google.golang.org/protobuf v1.36.1
# google.golang.org/protobuf v1.36.2
## explicit; go 1.21
google.golang.org/protobuf/encoding/protodelim
google.golang.org/protobuf/encoding/protojson