diff --git a/go.mod b/go.mod index e169fae..cf1f10b 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,36 @@ module golang.design/x/ssaplayground go 1.19 require ( - github.com/gin-gonic/gin v1.8.2 + github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 - golang.org/x/tools v0.4.0 + golang.org/x/tools v0.6.0 gopkg.in/yaml.v2 v2.4.0 ) require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.11.1 // indirect - github.com/goccy/go-json v0.9.11 // 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.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/leodido/go-urn v1.2.1 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect - golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d4a5739..5c3b627 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,27 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= 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-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= -github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +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.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -24,78 +30,64 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/vendor/github.com/bytedance/sonic/.gitignore b/vendor/github.com/bytedance/sonic/.gitignore new file mode 100644 index 0000000..0d88447 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/.gitignore @@ -0,0 +1,52 @@ +*.o +*.swp +*.swm +*.swn +*.a +*.so +_obj +_test +*.[568vq] +[568vq].out +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* +_testmain.go +*.exe +*.exe~ +*.test +*.prof +*.rar +*.zip +*.gz +*.psd +*.bmd +*.cfg +*.pptx +*.log +*nohup.out +*settings.pyc +*.sublime-project +*.sublime-workspace +.DS_Store +/.idea/ +/.vscode/ +/output/ +/vendor/ +/Gopkg.lock +/Gopkg.toml +coverage.html +coverage.out +coverage.xml +junit.xml +*.profile +*.svg +*.out +ast/test.out +ast/bench.sh + +!testdata/*.json.gz +fuzz/testdata +*__debug_bin \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/.gitmodules b/vendor/github.com/bytedance/sonic/.gitmodules new file mode 100644 index 0000000..b8d11c9 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools/asm2asm"] + path = tools/asm2asm + url = https://github.com/chenzhuoyu/asm2asm diff --git a/vendor/github.com/bytedance/sonic/.licenserc.yaml b/vendor/github.com/bytedance/sonic/.licenserc.yaml new file mode 100644 index 0000000..1cb993e --- /dev/null +++ b/vendor/github.com/bytedance/sonic/.licenserc.yaml @@ -0,0 +1,24 @@ +header: + license: + spdx-id: Apache-2.0 + copyright-owner: ByteDance Inc. + + paths: + - '**/*.go' + - '**/*.s' + + paths-ignore: + - 'ast/asm.s' # empty file + - 'decoder/asm.s' # empty file + - 'encoder/asm.s' # empty file + - 'internal/caching/asm.s' # empty file + - 'internal/jit/asm.s' # empty file + - 'internal/native/avx/native_amd64.s' # auto-generated by asm2asm + - 'internal/native/avx/native_subr_amd64.go' # auto-generated by asm2asm + - 'internal/native/avx2/native_amd64.s' # auto-generated by asm2asm + - 'internal/native/avx2/native_subr_amd64.go' # auto-generated by asm2asm + - 'internal/resolver/asm.s' # empty file + - 'internal/rt/asm.s' # empty file + - 'internal/loader/asm.s' # empty file + + comment: on-failure \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/CODE_OF_CONDUCT.md b/vendor/github.com/bytedance/sonic/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..8505feb --- /dev/null +++ b/vendor/github.com/bytedance/sonic/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +wudi.daniel@bytedance.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/vendor/github.com/bytedance/sonic/CONTRIBUTING.md b/vendor/github.com/bytedance/sonic/CONTRIBUTING.md new file mode 100644 index 0000000..7f63c66 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# How to Contribute + +## Your First Pull Request +We use GitHub for our codebase. You can start by reading [How To Pull Request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests). + +## Without Semantic Versioning +We keep the stable code in branch `main` like `golang.org/x`. Development base on branch `develop`. We promise the **Forward Compatibility** by adding new package directory with suffix `v2/v3` when code has break changes. + +## Branch Organization +We use [git-flow](https://nvie.com/posts/a-successful-git-branching-model/) as our branch organization, as known as [FDD](https://en.wikipedia.org/wiki/Feature-driven_development) + + +## Bugs +### 1. How to Find Known Issues +We are using [Github Issues](https://github.com/bytedance/sonic/issues) for our public bugs. We keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn’t already exist. + +### 2. Reporting New Issues +Providing a reduced test code is a recommended way for reporting issues. Then can be placed in: +- Just in issues +- [Golang Playground](https://play.golang.org/) + +### 3. Security Bugs +Please do not report the safe disclosure of bugs to public issues. Contact us by [Support Email](mailto:sonic@bytedance.com) + +## How to Get in Touch +- [Email](mailto:wudi.daniel@bytedance.com) + +## Submit a Pull Request +Before you submit your Pull Request (PR) consider the following guidelines: +1. Search [GitHub](https://github.com/bytedance/sonic/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate existing efforts. +2. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add. Discussing the design upfront helps to ensure that we're ready to accept your work. +3. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the bytedance/sonic repo. +4. In your forked repository, make your changes in a new git branch: + ``` + git checkout -b bugfix/security_bug develop + ``` +5. Create your patch, including appropriate test cases. +6. Follow our [Style Guides](#code-style-guides). +7. Commit your changes using a descriptive commit message that follows [AngularJS Git Commit Message Conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit). + Adherence to these conventions is necessary because release notes will be automatically generated from these messages. +8. Push your branch to GitHub: + ``` + git push origin bugfix/security_bug + ``` +9. In GitHub, send a pull request to `sonic:main` + +Note: you must use one of `optimize/feature/bugfix/doc/ci/test/refactor` following a slash(`/`) as the branch prefix. + +Your pr title and commit message should follow https://www.conventionalcommits.org/. + +## Contribution Prerequisites +- Our development environment keeps up with [Go Official](https://golang.org/project/). +- You need fully checking with lint tools before submit your pull request. [gofmt](https://golang.org/pkg/cmd/gofmt/) & [golangci-lint](https://github.com/golangci/golangci-lint) +- You are familiar with [Github](https://github.com) +- Maybe you need familiar with [Actions](https://github.com/features/actions)(our default workflow tool). + +## Code Style Guides +See [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments). + +Good resources: +- [Effective Go](https://golang.org/doc/effective_go) +- [Pingcap General advice](https://pingcap.github.io/style-guide/general.html) +- [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) diff --git a/vendor/github.com/bytedance/sonic/CREDITS b/vendor/github.com/bytedance/sonic/CREDITS new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/bytedance/sonic/LICENSE b/vendor/github.com/bytedance/sonic/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/LICENSE @@ -0,0 +1,201 @@ + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/bytedance/sonic/Makefile b/vendor/github.com/bytedance/sonic/Makefile new file mode 100644 index 0000000..8cc0acf --- /dev/null +++ b/vendor/github.com/bytedance/sonic/Makefile @@ -0,0 +1,112 @@ +# +# Copyright 2021 ByteDance Inc. +# +# 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. +# + +ARCH := avx avx2 sse +TMP_DIR := output +OUT_DIR := internal/native +SRC_FILE := native/native.c + +CPU_avx := amd64 +CPU_avx2 := amd64 +CPU_sse := amd64 + +TMPL_avx := fastint_amd64_test fastfloat_amd64_test native_amd64_test native_export_amd64 +TMPL_avx2 := fastint_amd64_test fastfloat_amd64_test native_amd64_test native_export_amd64 +TMPL_sse := fastint_amd64_test fastfloat_amd64_test native_amd64_test native_export_amd64 + +CFLAGS_avx := -msse -mno-sse4 -mavx -mpclmul -mno-avx2 -DUSE_AVX=1 -DUSE_AVX2=0 +CFLAGS_avx2 := -msse -mno-sse4 -mavx -mpclmul -mavx2 -DUSE_AVX=1 -DUSE_AVX2=1 +CFLAGS_sse := -msse -mno-sse4 -mno-avx -mno-avx2 -mpclmul + +CC_amd64 := clang +ASM2ASM_amd64 := tools/asm2asm/asm2asm.py + +CFLAGS := -mno-red-zone +CFLAGS += -target x86_64-apple-macos11 +CFLAGS += -fno-asynchronous-unwind-tables +CFLAGS += -fno-builtin +CFLAGS += -fno-exceptions +CFLAGS += -fno-rtti +CFLAGS += -fno-stack-protector +CFLAGS += -nostdlib +CFLAGS += -O3 +CFLAGS += -Wall -Werror + +NATIVE_SRC := $(wildcard native/*.h) +NATIVE_SRC += $(wildcard native/*.c) + +.PHONY: all clean ${ARCH} + +define build_tmpl + $(eval @arch := $(1)) + $(eval @tmpl := $(2)) + $(eval @dest := $(3)) + +${@dest}: ${@tmpl} + mkdir -p $(dir ${@dest}) + echo '// Code generated by Makefile, DO NOT EDIT.' > ${@dest} + echo >> ${@dest} + sed -e 's/{{PACKAGE}}/${@arch}/g' ${@tmpl} >> ${@dest} +endef + +define build_arch + $(eval @cpu := $(value CPU_$(1))) + $(eval @deps := $(foreach tmpl,$(value TMPL_$(1)),${OUT_DIR}/$(1)/${tmpl}.go)) + $(eval @asmin := ${TMP_DIR}/$(1)/native.s) + $(eval @asmout := ${OUT_DIR}/$(1)/native_${@cpu}.s) + $(eval @stubin := ${OUT_DIR}/native_${@cpu}.tmpl) + $(eval @stubout := ${OUT_DIR}/$(1)/native_${@cpu}.go) + +$(1): ${@asmout} ${@deps} + +${@asmout}: ${@stubout} ${NATIVE_SRC} + mkdir -p ${TMP_DIR}/$(1) + $${CC_${@cpu}} $${CFLAGS} $${CFLAGS_$(1)} -S -o ${TMP_DIR}/$(1)/native.s ${SRC_FILE} + python3 $${ASM2ASM_${@cpu}} ${@asmout} ${TMP_DIR}/$(1)/native.s + asmfmt -w ${@asmout} + +$(eval $(call \ + build_tmpl, \ + $(1), \ + ${@stubin}, \ + ${@stubout} \ +)) + +$(foreach \ + tmpl, \ + $(value TMPL_$(1)), \ + $(eval $(call \ + build_tmpl, \ + $(1), \ + ${OUT_DIR}/${tmpl}.tmpl, \ + ${OUT_DIR}/$(1)/${tmpl}.go \ + )) \ +) +endef + +all: ${ARCH} + +clean: + for arch in ${ARCH}; do \ + rm -vfr ${TMP_DIR}/$${arch}; \ + rm -vfr ${OUT_DIR}/$${arch}; \ + done + +$(foreach \ + arch, \ + ${ARCH}, \ + $(eval $(call build_arch,${arch})) \ +) diff --git a/vendor/github.com/bytedance/sonic/README.md b/vendor/github.com/bytedance/sonic/README.md new file mode 100644 index 0000000..cdb32a5 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/README.md @@ -0,0 +1,362 @@ +# Sonic + +English | [中文](README_ZH_CN.md) + +A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data). + +## Requirement +- Go 1.15~1.20 +- Linux/MacOS/Windows +- Amd64 ARCH + +## Features +- Runtime object binding without code generation +- Complete APIs for JSON value manipulation +- Fast, fast, fast! + +## Benchmarks +For **all sizes** of json and **all scenarios** of usage, **Sonic performs best**. +- [Medium](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13KB, 300+ key, 6 layers) +```powershell +goversion: 1.17.1 +goos: darwin +goarch: amd64 +cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz +BenchmarkEncoder_Generic_Sonic-16 32393 ns/op 402.40 MB/s 11965 B/op 4 allocs/op +BenchmarkEncoder_Generic_Sonic_Fast-16 21668 ns/op 601.57 MB/s 10940 B/op 4 allocs/op +BenchmarkEncoder_Generic_JsonIter-16 42168 ns/op 309.12 MB/s 14345 B/op 115 allocs/op +BenchmarkEncoder_Generic_GoJson-16 65189 ns/op 199.96 MB/s 23261 B/op 16 allocs/op +BenchmarkEncoder_Generic_StdLib-16 106322 ns/op 122.60 MB/s 49136 B/op 789 allocs/op +BenchmarkEncoder_Binding_Sonic-16 6269 ns/op 2079.26 MB/s 14173 B/op 4 allocs/op +BenchmarkEncoder_Binding_Sonic_Fast-16 5281 ns/op 2468.16 MB/s 12322 B/op 4 allocs/op +BenchmarkEncoder_Binding_JsonIter-16 20056 ns/op 649.93 MB/s 9488 B/op 2 allocs/op +BenchmarkEncoder_Binding_GoJson-16 8311 ns/op 1568.32 MB/s 9481 B/op 1 allocs/op +BenchmarkEncoder_Binding_StdLib-16 16448 ns/op 792.52 MB/s 9479 B/op 1 allocs/op +BenchmarkEncoder_Parallel_Generic_Sonic-16 6681 ns/op 1950.93 MB/s 12738 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Generic_Sonic_Fast-16 4179 ns/op 3118.99 MB/s 10757 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Generic_JsonIter-16 9861 ns/op 1321.84 MB/s 14362 B/op 115 allocs/op +BenchmarkEncoder_Parallel_Generic_GoJson-16 18850 ns/op 691.52 MB/s 23278 B/op 16 allocs/op +BenchmarkEncoder_Parallel_Generic_StdLib-16 45902 ns/op 283.97 MB/s 49174 B/op 789 allocs/op +BenchmarkEncoder_Parallel_Binding_Sonic-16 1480 ns/op 8810.09 MB/s 13049 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Binding_Sonic_Fast-16 1209 ns/op 10785.23 MB/s 11546 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Binding_JsonIter-16 6170 ns/op 2112.58 MB/s 9504 B/op 2 allocs/op +BenchmarkEncoder_Parallel_Binding_GoJson-16 3321 ns/op 3925.52 MB/s 9496 B/op 1 allocs/op +BenchmarkEncoder_Parallel_Binding_StdLib-16 3739 ns/op 3486.49 MB/s 9480 B/op 1 allocs/op + +BenchmarkDecoder_Generic_Sonic-16 66812 ns/op 195.10 MB/s 57602 B/op 723 allocs/op +BenchmarkDecoder_Generic_Sonic_Fast-16 54523 ns/op 239.07 MB/s 49786 B/op 313 allocs/op +BenchmarkDecoder_Generic_StdLib-16 124260 ns/op 104.90 MB/s 50869 B/op 772 allocs/op +BenchmarkDecoder_Generic_JsonIter-16 91274 ns/op 142.81 MB/s 55782 B/op 1068 allocs/op +BenchmarkDecoder_Generic_GoJson-16 88569 ns/op 147.17 MB/s 66367 B/op 973 allocs/op +BenchmarkDecoder_Binding_Sonic-16 32557 ns/op 400.38 MB/s 28302 B/op 137 allocs/op +BenchmarkDecoder_Binding_Sonic_Fast-16 28649 ns/op 455.00 MB/s 24999 B/op 34 allocs/op +BenchmarkDecoder_Binding_StdLib-16 111437 ns/op 116.97 MB/s 10576 B/op 208 allocs/op +BenchmarkDecoder_Binding_JsonIter-16 35090 ns/op 371.48 MB/s 14673 B/op 385 allocs/op +BenchmarkDecoder_Binding_GoJson-16 28738 ns/op 453.59 MB/s 22039 B/op 49 allocs/op +BenchmarkDecoder_Parallel_Generic_Sonic-16 12321 ns/op 1057.91 MB/s 57233 B/op 723 allocs/op +BenchmarkDecoder_Parallel_Generic_Sonic_Fast-16 10644 ns/op 1224.64 MB/s 49362 B/op 313 allocs/op +BenchmarkDecoder_Parallel_Generic_StdLib-16 57587 ns/op 226.35 MB/s 50874 B/op 772 allocs/op +BenchmarkDecoder_Parallel_Generic_JsonIter-16 38666 ns/op 337.12 MB/s 55789 B/op 1068 allocs/op +BenchmarkDecoder_Parallel_Generic_GoJson-16 30259 ns/op 430.79 MB/s 66370 B/op 974 allocs/op +BenchmarkDecoder_Parallel_Binding_Sonic-16 5965 ns/op 2185.28 MB/s 27747 B/op 137 allocs/op +BenchmarkDecoder_Parallel_Binding_Sonic_Fast-16 5170 ns/op 2521.31 MB/s 24715 B/op 34 allocs/op +BenchmarkDecoder_Parallel_Binding_StdLib-16 27582 ns/op 472.58 MB/s 10576 B/op 208 allocs/op +BenchmarkDecoder_Parallel_Binding_JsonIter-16 13571 ns/op 960.51 MB/s 14685 B/op 385 allocs/op +BenchmarkDecoder_Parallel_Binding_GoJson-16 10031 ns/op 1299.51 MB/s 22111 B/op 49 allocs/op + +BenchmarkGetOne_Sonic-16 3276 ns/op 3975.78 MB/s 24 B/op 1 allocs/op +BenchmarkGetOne_Gjson-16 9431 ns/op 1380.81 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Jsoniter-16 51178 ns/op 254.46 MB/s 27936 B/op 647 allocs/op +BenchmarkGetOne_Parallel_Sonic-16 216.7 ns/op 60098.95 MB/s 24 B/op 1 allocs/op +BenchmarkGetOne_Parallel_Gjson-16 1076 ns/op 12098.62 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Parallel_Jsoniter-16 17741 ns/op 734.06 MB/s 27945 B/op 647 allocs/op +BenchmarkSetOne_Sonic-16 9571 ns/op 1360.61 MB/s 1584 B/op 17 allocs/op +BenchmarkSetOne_Sjson-16 36456 ns/op 357.22 MB/s 52180 B/op 9 allocs/op +BenchmarkSetOne_Jsoniter-16 79475 ns/op 163.86 MB/s 45862 B/op 964 allocs/op +BenchmarkSetOne_Parallel_Sonic-16 850.9 ns/op 15305.31 MB/s 1584 B/op 17 allocs/op +BenchmarkSetOne_Parallel_Sjson-16 18194 ns/op 715.77 MB/s 52247 B/op 9 allocs/op +BenchmarkSetOne_Parallel_Jsoniter-16 33560 ns/op 388.05 MB/s 45892 B/op 964 allocs/op +``` +- [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers) +![small benchmarks](./docs/imgs/bench-small.png) +- [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635KB, 10000+ key, 6 layers) +![large benchmarks](./docs/imgs/bench-large.png) + +See [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) for benchmark codes. + +## How it works +See [INTRODUCTION.md](./docs/INTRODUCTION.md). + +## Usage + +### Marshal/Unmarshal + +Default behaviors are mostly consistent with `encoding/json`, except HTML escaping form (see [Escape HTML](https://github.com/bytedance/sonic/blob/main/README.md#escape-html)) and `SortKeys` feature (optional support see [Sort Keys](https://github.com/bytedance/sonic/blob/main/README.md#sort-keys)) that is **NOT** in conformity to [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). + ```go +import "github.com/bytedance/sonic" + +var data YourSchema +// Marshal +output, err := sonic.Marshal(&data) +// Unmarshal +err := sonic.Unmarshal(output, &data) + ``` + +### Streaming IO +Sonic supports decoding json from `io.Reader` or encoding objects into `io.`Writer`, aims at handling multiple values as well as reducing memory consumption. +- encoder +```go +var o1 = map[string]interface{}{ + "a": "b", +} +var o2 = 1 +var w = bytes.NewBuffer(nil) +var enc = sonic.ConfigDefault.NewEncoder(w) +enc.Encode(o1) +enc.Encode(o2) +fmt.Println(w.String()) +// Output: +// {"a":"b"} +// 1 +``` +- decoder +```go +var o = map[string]interface{}{} +var r = strings.NewReader(`{"a":"b"}{"1":"2"}`) +var dec = sonic.ConfigDefault.NewDecoder(r) +dec.Decode(&o) +dec.Decode(&o) +fmt.Printf("%+v", o) +// Output: +// map[1:2 a:b] +``` + +### Use Number/Use Int64 + ```go +import "github.com/bytedance/sonic/decoder" + +var input = `1` +var data interface{} + +// default float64 +dc := decoder.NewDecoder(input) +dc.Decode(&data) // data == float64(1) +// use json.Number +dc = decoder.NewDecoder(input) +dc.UseNumber() +dc.Decode(&data) // data == json.Number("1") +// use int64 +dc = decoder.NewDecoder(input) +dc.UseInt64() +dc.Decode(&data) // data == int64(1) + +root, err := sonic.GetFromString(input) +// Get json.Number +jn := root.Number() +jm := root.InterfaceUseNumber().(json.Number) // jn == jm +// Get float64 +fn := root.Float64() +fm := root.Interface().(float64) // jn == jm + ``` + +### Sort Keys +On account of the performance loss from sorting (roughly 10%), sonic doesn't enable this feature by default. If your component depends on it to work (like [zstd](https://github.com/facebook/zstd)), Use it like this: +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/encoder" + +// Binding map only +m := map[string]interface{}{} +v, err := encoder.Encode(m, encoder.SortMapKeys) + +// Or ast.Node.SortKeys() before marshal +var root := sonic.Get(JSON) +err := root.SortKeys() +``` +### Escape HTML +On account of the performance loss (roughly 15%), sonic doesn't enable this feature by default. You can use `encoder.EscapeHTML` option to open this feature (align with `encoding/json.HTMLEscape`). +```go +import "github.com/bytedance/sonic" + +v := map[string]string{"&&":"<>"} +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. + +### Print Error +If there invalid syntax in input JSON, sonic will return `decoder.SyntaxError`, which supports pretty-printing of error position +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/decoder" + +var data interface{} +err := sonic.UnmarshalString("[[[}]]", &data) +if err != nil { + /* One line by default */ + println(e.Error()) // "Syntax error at index 3: invalid char\n\n\t[[[}]]\n\t...^..\n" + /* Pretty print */ + if e, ok := err.(decoder.SyntaxError); ok { + /*Syntax error at index 3: invalid char + + [[[}]] + ...^.. + */ + print(e.Description()) + } else if me, ok := err.(*decoder.MismatchTypeError); ok { + // decoder.MismatchTypeError is new to Sonic v1.6.0 + print(me.Description()) + } +} +``` + +#### Mismatched Types [Sonic v1.6.0] +If there a **mismatch-typed** value for a given key, sonic will report `decoder.MismatchTypeError` (if there are many, report the last one), but still skip wrong the value and keep decoding next JSON. +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/decoder" + +var data = struct{ + A int + B int +}{} +err := UnmarshalString(`{"A":"1","B":1}`, &data) +println(err.Error()) // Mismatch type int with value string "at index 5: mismatched type with value\n\n\t{\"A\":\"1\",\"B\":1}\n\t.....^.........\n" +fmt.Printf("%+v", data) // {A:0 B:1} +``` +### Ast.Node +Sonic/ast.Node is a completely self-contained AST for JSON. It implements serialization and deserialization both and provides robust APIs for obtaining and modification of generic data. +#### Get/Index +Search partial JSON by given paths, which must be non-negative integer or string, or nil +```go +import "github.com/bytedance/sonic" + +input := []byte(`{"key1":[{},{"key2":{"key3":[1,2,3]}}]}`) + +// no path, returns entire json +root, err := sonic.Get(input) +raw := root.Raw() // == string(input) + +// multiple paths +root, err := sonic.Get(input, "key1", 1, "key2") +sub := root.Get("key3").Index(2).Int64() // == 3 +``` +**Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensure the key is matched. + +#### Set/Unset +Modify the json content by Set()/Unset() +```go +import "github.com/bytedance/sonic" + +// Set +exist, err := root.Set("key4", NewBool(true)) // exist == false +alias1 := root.Get("key4") +println(alias1.Valid()) // true +alias2 := root.Index(1) +println(alias1 == alias2) // true + +// Unset +exist, err := root.UnsetByIndex(1) // exist == true +println(root.Get("key4").Check()) // "value not exist" +``` + +#### Serialize +To encode `ast.Node` as json, use `MarshalJson()` or `json.Marshal()` (MUST pass the node's pointer) +```go +import ( + "encoding/json" + "github.com/bytedance/sonic" +) + +buf, err := root.MarshalJson() +println(string(buf)) // {"key1":[{},{"key2":{"key3":[1,2,3]}}]} +exp, err := json.Marshal(&root) // WARN: use pointer +println(string(buf) == string(exp)) // true +``` + +#### APIs +- validation: `Check()`, `Error()`, `Valid()`, `Exist()` +- searching: `Index()`, `Get()`, `IndexPair()`, `IndexOrGet()`, `GetByPath()` +- go-type casting: `Int64()`, `Float64()`, `String()`, `Number()`, `Bool()`, `Map[UseNumber|UseNode]()`, `Array[UseNumber|UseNode]()`, `Interface[UseNumber|UseNode]()` +- go-type packing: `NewRaw()`, `NewNumber()`, `NewNull()`, `NewBool()`, `NewString()`, `NewObject()`, `NewArray()` +- iteration: `Values()`, `Properties()`, `ForEach()`, `SortKeys()` +- modification: `Set()`, `SetByIndex()`, `Add()` + +## Compatibility +Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. For developers who use sonic to build their applications in different environments, we have the following suggestions: + +- Developing on **Mac M1**: Make sure you have Rosetta 2 installed on your machine, and set `GOARCH=amd64` when building your application. Rosetta 2 can automatically translate x86 binaries to arm64 binaries and run x86 applications on Mac M1. +- Developing on **Linux arm64**: You can install qemu and use the `qemu-x86_64 -cpu max` command to convert x86 binaries to amr64 binaries for applications built with sonic. The qemu can achieve a similar transfer effect to Rosetta 2 on Mac M1. + +For developers who want to use sonic on Linux arm64 without qemu, or those who want to handle JSON strictly consistent with `encoding/json`, we provide some compatible APIs as `sonic.API` +- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options like `SortKeys=false` will be invalid. +- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...) to run on sonic-supporting environment. It will fall back to `encoding/json`. +- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options will be invalid. + +## Tips + +### Pretouch +Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as a JIT assembler, which is NOT very suitable for runtime compiling, first-hit running of a huge schema may cause request-timeout or even process-OOM. For better stability, we advise **using `Pretouch()` for huge-schema or compact-memory applications** before `Marshal()/Unmarshal()`. +```go +import ( + "reflect" + "github.com/bytedance/sonic" + "github.com/bytedance/sonic/option" +) + +func init() { + var v HugeStruct + + // For most large types (nesting depth <= option.DefaultMaxInlineDepth) + err := sonic.Pretouch(reflect.TypeOf(v)) + + // with more CompileOption... + err := sonic.Pretouch(reflect.TypeOf(v), + // If the type is too deep nesting (nesting depth > option.DefaultMaxInlineDepth), + // you can set compile recursive loops in Pretouch for better stability in JIT. + option.WithCompileRecursiveDepth(loop), + // For a large nested struct, try to set a smaller depth to reduce compiling time. + option.WithCompileMaxInlineDepth(depth), + ) +} +``` + +### Copy string +When decoding **string values without any escaped characters**, sonic references them from the origin JSON buffer instead of mallocing a new buffer to copy. This helps a lot for CPU performance but may leave the whole JSON buffer in memory as long as the decoded objects are being used. In practice, we found the extra memory introduced by referring JSON buffer is usually 20% ~ 80% of decoded objects. Once an application holds these objects for a long time (for example, cache the decoded objects for reusing), its in-use memory on the server may go up. We provide the option `decoder.CopyString()` for users to choose not to reference the JSON buffer, which may cause a decline in CPU performance to some degree. + +### Pass string or []byte? +For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when the origin JSON is huge. Therefore, you can use `UnmarshalString()` and `GetFromString()` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. We also provide API `MarshalString()` for convenient **nocopy-cast** of encoded JSON []byte, which is safe since sonic's output bytes is always duplicated and unique. + +### Accelerate `encoding.TextMarshaler` +To ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted following [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). + + +### Better performance for generic data +In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of the schema for specific json, you can combine `Get()` and `Unmarshal()` together: +```go +import "github.com/bytedance/sonic" + +node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") +var user User // your partial schema... +err = sonic.UnmarshalString(node.Raw(), &user) +``` +Even if you don't have any schema, use `ast.Node` as the container of generic values instead of `map` or `interface`: +```go +import "github.com/bytedance/sonic" + +root, err := sonic.GetFromString(_TwitterJson) +user := root.GetByPath("statuses", 3, "user") // === root.Get("status").Index(3).Get("user") +err = user.Check() + +// err = user.LoadAll() // only call this when you want to use 'user' concurrently... +go someFunc(user) +``` +Why? Because `ast.Node` stores its children using `array`: +- `Array`'s performance is **much better** than `Map` when Inserting (Deserialize) and Scanning (Serialize) data; +- **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**; +- Using `Interface()`/`Map()` means Sonic must parse all the underlying values, while `ast.Node` can parse them **on demand**. + +**CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, you can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}` + +## Community +Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem. diff --git a/vendor/github.com/bytedance/sonic/README_ZH_CN.md b/vendor/github.com/bytedance/sonic/README_ZH_CN.md new file mode 100644 index 0000000..43fd1d6 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/README_ZH_CN.md @@ -0,0 +1,382 @@ +# Sonic + +[English](README.md) | 中文 + +一个速度奇快的 JSON 序列化/反序列化库,由 JIT (即时编译)和 SIMD (单指令流多数据流)加速。 + +## 依赖 + +- Go 1.15~1.20 +- Linux/MacOS/Windows +- Amd64 架构 + +## 特色 + +- 运行时对象绑定,无需代码生成 +- 完备的 JSON 操作 API +- 快,更快,还要更快! + +## 基准测试 + +对于**所有大小**的 json 和**所有使用场景**, **Sonic 表现均为最佳**。 +- [中型](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13kB, 300+ 键, 6 层) +```powershell +goversion: 1.17.1 +goos: darwin +goarch: amd64 +cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz +BenchmarkEncoder_Generic_Sonic-16 32393 ns/op 402.40 MB/s 11965 B/op 4 allocs/op +BenchmarkEncoder_Generic_Sonic_Fast-16 21668 ns/op 601.57 MB/s 10940 B/op 4 allocs/op +BenchmarkEncoder_Generic_JsonIter-16 42168 ns/op 309.12 MB/s 14345 B/op 115 allocs/op +BenchmarkEncoder_Generic_GoJson-16 65189 ns/op 199.96 MB/s 23261 B/op 16 allocs/op +BenchmarkEncoder_Generic_StdLib-16 106322 ns/op 122.60 MB/s 49136 B/op 789 allocs/op +BenchmarkEncoder_Binding_Sonic-16 6269 ns/op 2079.26 MB/s 14173 B/op 4 allocs/op +BenchmarkEncoder_Binding_Sonic_Fast-16 5281 ns/op 2468.16 MB/s 12322 B/op 4 allocs/op +BenchmarkEncoder_Binding_JsonIter-16 20056 ns/op 649.93 MB/s 9488 B/op 2 allocs/op +BenchmarkEncoder_Binding_GoJson-16 8311 ns/op 1568.32 MB/s 9481 B/op 1 allocs/op +BenchmarkEncoder_Binding_StdLib-16 16448 ns/op 792.52 MB/s 9479 B/op 1 allocs/op +BenchmarkEncoder_Parallel_Generic_Sonic-16 6681 ns/op 1950.93 MB/s 12738 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Generic_Sonic_Fast-16 4179 ns/op 3118.99 MB/s 10757 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Generic_JsonIter-16 9861 ns/op 1321.84 MB/s 14362 B/op 115 allocs/op +BenchmarkEncoder_Parallel_Generic_GoJson-16 18850 ns/op 691.52 MB/s 23278 B/op 16 allocs/op +BenchmarkEncoder_Parallel_Generic_StdLib-16 45902 ns/op 283.97 MB/s 49174 B/op 789 allocs/op +BenchmarkEncoder_Parallel_Binding_Sonic-16 1480 ns/op 8810.09 MB/s 13049 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Binding_Sonic_Fast-16 1209 ns/op 10785.23 MB/s 11546 B/op 4 allocs/op +BenchmarkEncoder_Parallel_Binding_JsonIter-16 6170 ns/op 2112.58 MB/s 9504 B/op 2 allocs/op +BenchmarkEncoder_Parallel_Binding_GoJson-16 3321 ns/op 3925.52 MB/s 9496 B/op 1 allocs/op +BenchmarkEncoder_Parallel_Binding_StdLib-16 3739 ns/op 3486.49 MB/s 9480 B/op 1 allocs/op + +BenchmarkDecoder_Generic_Sonic-16 66812 ns/op 195.10 MB/s 57602 B/op 723 allocs/op +BenchmarkDecoder_Generic_Sonic_Fast-16 54523 ns/op 239.07 MB/s 49786 B/op 313 allocs/op +BenchmarkDecoder_Generic_StdLib-16 124260 ns/op 104.90 MB/s 50869 B/op 772 allocs/op +BenchmarkDecoder_Generic_JsonIter-16 91274 ns/op 142.81 MB/s 55782 B/op 1068 allocs/op +BenchmarkDecoder_Generic_GoJson-16 88569 ns/op 147.17 MB/s 66367 B/op 973 allocs/op +BenchmarkDecoder_Binding_Sonic-16 32557 ns/op 400.38 MB/s 28302 B/op 137 allocs/op +BenchmarkDecoder_Binding_Sonic_Fast-16 28649 ns/op 455.00 MB/s 24999 B/op 34 allocs/op +BenchmarkDecoder_Binding_StdLib-16 111437 ns/op 116.97 MB/s 10576 B/op 208 allocs/op +BenchmarkDecoder_Binding_JsonIter-16 35090 ns/op 371.48 MB/s 14673 B/op 385 allocs/op +BenchmarkDecoder_Binding_GoJson-16 28738 ns/op 453.59 MB/s 22039 B/op 49 allocs/op +BenchmarkDecoder_Parallel_Generic_Sonic-16 12321 ns/op 1057.91 MB/s 57233 B/op 723 allocs/op +BenchmarkDecoder_Parallel_Generic_Sonic_Fast-16 10644 ns/op 1224.64 MB/s 49362 B/op 313 allocs/op +BenchmarkDecoder_Parallel_Generic_StdLib-16 57587 ns/op 226.35 MB/s 50874 B/op 772 allocs/op +BenchmarkDecoder_Parallel_Generic_JsonIter-16 38666 ns/op 337.12 MB/s 55789 B/op 1068 allocs/op +BenchmarkDecoder_Parallel_Generic_GoJson-16 30259 ns/op 430.79 MB/s 66370 B/op 974 allocs/op +BenchmarkDecoder_Parallel_Binding_Sonic-16 5965 ns/op 2185.28 MB/s 27747 B/op 137 allocs/op +BenchmarkDecoder_Parallel_Binding_Sonic_Fast-16 5170 ns/op 2521.31 MB/s 24715 B/op 34 allocs/op +BenchmarkDecoder_Parallel_Binding_StdLib-16 27582 ns/op 472.58 MB/s 10576 B/op 208 allocs/op +BenchmarkDecoder_Parallel_Binding_JsonIter-16 13571 ns/op 960.51 MB/s 14685 B/op 385 allocs/op +BenchmarkDecoder_Parallel_Binding_GoJson-16 10031 ns/op 1299.51 MB/s 22111 B/op 49 allocs/op + +BenchmarkGetOne_Sonic-16 3276 ns/op 3975.78 MB/s 24 B/op 1 allocs/op +BenchmarkGetOne_Gjson-16 9431 ns/op 1380.81 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Jsoniter-16 51178 ns/op 254.46 MB/s 27936 B/op 647 allocs/op +BenchmarkGetOne_Parallel_Sonic-16 216.7 ns/op 60098.95 MB/s 24 B/op 1 allocs/op +BenchmarkGetOne_Parallel_Gjson-16 1076 ns/op 12098.62 MB/s 0 B/op 0 allocs/op +BenchmarkGetOne_Parallel_Jsoniter-16 17741 ns/op 734.06 MB/s 27945 B/op 647 allocs/op +BenchmarkSetOne_Sonic-16 9571 ns/op 1360.61 MB/s 1584 B/op 17 allocs/op +BenchmarkSetOne_Sjson-16 36456 ns/op 357.22 MB/s 52180 B/op 9 allocs/op +BenchmarkSetOne_Jsoniter-16 79475 ns/op 163.86 MB/s 45862 B/op 964 allocs/op +BenchmarkSetOne_Parallel_Sonic-16 850.9 ns/op 15305.31 MB/s 1584 B/op 17 allocs/op +BenchmarkSetOne_Parallel_Sjson-16 18194 ns/op 715.77 MB/s 52247 B/op 9 allocs/op +BenchmarkSetOne_Parallel_Jsoniter-16 33560 ns/op 388.05 MB/s 45892 B/op 964 allocs/op +``` +- [小型](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 个键, 3 层) +![small benchmarks](./docs/imgs/bench-small.png) +- [大型](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635kB, 10000+ 个键, 6 层) +![large benchmarks](./docs/imgs/bench-large.png) + +要查看基准测试代码,请参阅 [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) 。 + +## 工作原理 + +请参阅 [INTRODUCTION_ZH_CN.md](./docs/INTRODUCTION_ZH_CN.md). + +## 使用方式 + +### 序列化/反序列化 + +默认的行为基本上与 `encoding/json` 相一致,除了 HTML 转义形式(参见 [Escape HTML](https://github.com/bytedance/sonic/blob/main/README.md#escape-html)) 和 `SortKeys` 功能(参见 [Sort Keys](https://github.com/bytedance/sonic/blob/main/README.md#sort-keys))**没有**遵循 [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259) 。 + ```go +import "github.com/bytedance/sonic" + +var data YourSchema +// Marshal +output, err := sonic.Marshal(&data) +// Unmarshal +err := sonic.Unmarshal(output, &data) + ``` + +### 流式输入输出 + +Sonic 支持解码 `io.Reader` 中输入的 json,或将对象编码为 json 后输出至 `io.Writer`,以处理多个值并减少内存消耗。 +- 编码器 +```go +var o1 = map[string]interface{}{ + "a": "b", +} +var o2 = 1 +var w = bytes.NewBuffer(nil) +var enc = sonic.ConfigDefault.NewEncoder(w) +enc.Encode(o1) +enc.Encode(o2) +fmt.Println(w.String()) +// Output: +// {"a":"b"} +// 1 +``` +- 解码器 +```go +var o = map[string]interface{}{} +var r = strings.NewReader(`{"a":"b"}{"1":"2"}`) +var dec = sonic.ConfigDefault.NewDecoder(r) +dec.Decode(&o) +dec.Decode(&o) +fmt.Printf("%+v", o) +// Output: +// map[1:2 a:b] +``` + +### 使用 `Number` / `int64` + +```go +import "github.com/bytedance/sonic/decoder" + +var input = `1` +var data interface{} + +// default float64 +dc := decoder.NewDecoder(input) +dc.Decode(&data) // data == float64(1) +// use json.Number +dc = decoder.NewDecoder(input) +dc.UseNumber() +dc.Decode(&data) // data == json.Number("1") +// use int64 +dc = decoder.NewDecoder(input) +dc.UseInt64() +dc.Decode(&data) // data == int64(1) + +root, err := sonic.GetFromString(input) +// Get json.Number +jn := root.Number() +jm := root.InterfaceUseNumber().(json.Number) // jn == jm +// Get float64 +fn := root.Float64() +fm := root.Interface().(float64) // jn == jm + ``` + +### 对键排序 + +考虑到排序带来的性能损失(约 10% ), sonic 默认不会启用这个功能。如果你的组件依赖这个行为(如 [zstd](https://github.com/facebook/zstd)) ,可以仿照下面的例子: +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/encoder" + +// Binding map only +m := map[string]interface{}{} +v, err := encoder.Encode(m, encoder.SortMapKeys) + +// Or ast.Node.SortKeys() before marshal +var root := sonic.Get(JSON) +err := root.SortKeys() +``` + +### HTML 转义 + +考虑到性能损失(约15%), sonic 默认不会启用这个功能。你可以使用 `encoder.EscapeHTML` 选项来开启(与 `encoding/json.HTMLEscape` 行为一致)。 +```go +import "github.com/bytedance/sonic" + +v := map[string]string{"&&":"<>"} +ret, err := Encode(v, EscapeHTML) // ret == `{"\u0026\u0026":{"X":"\u003c\u003e"}}` +``` + +### 紧凑格式 +Sonic 默认将基本类型( `struct` , `map` 等)编码为紧凑格式的 JSON ,除非使用 `json.RawMessage` or `json.Marshaler` 进行编码: sonic 确保输出的 JSON 合法,但出于性能考虑,**不会**加工成紧凑格式。我们提供选项 `encoder.CompactMarshaler` 来添加此过程, + +### 打印错误 + +如果输入的 JSON 存在无效的语法,sonic 将返回 `decoder.SyntaxError`,该错误支持错误位置的美化输出。 +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/decoder" + +var data interface{} +err := sonic.UnmarshalString("[[[}]]", &data) +if err != nil { + /* One line by default */ + println(e.Error()) // "Syntax error at index 3: invalid char\n\n\t[[[}]]\n\t...^..\n" + /* Pretty print */ + if e, ok := err.(decoder.SyntaxError); ok { + /*Syntax error at index 3: invalid char + + [[[}]] + ...^.. + */ + print(e.Description()) + } else if me, ok := err.(*decoder.MismatchTypeError); ok { + // decoder.MismatchTypeError is new to Sonic v1.6.0 + print(me.Description()) + } +} +``` + +#### 类型不匹配 [Sonic v1.6.0] + +如果给定键中存在**类型不匹配**的值, sonic 会抛出 `decoder.MismatchTypeError` (如果有多个,只会报告最后一个),但仍会跳过错误的值并解码下一个 JSON 。 +```go +import "github.com/bytedance/sonic" +import "github.com/bytedance/sonic/decoder" + +var data = struct{ + A int + B int +}{} +err := UnmarshalString(`{"A":"1","B":1}`, &data) +println(err.Error()) // Mismatch type int with value string "at index 5: mismatched type with value\n\n\t{\"A\":\"1\",\"B\":1}\n\t.....^.........\n" +fmt.Printf("%+v", data) // {A:0 B:1} +``` +### `Ast.Node` + +Sonic/ast.Node 是完全独立的 JSON 抽象语法树库。它实现了序列化和反序列化,并提供了获取和修改通用数据的鲁棒的 API。 + +#### 查找/索引 + +通过给定的路径搜索 JSON 片段,路径必须为非负整数,字符串或 `nil` 。 +```go +import "github.com/bytedance/sonic" + +input := []byte(`{"key1":[{},{"key2":{"key3":[1,2,3]}}]}`) + +// no path, returns entire json +root, err := sonic.Get(input) +raw := root.Raw() // == string(input) + +// multiple paths +root, err := sonic.Get(input, "key1", 1, "key2") +sub := root.Get("key3").Index(2).Int64() // == 3 +``` +**注意**:由于 `Index()` 使用偏移量来定位数据,比使用扫描的 `Get()` 要快的多,建议尽可能的使用 `Index` 。 Sonic 也提供了另一个 API, `IndexOrGet()` ,以偏移量为基础并且也确保键的匹配。 + +#### 修改 + +使用 ` Set()` / `Unset()` 修改 json 的内容 +```go +import "github.com/bytedance/sonic" + +// Set +exist, err := root.Set("key4", NewBool(true)) // exist == false +alias1 := root.Get("key4") +println(alias1.Valid()) // true +alias2 := root.Index(1) +println(alias1 == alias2) // true + +// Unset +exist, err := root.UnsetByIndex(1) // exist == true +println(root.Get("key4").Check()) // "value not exist" +``` + +#### 序列化 +要将 `ast.Node` 编码为 json ,使用 `MarshalJson()` 或者 `json.Marshal()` (必须传递指向节点的指针) +```go +import ( + "encoding/json" + "github.com/bytedance/sonic" +) + +buf, err := root.MarshalJson() +println(string(buf)) // {"key1":[{},{"key2":{"key3":[1,2,3]}}]} +exp, err := json.Marshal(&root) // WARN: use pointer +println(string(buf) == string(exp)) // true +``` + +#### APIs +- 合法性检查: `Check()`, `Error()`, `Valid()`, `Exist()` +- 索引: `Index()`, `Get()`, `IndexPair()`, `IndexOrGet()`, `GetByPath()` +- 转换至 go 内置类型: `Int64()`, `Float64()`, `String()`, `Number()`, `Bool()`, `Map[UseNumber|UseNode]()`, `Array[UseNumber|UseNode]()`, `Interface[UseNumber|UseNode]()` +- go 类型打包: `NewRaw()`, `NewNumber()`, `NewNull()`, `NewBool()`, `NewString()`, `NewObject()`, `NewArray()` +- 迭代: `Values()`, `Properties()`, `ForEach()`, `SortKeys()` +- 修改: `Set()`, `SetByIndex()`, `Add()` + +## 兼容性 +由于开发高性能代码的困难性, Sonic **不**保证对所有环境的支持。对于在不同环境中使用 Sonic 构建应用程序的开发者,我们有以下建议: + +- 在 **Mac M1** 上开发:确保在您的计算机上安装了 Rosetta 2,并在构建时设置 `GOARCH=amd64` 。 Rosetta 2 可以自动将 x86 二进制文件转换为 arm64 二进制文件,并在 Mac M1 上运行 x86 应用程序。 +- 在 **Linux arm64** 上开发:您可以安装 qemu 并使用 `qemu-x86_64 -cpu max` 命令来将 x86 二进制文件转换为 arm64 二进制文件。qemu可以实现与Mac M1上的Rosetta 2类似的转换效果。 + +对于希望在不使用 qemu 下使用 sonic 的开发者,或者希望处理 JSON 时与 `encoding/JSON` 严格保持一致的开发者,我们在 `sonic.API` 中提供了一些兼容性 API +- `ConfigDefault`: 在支持 sonic 的环境下 sonic 的默认配置(`EscapeHTML=false`,`SortKeys=false`等)。行为与具有相应配置的 `encoding/json` 一致,一些选项,如 `SortKeys=false` 将无效。 +- `ConfigStd`: 在支持 sonic 的环境下与标准库兼容的配置(`EscapeHTML=true`,`SortKeys=true`等)。行为与 `encoding/json` 一致。 +- `ConfigFastest`: 在支持 sonic 的环境下运行最快的配置(`NoQuoteTextMarshaler=true`)。行为与具有相应配置的 `encoding/json` 一致,某些选项将无效。 + +## 注意事项 + +### 预热 +由于 Sonic 使用 [golang-asm](https://github.com/twitchyliquid64/golang-asm) 作为 JIT 汇编器,这个库并不适用于运行时编译,第一次运行一个大型模式可能会导致请求超时甚至进程内存溢出。为了更好地稳定性,我们建议在运行大型模式或在内存有限的应用中,在使用 `Marshal()/Unmarshal()` 前运行 `Pretouch()`。 +```go +import ( + "reflect" + "github.com/bytedance/sonic" + "github.com/bytedance/sonic/option" +) + +func init() { + var v HugeStruct + + // For most large types (nesting depth <= option.DefaultMaxInlineDepth) + err := sonic.Pretouch(reflect.TypeOf(v)) + + // with more CompileOption... + err := sonic.Pretouch(reflect.TypeOf(v), + // If the type is too deep nesting (nesting depth > option.DefaultMaxInlineDepth), + // you can set compile recursive loops in Pretouch for better stability in JIT. + option.WithCompileRecursiveDepth(loop), + // For a large nested struct, try to set a smaller depth to reduce compiling time. + option.WithCompileMaxInlineDepth(depth), + ) +} +``` + +### 拷贝字符串 + +当解码 **没有转义字符的字符串**时, sonic 会从原始的 JSON 缓冲区内引用而不是复制到新的一个缓冲区中。这对 CPU 的性能方面很有帮助,但是可能因此在解码后对象仍在使用的时候将整个 JSON 缓冲区保留在内存中。实践中我们发现,通过引用 JSON 缓冲区引入的额外内存通常是解码后对象的 20% 至 80% ,一旦应用长期保留这些对象(如缓存以备重用),服务器所使用的内存可能会增加。我们提供了选项 `decoder.CopyString()` 供用户选择,不引用 JSON 缓冲区。这可能在一定程度上降低 CPU 性能。 + +### 传递字符串还是字节数组? +为了和 `encoding/json` 保持一致,我们提供了传递 `[]byte` 作为参数的 API ,但考虑到安全性,字符串到字节的复制是同时进行的,这在原始 JSON 非常大时可能会导致性能损失。因此,你可以使用 `UnmarshalString()` 和 `GetFromString()` 来传递字符串,只要你的原始数据是字符串,或**零拷贝类型转换**对于你的字节数组是安全的。我们也提供了 `MarshalString()` 的 API ,以便对编码的 JSON 字节数组进行**零拷贝类型转换**,因为 sonic 输出的字节始终是重复并且唯一的,所以这样是安全的。 + +### 加速 `encoding.TextMarshaler` + +为了保证数据安全性, `sonic.Encoder` 默认会对来自 `encoding.TextMarshaler` 接口的字符串进行引用和转义,如果大部分数据都是这种形式那可能会导致很大的性能损失。我们提供了 `encoder.NoQuoteTextMarshaler` 选项来跳过这些操作,但你**必须**保证他们的输出字符串依照 [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259) 进行了转义和引用。 + + +### 泛型的性能优化 + +在 **完全解析**的场景下, `Unmarshal()` 表现得比 `Get()`+`Node.Interface()` 更好。但是如果你只有特定 JSON 的部分模式,你可以将 `Get()` 和 `Unmarshal()` 结合使用: +```go +import "github.com/bytedance/sonic" + +node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") +var user User // your partial schema... +err = sonic.UnmarshalString(node.Raw(), &user) +``` +甚至如果你没有任何模式,可以用 `ast.Node` 代替 `map` 或 `interface` 作为泛型的容器: +```go +import "github.com/bytedance/sonic" + +root, err := sonic.GetFromString(_TwitterJson) +user := root.GetByPath("statuses", 3, "user") // === root.Get("status").Index(3).Get("user") +err = user.Check() + +// err = user.LoadAll() // only call this when you want to use 'user' concurrently... +go someFunc(user) +``` +为什么?因为 `ast.Node` 使用 `array` 来存储其子节点: +- 在插入(反序列化)和扫描(序列化)数据时,`Array` 的性能比 `Map` **好得多**; +- **哈希**(`map[x]`)的效率不如**索引**(`array[x]`)高效,而 `ast.Node` 可以在数组和对象上使用索引; +- 使用 `Interface()` / `Map()` 意味着 sonic 必须解析所有的底层值,而 `ast.Node` 可以**按需解析**它们。 + +**注意**:由于 `ast.Node` 的惰性加载设计,其**不能**直接保证并发安全性,但你可以调用 `Node.Load()` / `Node.LoadAll()` 来实现并发安全。尽管可能会带来性能损失,但仍比转换成 `map` 或 `interface{}` 更为高效。 + +## 社区 + +Sonic 是 [CloudWeGo](https://www.cloudwego.io/) 下的一个子项目。我们致力于构建云原生生态系统。 diff --git a/vendor/github.com/bytedance/sonic/api.go b/vendor/github.com/bytedance/sonic/api.go new file mode 100644 index 0000000..a042476 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/api.go @@ -0,0 +1,186 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 sonic + +import ( + `io` + + `github.com/bytedance/sonic/ast` +) + +// Config is a combination of sonic/encoder.Options and sonic/decoder.Options +type Config struct { + // EscapeHTML indicates encoder to escape all HTML characters + // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape). + // WARNING: This hurts performance A LOT, USE WITH CARE. + EscapeHTML bool + + // SortMapKeys indicates encoder that the keys of a map needs to be sorted + // before serializing into JSON. + // WARNING: This hurts performance A LOT, USE WITH CARE. + SortMapKeys bool + + // CompactMarshaler indicates encoder that the output JSON from json.Marshaler + // is always compact and needs no validation + CompactMarshaler bool + + // NoQuoteTextMarshaler indicates encoder that the output text from encoding.TextMarshaler + // is always escaped string and needs no quoting + NoQuoteTextMarshaler bool + + // NoNullSliceOrMap indicates encoder that all empty Array or Object are encoded as '[]' or '{}', + // instead of 'null' + NoNullSliceOrMap bool + + // UseInt64 indicates decoder to unmarshal an integer into an interface{} as an + // int64 instead of as a float64. + UseInt64 bool + + // UseNumber indicates decoder to unmarshal a number into an interface{} as a + // json.Number instead of as a float64. + UseNumber bool + + // UseUnicodeErrors indicates decoder to return an error when encounter invalid + // UTF-8 escape sequences. + UseUnicodeErrors bool + + // DisallowUnknownFields indicates decoder to return an error when the destination + // is a struct and the input contains object keys which do not match any + // non-ignored, exported fields in the destination. + DisallowUnknownFields bool + + // 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 + // when unescaped control chars(\u0000-\u001f) in the string value of JSON. + ValidateString bool +} + +var ( + // ConfigDefault is the default config of APIs, aiming at efficiency and safty. + ConfigDefault = Config{}.Froze() + + // ConfigStd is the standard config of APIs, aiming at being compatible with encoding/json. + ConfigStd = Config{ + EscapeHTML : true, + SortMapKeys: true, + CompactMarshaler: true, + CopyString : true, + ValidateString : true, + }.Froze() + + // ConfigFastest is the fastest config of APIs, aiming at speed. + ConfigFastest = Config{ + NoQuoteTextMarshaler: true, + }.Froze() +) + + +// API is a binding of specific config. +// This interface is inspired by github.com/json-iterator/go, +// and has same behaviors under equavilent config. +type API interface { + // MarshalToString returns the JSON encoding string of v + MarshalToString(v interface{}) (string, error) + // Marshal returns the JSON encoding bytes of v. + Marshal(v interface{}) ([]byte, error) + // MarshalIndent returns the JSON encoding bytes with indent and prefix. + MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) + // UnmarshalFromString parses the JSON-encoded bytes and stores the result in the value pointed to by v. + UnmarshalFromString(str string, v interface{}) error + // Unmarshal parses the JSON-encoded string and stores the result in the value pointed to by v. + Unmarshal(data []byte, v interface{}) error + // NewEncoder create a Encoder holding writer + NewEncoder(writer io.Writer) Encoder + // NewDecoder create a Decoder holding reader + NewDecoder(reader io.Reader) Decoder + // Valid validates the JSON-encoded bytes and reportes if it is valid + Valid(data []byte) bool +} + +// Encoder encodes JSON into io.Writer +type Encoder interface { + // Encode writes the JSON encoding of v to the stream, followed by a newline character. + Encode(val interface{}) error + // SetEscapeHTML specifies whether problematic HTML characters + // should be escaped inside JSON quoted strings. + // The default behavior NOT ESCAPE + SetEscapeHTML(on bool) + // SetIndent instructs the encoder to format each subsequent encoded value + // as if indented by the package-level function Indent(dst, src, prefix, indent). + // Calling SetIndent("", "") disables indentation + SetIndent(prefix, indent string) +} + +// Decoder decodes JSON from io.Read +type Decoder interface { + // Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v. + Decode(val interface{}) error + // Buffered returns a reader of the data remaining in the Decoder's buffer. + // The reader is valid until the next call to Decode. + Buffered() io.Reader + // DisallowUnknownFields causes the Decoder to return an error when the destination is a struct + // and the input contains object keys which do not match any non-ignored, exported fields in the destination. + DisallowUnknownFields() + // More reports whether there is another element in the current array or object being parsed. + More() bool + // UseNumber causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64. + UseNumber() +} + +// Marshal returns the JSON encoding bytes of v. +func Marshal(val interface{}) ([]byte, error) { + return ConfigDefault.Marshal(val) +} + +// MarshalString returns the JSON encoding string of v. +func MarshalString(val interface{}) (string, error) { + return ConfigDefault.MarshalToString(val) +} + +// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. +// NOTICE: This API copies given buffer by default, +// if you want to pass JSON more efficiently, use UnmarshalString instead. +func Unmarshal(buf []byte, val interface{}) error { + return ConfigDefault.Unmarshal(buf, val) +} + +// UnmarshalString is like Unmarshal, except buf is a string. +func UnmarshalString(buf string, val interface{}) error { + return ConfigDefault.UnmarshalFromString(buf, val) +} + +// Get searches the given path from json, +// and returns its representing ast.Node. +// +// Each path arg must be integer or string: +// - Integer is target index(>=0), means searching current node as array. +// - String is target key, means searching current node as object. +// +// +// Note, the api expects the json is well-formed at least, +// otherwise it may return unexpected result. +func Get(src []byte, path ...interface{}) (ast.Node, error) { + return GetFromString(string(src), path...) +} + +// GetFromString is same with Get except src is string, +// which can reduce unnecessary memory copy. +func GetFromString(src string, path ...interface{}) (ast.Node, error) { + return ast.NewSearcher(src).GetByPath(path...) +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/api_amd64.go b/vendor/github.com/bytedance/sonic/ast/api_amd64.go new file mode 100644 index 0000000..3047f59 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/api_amd64.go @@ -0,0 +1,151 @@ +// +build amd64,go1.15,!go1.21 + +/* + * Copyright 2022 ByteDance Inc. + * + * 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 ast + +import ( + `runtime` + `unsafe` + + `github.com/bytedance/sonic/encoder` + `github.com/bytedance/sonic/internal/native` + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` + uq `github.com/bytedance/sonic/unquote` + `github.com/chenzhuoyu/base64x` +) + +var typeByte = rt.UnpackEface(byte(0)).Type + +//go:nocheckptr +func quote(buf *[]byte, val string) { + *buf = append(*buf, '"') + if len(val) == 0 { + *buf = append(*buf, '"') + return + } + + sp := rt.IndexChar(val, 0) + nb := len(val) + b := (*rt.GoSlice)(unsafe.Pointer(buf)) + + // input buffer + for nb > 0 { + // output buffer + dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len)) + dn := b.Cap - b.Len + // call native.Quote, dn is byte count it outputs + ret := native.Quote(sp, nb, dp, &dn, 0) + // update *buf length + b.Len += dn + + // no need more output + if ret >= 0 { + break + } + + // double buf size + *b = growslice(typeByte, *b, b.Cap*2) + // ret is the complement of consumed input + ret = ^ret + // update input buffer + nb -= ret + sp = unsafe.Pointer(uintptr(sp) + uintptr(ret)) + } + + runtime.KeepAlive(buf) + runtime.KeepAlive(sp) + *buf = append(*buf, '"') +} + +func unquote(src string) (string, types.ParsingError) { + return uq.String(src) +} + +func decodeBase64(src string) ([]byte, error) { + return base64x.StdEncoding.DecodeString(src) +} + +func encodeBase64(src []byte) string { + return base64x.StdEncoding.EncodeToString(src) +} + +func (self *Parser) decodeValue() (val types.JsonState) { + sv := (*rt.GoString)(unsafe.Pointer(&self.s)) + self.p = native.Value(sv.Ptr, sv.Len, self.p, &val, 0) + return +} + +func (self *Parser) skip() (int, types.ParsingError) { + fsm := types.NewStateMachine() + start := native.SkipOne(&self.s, &self.p, fsm, 0) + types.FreeStateMachine(fsm) + + if start < 0 { + return self.p, types.ParsingError(-start) + } + return start, 0 +} + +func (self *Node) encodeInterface(buf *[]byte) error { + //WARN: NOT compatible with json.Encoder + return encoder.EncodeInto(buf, self.packAny(), 0) +} + +func (self *Parser) skipFast() (int, types.ParsingError) { + start := native.SkipOneFast(&self.s, &self.p) + if start < 0 { + return self.p, types.ParsingError(-start) + } + return start, 0 +} + +func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) { + fsm := types.NewStateMachine() + start := native.GetByPath(&self.s, &self.p, &path, fsm) + types.FreeStateMachine(fsm) + runtime.KeepAlive(path) + if start < 0 { + return self.p, types.ParsingError(-start) + } + return start, 0 +} + +func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { + var err types.ParsingError + var start int + + self.parser.p = 0 + start, err = self.parser.getByPath(path...) + if err != 0 { + // for compatibility with old version + if err == types.ERR_NOT_FOUND { + return Node{}, ErrNotExist + } + if err == types.ERR_UNSUPPORT_TYPE { + panic("path must be either int(>=0) or string") + } + return Node{}, self.parser.syntaxError(err) + } + + t := switchRawType(self.parser.s[start]) + if t == _V_NONE { + return Node{}, self.parser.ExportError(err) + } + return newRawNode(self.parser.s[start:self.parser.p], t), nil +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/api_compat.go b/vendor/github.com/bytedance/sonic/ast/api_compat.go new file mode 100644 index 0000000..b18b5ae --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/api_compat.go @@ -0,0 +1,120 @@ +// +build !amd64 go1.21 + +/* + * Copyright 2022 ByteDance Inc. + * + * 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 ast + +import ( + `encoding/base64` + `encoding/json` + `fmt` + + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` +) + +func quote(buf *[]byte, val string) { + quoteString(buf, val) +} + +func unquote(src string) (string, types.ParsingError) { + sp := rt.IndexChar(src, -1) + out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2)) + if !ok { + return "", types.ERR_INVALID_ESCAPE + } + return rt.Mem2Str(out), 0 +} + +func decodeBase64(src string) ([]byte, error) { + return base64.StdEncoding.DecodeString(src) +} + +func encodeBase64(src []byte) string { + return base64.StdEncoding.EncodeToString(src) +} + +func (self *Parser) decodeValue() (val types.JsonState) { + e, v := decodeValue(self.s, self.p) + if e < 0 { + return v + } + self.p = e + return v +} + +func (self *Parser) skip() (int, types.ParsingError) { + e, s := skipValue(self.s, self.p) + if e < 0 { + return self.p, types.ParsingError(-e) + } + self.p = e + return s, 0 +} + +func (self *Parser) skipFast() (int, types.ParsingError) { + e, s := skipValueFast(self.s, self.p) + if e < 0 { + return self.p, types.ParsingError(-e) + } + self.p = e + return s, 0 +} + +func (self *Node) encodeInterface(buf *[]byte) error { + out, err := json.Marshal(self.packAny()) + if err != nil { + return err + } + *buf = append(*buf, out...) + return nil +} + +func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { + self.parser.p = 0 + + var err types.ParsingError + for _, p := range path { + if idx, ok := p.(int); ok && idx >= 0 { + if err = self.parser.searchIndex(idx); err != 0 { + return Node{}, self.parser.ExportError(err) + } + } else if key, ok := p.(string); ok { + if err = self.parser.searchKey(key); err != 0 { + return Node{}, self.parser.ExportError(err) + } + } else { + panic("path must be either int(>=0) or string") + } + } + + var start = self.parser.p + if start, err = self.parser.skip(); err != 0 { + return Node{}, self.parser.ExportError(err) + } + ns := len(self.parser.s) + if self.parser.p > ns || start >= ns || start>=self.parser.p { + return Node{}, fmt.Errorf("skip %d char out of json boundary", start) + } + + t := switchRawType(self.parser.s[start]) + if t == _V_NONE { + return Node{}, self.parser.ExportError(err) + } + + return newRawNode(self.parser.s[start:self.parser.p], t), nil +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/asm.s b/vendor/github.com/bytedance/sonic/ast/asm.s new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/bytedance/sonic/ast/decode.go b/vendor/github.com/bytedance/sonic/ast/decode.go new file mode 100644 index 0000000..6a5f6fe --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/decode.go @@ -0,0 +1,575 @@ +/* + * Copyright 2022 ByteDance Inc. + * + * 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 ast + +import ( + `encoding/base64` + `runtime` + `strconv` + `unsafe` + + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` +) + +const _blankCharsMask = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n') + +const ( + bytesNull = "null" + bytesTrue = "true" + bytesFalse = "false" + bytesObject = "{}" + bytesArray = "[]" +) + +func isSpace(c byte) bool { + return (int(1<= se { + return -int(types.ERR_EOF) + } + runtime.KeepAlive(src) + return int(sp - uintptr(rt.IndexChar(src, 0))) +} + +func decodeNull(src string, pos int) (ret int) { + ret = pos + 4 + if ret > len(src) { + return -int(types.ERR_EOF) + } + if src[pos:ret] == bytesNull { + return ret + } else { + return -int(types.ERR_INVALID_CHAR) + } +} + +func decodeTrue(src string, pos int) (ret int) { + ret = pos + 4 + if ret > len(src) { + return -int(types.ERR_EOF) + } + if src[pos:ret] == bytesTrue { + return ret + } else { + return -int(types.ERR_INVALID_CHAR) + } + +} + +func decodeFalse(src string, pos int) (ret int) { + ret = pos + 5 + if ret > len(src) { + return -int(types.ERR_EOF) + } + if src[pos:ret] == bytesFalse { + return ret + } + return -int(types.ERR_INVALID_CHAR) +} + +//go:nocheckptr +func decodeString(src string, pos int) (ret int, v string) { + ret, ep := skipString(src, pos) + if ep == -1 { + (*rt.GoString)(unsafe.Pointer(&v)).Ptr = rt.IndexChar(src, pos+1) + (*rt.GoString)(unsafe.Pointer(&v)).Len = ret - pos - 2 + return ret, v + } + + vv, ok := unquoteBytes(rt.Str2Mem(src[pos:ret])) + if !ok { + return -int(types.ERR_INVALID_CHAR), "" + } + + runtime.KeepAlive(src) + return ret, rt.Mem2Str(vv) +} + +func decodeBinary(src string, pos int) (ret int, v []byte) { + var vv string + ret, vv = decodeString(src, pos) + if ret < 0 { + return ret, nil + } + var err error + v, err = base64.StdEncoding.DecodeString(vv) + if err != nil { + return -int(types.ERR_INVALID_CHAR), nil + } + return ret, v +} + +func isDigit(c byte) bool { + return c >= '0' && c <= '9' +} + +//go:nocheckptr +func decodeInt64(src string, pos int) (ret int, v int64, err error) { + sp := uintptr(rt.IndexChar(src, pos)) + ss := uintptr(sp) + se := uintptr(rt.IndexChar(src, len(src))) + if uintptr(sp) >= se { + return -int(types.ERR_EOF), 0, nil + } + + if c := *(*byte)(unsafe.Pointer(sp)); c == '-' { + sp += 1 + } + if sp == se { + return -int(types.ERR_EOF), 0, nil + } + + for ; sp < se; sp += uintptr(1) { + if !isDigit(*(*byte)(unsafe.Pointer(sp))) { + break + } + } + + if sp < se { + if c := *(*byte)(unsafe.Pointer(sp)); c == '.' || c == 'e' || c == 'E' { + return -int(types.ERR_INVALID_NUMBER_FMT), 0, nil + } + } + + var vv string + ret = int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)) + (*rt.GoString)(unsafe.Pointer(&vv)).Ptr = unsafe.Pointer(ss) + (*rt.GoString)(unsafe.Pointer(&vv)).Len = ret - pos + + v, err = strconv.ParseInt(vv, 10, 64) + if err != nil { + //NOTICE: allow overflow here + if err.(*strconv.NumError).Err == strconv.ErrRange { + return ret, 0, err + } + return -int(types.ERR_INVALID_CHAR), 0, err + } + + runtime.KeepAlive(src) + return ret, v, nil +} + +func isNumberChars(c byte) bool { + return (c >= '0' && c <= '9') || c == '+' || c == '-' || c == 'e' || c == 'E' || c == '.' +} + +//go:nocheckptr +func decodeFloat64(src string, pos int) (ret int, v float64, err error) { + sp := uintptr(rt.IndexChar(src, pos)) + ss := uintptr(sp) + se := uintptr(rt.IndexChar(src, len(src))) + if uintptr(sp) >= se { + return -int(types.ERR_EOF), 0, nil + } + + if c := *(*byte)(unsafe.Pointer(sp)); c == '-' { + sp += 1 + } + if sp == se { + return -int(types.ERR_EOF), 0, nil + } + + for ; sp < se; sp += uintptr(1) { + if !isNumberChars(*(*byte)(unsafe.Pointer(sp))) { + break + } + } + + var vv string + ret = int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)) + (*rt.GoString)(unsafe.Pointer(&vv)).Ptr = unsafe.Pointer(ss) + (*rt.GoString)(unsafe.Pointer(&vv)).Len = ret - pos + + v, err = strconv.ParseFloat(vv, 64) + if err != nil { + //NOTICE: allow overflow here + if err.(*strconv.NumError).Err == strconv.ErrRange { + return ret, 0, err + } + return -int(types.ERR_INVALID_CHAR), 0, err + } + + runtime.KeepAlive(src) + return ret, v, nil +} + +func decodeValue(src string, pos int) (ret int, v types.JsonState) { + pos = skipBlank(src, pos) + if pos < 0 { + return pos, types.JsonState{Vt: types.ValueType(pos)} + } + switch c := src[pos]; c { + case 'n': + ret = decodeNull(src, pos) + if ret < 0 { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + return ret, types.JsonState{Vt: types.V_NULL} + case '"': + var ep int + ret, ep = skipString(src, pos) + if ret < 0 { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + return ret, types.JsonState{Vt: types.V_STRING, Iv: int64(pos + 1), Ep: ep} + case '{': + return pos + 1, types.JsonState{Vt: types.V_OBJECT} + case '[': + return pos + 1, types.JsonState{Vt: types.V_ARRAY} + case 't': + ret = decodeTrue(src, pos) + if ret < 0 { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + return ret, types.JsonState{Vt: types.V_TRUE} + case 'f': + ret = decodeFalse(src, pos) + if ret < 0 { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + return ret, types.JsonState{Vt: types.V_FALSE} + case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + var iv int64 + ret, iv, _ = decodeInt64(src, pos) + if ret >= 0 { + return ret, types.JsonState{Vt: types.V_INTEGER, Iv: iv, Ep: pos} + } else if ret != -int(types.ERR_INVALID_NUMBER_FMT) { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + var fv float64 + ret, fv, _ = decodeFloat64(src, pos) + if ret >= 0 { + return ret, types.JsonState{Vt: types.V_DOUBLE, Dv: fv, Ep: pos} + } else { + return ret, types.JsonState{Vt: types.ValueType(ret)} + } + default: + return -int(types.ERR_INVALID_CHAR), types.JsonState{Vt:-types.ValueType(types.ERR_INVALID_CHAR)} + } +} + +//go:nocheckptr +func skipNumber(src string, pos int) (ret int) { + sp := uintptr(rt.IndexChar(src, pos)) + se := uintptr(rt.IndexChar(src, len(src))) + if uintptr(sp) >= se { + return -int(types.ERR_EOF) + } + + if c := *(*byte)(unsafe.Pointer(sp)); c == '-' { + sp += 1 + } + ss := sp + + var pointer bool + var exponent bool + var lastIsDigit bool + var nextNeedDigit = true + + for ; sp < se; sp += uintptr(1) { + c := *(*byte)(unsafe.Pointer(sp)) + if isDigit(c) { + lastIsDigit = true + nextNeedDigit = false + continue + } else if nextNeedDigit { + return -int(types.ERR_INVALID_CHAR) + } else if c == '.' { + if !lastIsDigit || pointer || exponent || sp == ss { + return -int(types.ERR_INVALID_CHAR) + } + pointer = true + lastIsDigit = false + nextNeedDigit = true + continue + } else if c == 'e' || c == 'E' { + if !lastIsDigit || exponent { + return -int(types.ERR_INVALID_CHAR) + } + if sp == se-1 { + return -int(types.ERR_EOF) + } + exponent = true + lastIsDigit = false + nextNeedDigit = false + continue + } else if c == '-' || c == '+' { + if prev := *(*byte)(unsafe.Pointer(sp - 1)); prev != 'e' && prev != 'E' { + return -int(types.ERR_INVALID_CHAR) + } + lastIsDigit = false + nextNeedDigit = true + continue + } else { + break + } + } + + if nextNeedDigit { + return -int(types.ERR_EOF) + } + + runtime.KeepAlive(src) + return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)) +} + +//go:nocheckptr +func skipString(src string, pos int) (ret int, ep int) { + if pos+1 >= len(src) { + return -int(types.ERR_EOF), -1 + } + + sp := uintptr(rt.IndexChar(src, pos)) + se := uintptr(rt.IndexChar(src, len(src))) + + // not start with quote + if *(*byte)(unsafe.Pointer(sp)) != '"' { + return -int(types.ERR_INVALID_CHAR), -1 + } + sp += 1 + + ep = -1 + for sp < se { + c := *(*byte)(unsafe.Pointer(sp)) + if c == '\\' { + if ep == -1 { + ep = int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)) + } + sp += 2 + continue + } + sp += 1 + if c == '"' { + return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)), ep + } + } + + runtime.KeepAlive(src) + // not found the closed quote until EOF + return -int(types.ERR_EOF), -1 +} + +//go:nocheckptr +func skipPair(src string, pos int, lchar byte, rchar byte) (ret int) { + if pos+1 >= len(src) { + return -int(types.ERR_EOF) + } + + sp := uintptr(rt.IndexChar(src, pos)) + se := uintptr(rt.IndexChar(src, len(src))) + + if *(*byte)(unsafe.Pointer(sp)) != lchar { + return -int(types.ERR_INVALID_CHAR) + } + + sp += 1 + nbrace := 1 + inquote := false + + for sp < se { + c := *(*byte)(unsafe.Pointer(sp)) + if c == '\\' { + sp += 2 + continue + } else if c == '"' { + inquote = !inquote + } else if c == lchar { + if !inquote { + nbrace += 1 + } + } else if c == rchar { + if !inquote { + nbrace -= 1 + if nbrace == 0 { + sp += 1 + break + } + } + } + sp += 1 + } + + if nbrace != 0 { + return -int(types.ERR_INVALID_CHAR) + } + + runtime.KeepAlive(src) + return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr)) +} + +func skipValueFast(src string, pos int) (ret int, start int) { + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + switch c := src[pos]; c { + case 'n': + ret = decodeNull(src, pos) + case '"': + ret, _ = skipString(src, pos) + case '{': + ret = skipPair(src, pos, '{', '}') + case '[': + ret = skipPair(src, pos, '[', ']') + case 't': + ret = decodeTrue(src, pos) + case 'f': + ret = decodeFalse(src, pos) + case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + ret = skipNumber(src, pos) + default: + ret = -int(types.ERR_INVALID_CHAR) + } + return ret, pos +} + +func skipValue(src string, pos int) (ret int, start int) { + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + switch c := src[pos]; c { + case 'n': + ret = decodeNull(src, pos) + case '"': + ret, _ = skipString(src, pos) + case '{': + ret, _ = skipObject(src, pos) + case '[': + ret, _ = skipArray(src, pos) + case 't': + ret = decodeTrue(src, pos) + case 'f': + ret = decodeFalse(src, pos) + case '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + ret = skipNumber(src, pos) + default: + ret = -int(types.ERR_INVALID_CHAR) + } + return ret, pos +} + +func skipObject(src string, pos int) (ret int, start int) { + start = skipBlank(src, pos) + if start < 0 { + return start, -1 + } + + if src[start] != '{' { + return -int(types.ERR_INVALID_CHAR), -1 + } + + pos = start + 1 + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + if src[pos] == '}' { + return pos + 1, start + } + + for { + pos, _ = skipString(src, pos) + if pos < 0 { + return pos, -1 + } + + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + if src[pos] != ':' { + return -int(types.ERR_INVALID_CHAR), -1 + } + + pos++ + pos, _ = skipValue(src, pos) + if pos < 0 { + return pos, -1 + } + + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + if src[pos] == '}' { + return pos + 1, start + } + if src[pos] != ',' { + return -int(types.ERR_INVALID_CHAR), -1 + } + + pos++ + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + + } +} + +func skipArray(src string, pos int) (ret int, start int) { + start = skipBlank(src, pos) + if start < 0 { + return start, -1 + } + + if src[start] != '[' { + return -int(types.ERR_INVALID_CHAR), -1 + } + + pos = start + 1 + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + if src[pos] == ']' { + return pos + 1, start + } + + for { + pos, _ = skipValue(src, pos) + if pos < 0 { + return pos, -1 + } + + pos = skipBlank(src, pos) + if pos < 0 { + return pos, -1 + } + if src[pos] == ']' { + return pos + 1, start + } + if src[pos] != ',' { + return -int(types.ERR_INVALID_CHAR), -1 + } + pos++ + } +} diff --git a/vendor/github.com/bytedance/sonic/ast/encode.go b/vendor/github.com/bytedance/sonic/ast/encode.go new file mode 100644 index 0000000..1187e30 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/encode.go @@ -0,0 +1,259 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `sync` + `unicode/utf8` + + `github.com/bytedance/sonic/internal/rt` +) + +const ( + _MaxBuffer = 1024 // 1KB buffer size +) + +func quoteString(e *[]byte, s string) { + *e = append(*e, '"') + start := 0 + for i := 0; i < len(s); { + if b := s[i]; b < utf8.RuneSelf { + if safeSet[b] { + i++ + continue + } + if start < i { + *e = append(*e, s[start:i]...) + } + *e = append(*e, '\\') + switch b { + case '\\', '"': + *e = append(*e, b) + case '\n': + *e = append(*e, 'n') + case '\r': + *e = append(*e, 'r') + case '\t': + *e = append(*e, 't') + default: + // This encodes bytes < 0x20 except for \t, \n and \r. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. + *e = append(*e, `u00`...) + *e = append(*e, hex[b>>4]) + *e = append(*e, hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + // if c == utf8.RuneError && size == 1 { + // if start < i { + // e.Write(s[start:i]) + // } + // e.WriteString(`\ufffd`) + // i += size + // start = i + // continue + // } + if c == '\u2028' || c == '\u2029' { + if start < i { + *e = append(*e, s[start:i]...) + } + *e = append(*e, `\u202`...) + *e = append(*e, hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(s) { + *e = append(*e, s[start:]...) + } + *e = append(*e, '"') +} + +var bytesPool = sync.Pool{} + +func (self *Node) MarshalJSON() ([]byte, error) { + buf := newBuffer() + err := self.encode(buf) + if err != nil { + freeBuffer(buf) + return nil, err + } + + ret := make([]byte, len(*buf)) + copy(ret, *buf) + freeBuffer(buf) + return ret, err +} + +func newBuffer() *[]byte { + if ret := bytesPool.Get(); ret != nil { + return ret.(*[]byte) + } else { + buf := make([]byte, 0, _MaxBuffer) + return &buf + } +} + +func freeBuffer(buf *[]byte) { + *buf = (*buf)[:0] + bytesPool.Put(buf) +} + +func (self *Node) encode(buf *[]byte) error { + if self.IsRaw() { + return self.encodeRaw(buf) + } + switch self.Type() { + case V_NONE : return ErrNotExist + case V_ERROR : return self.Check() + case V_NULL : return self.encodeNull(buf) + case V_TRUE : return self.encodeTrue(buf) + case V_FALSE : return self.encodeFalse(buf) + case V_ARRAY : return self.encodeArray(buf) + case V_OBJECT: return self.encodeObject(buf) + case V_STRING: return self.encodeString(buf) + case V_NUMBER: return self.encodeNumber(buf) + case V_ANY : return self.encodeInterface(buf) + default : return ErrUnsupportType + } +} + +func (self *Node) encodeRaw(buf *[]byte) error { + raw, err := self.Raw() + if err != nil { + return err + } + *buf = append(*buf, raw...) + return nil +} + +func (self *Node) encodeNull(buf *[]byte) error { + *buf = append(*buf, bytesNull...) + return nil +} + +func (self *Node) encodeTrue(buf *[]byte) error { + *buf = append(*buf, bytesTrue...) + return nil +} + +func (self *Node) encodeFalse(buf *[]byte) error { + *buf = append(*buf, bytesFalse...) + return nil +} + +func (self *Node) encodeNumber(buf *[]byte) error { + str := rt.StrFrom(self.p, self.v) + *buf = append(*buf, str...) + return nil +} + +func (self *Node) encodeString(buf *[]byte) error { + if self.v == 0 { + *buf = append(*buf, '"', '"') + return nil + } + + quote(buf, rt.StrFrom(self.p, self.v)) + return nil +} + +func (self *Node) encodeArray(buf *[]byte) error { + if self.isLazy() { + if err := self.skipAllIndex(); err != nil { + return err + } + } + + nb := self.len() + if nb == 0 { + *buf = append(*buf, bytesArray...) + return nil + } + + *buf = append(*buf, '[') + + var p = (*Node)(self.p) + err := p.encode(buf) + if err != nil { + return err + } + for i := 1; i < nb; i++ { + *buf = append(*buf, ',') + p = p.unsafe_next() + err := p.encode(buf) + if err != nil { + return err + } + } + + *buf = append(*buf, ']') + return nil +} + +func (self *Pair) encode(buf *[]byte) error { + if len(*buf) == 0 { + *buf = append(*buf, '"', '"', ':') + return self.Value.encode(buf) + } + + quote(buf, self.Key) + *buf = append(*buf, ':') + + return self.Value.encode(buf) +} + +func (self *Node) encodeObject(buf *[]byte) error { + if self.isLazy() { + if err := self.skipAllKey(); err != nil { + return err + } + } + + nb := self.len() + if nb == 0 { + *buf = append(*buf, bytesObject...) + return nil + } + + *buf = append(*buf, '{') + + var p = (*Pair)(self.p) + err := p.encode(buf) + if err != nil { + return err + } + for i := 1; i < nb; i++ { + *buf = append(*buf, ',') + p = p.unsafe_next() + err := p.encode(buf) + if err != nil { + return err + } + } + + *buf = append(*buf, '}') + return nil +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/error.go b/vendor/github.com/bytedance/sonic/ast/error.go new file mode 100644 index 0000000..f4c441a --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/error.go @@ -0,0 +1,98 @@ +package ast + +import ( + `fmt` + `strings` + `unsafe` + + `github.com/bytedance/sonic/internal/native/types` +) + +func (self *Parser) syntaxError(err types.ParsingError) SyntaxError { + return SyntaxError{ + Pos : self.p, + Src : self.s, + Code: err, + } +} + +func newSyntaxError(err SyntaxError) *Node { + msg := err.Description() + return &Node{ + t: V_ERROR, + v: int64(err.Code), + p: unsafe.Pointer(&msg), + } +} + +type SyntaxError struct { + Pos int + Src string + Code types.ParsingError + Msg string +} + +func (self SyntaxError) Error() string { + return fmt.Sprintf("%q", self.Description()) +} + +func (self SyntaxError) Description() string { + return "Syntax error " + self.description() +} + +func (self SyntaxError) description() string { + i := 16 + p := self.Pos - i + q := self.Pos + i + + /* check for empty source */ + if self.Src == "" { + return fmt.Sprintf("no sources available: %#v", self) + } + + /* prevent slicing before the beginning */ + if p < 0 { + p, q, i = 0, q - p, i + p + } + + /* prevent slicing beyond the end */ + if n := len(self.Src); q > n { + n = q - n + q = len(self.Src) + + /* move the left bound if possible */ + if p > n { + i += n + p -= n + } + } + + /* left and right length */ + x := clamp_zero(i) + y := clamp_zero(q - p - i - 1) + + /* compose the error description */ + return fmt.Sprintf( + "at index %d: %s\n\n\t%s\n\t%s^%s\n", + self.Pos, + self.Message(), + self.Src[p:q], + strings.Repeat(".", x), + strings.Repeat(".", y), + ) +} + +func (self SyntaxError) Message() string { + if self.Msg == "" { + return self.Code.Message() + } + return self.Msg +} + +func clamp_zero(v int) int { + if v < 0 { + return 0 + } else { + return v + } +} diff --git a/vendor/github.com/bytedance/sonic/ast/iterator.go b/vendor/github.com/bytedance/sonic/ast/iterator.go new file mode 100644 index 0000000..03a25b4 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/iterator.go @@ -0,0 +1,164 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `fmt` + + `github.com/bytedance/sonic/internal/native/types` +) + +type Pair struct { + Key string + Value Node +} + +// Values returns iterator for array's children traversal +func (self *Node) Values() (ListIterator, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return ListIterator{}, err + } + return ListIterator{Iterator{p: self}}, nil +} + +// Properties returns iterator for object's children traversal +func (self *Node) Properties() (ObjectIterator, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return ObjectIterator{}, err + } + return ObjectIterator{Iterator{p: self}}, nil +} + +type Iterator struct { + i int + p *Node +} + +func (self *Iterator) Pos() int { + return self.i +} + +func (self *Iterator) Len() int { + return self.p.len() +} + +// HasNext reports if it is the end of iteration or has error. +func (self *Iterator) HasNext() bool { + if !self.p.isLazy() { + return self.p.Valid() && self.i < self.p.len() + } else if self.p.t == _V_ARRAY_LAZY { + return self.p.skipNextNode().Valid() + } else if self.p.t == _V_OBJECT_LAZY { + pair := self.p.skipNextPair() + if pair == nil { + return false + } + return pair.Value.Valid() + } + return false +} + +// ListIterator is specialized iterator for V_ARRAY +type ListIterator struct { + Iterator +} + +// ObjectIterator is specialized iterator for V_ARRAY +type ObjectIterator struct { + Iterator +} + +// Next scans through children of underlying V_ARRAY, +// copies each child to v, and returns .HasNext(). +func (self *ListIterator) Next(v *Node) bool { + if !self.HasNext() { + return false + } else { + *v, self.i = *self.p.nodeAt(self.i), self.i + 1 + return true + } +} + +// Next scans through children of underlying V_OBJECT, +// copies each child to v, and returns .HasNext(). +func (self *ObjectIterator) Next(p *Pair) bool { + if !self.HasNext() { + return false + } else { + *p, self.i = *self.p.pairAt(self.i), self.i + 1 + return true + } +} + +// Sequence represents scanning path of single-layer nodes. +// Index indicates the value's order in both V_ARRAY and V_OBJECT json. +// Key is the value's key (for V_OBJECT json only, otherwise it will be nil). +type Sequence struct { + Index int + Key *string + // Level int +} + +// String is string representation of one Sequence +func (s Sequence) String() string { + k := "" + if s.Key != nil { + k = *s.Key + } + return fmt.Sprintf("Sequence(%d, %q)", s.Index, k) +} + +type Scanner func(path Sequence, node *Node) bool + +// 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, +// the node itself will be returned and Sequence.Index == -1. +func (self *Node) ForEach(sc Scanner) error { + switch self.itype() { + case types.V_ARRAY: + ns, err := self.UnsafeArray() + if err != nil { + return err + } + for i := range ns { + if !sc(Sequence{i, nil}, &ns[i]) { + return err + } + } + case types.V_OBJECT: + ns, err := self.UnsafeMap() + if err != nil { + return err + } + for i := range ns { + if !sc(Sequence{i, &ns[i].Key}, &ns[i].Value) { + return err + } + } + default: + sc(Sequence{-1, nil}, self) + } + return self.Check() +} + +type PairSlice []Pair + +func (self PairSlice) Sort() { + radixQsort(self, 0, maxDepth(len(self))) +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/node.go b/vendor/github.com/bytedance/sonic/ast/node.go new file mode 100644 index 0000000..6b5ad8a --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/node.go @@ -0,0 +1,1808 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `encoding/json` + `fmt` + `strconv` + `unsafe` + `reflect` + + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` +) + +const ( + _CAP_BITS = 32 + _LEN_MASK = 1 << _CAP_BITS - 1 + + _NODE_SIZE = unsafe.Sizeof(Node{}) + _PAIR_SIZE = unsafe.Sizeof(Pair{}) +) + +const ( + _V_NONE types.ValueType = 0 + _V_NODE_BASE types.ValueType = 1 << 5 + _V_LAZY types.ValueType = 1 << 7 + _V_RAW types.ValueType = 1 << 8 + _V_NUMBER = _V_NODE_BASE + 1 + _V_ANY = _V_NODE_BASE + 2 + _V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY + _V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT + _MASK_LAZY = _V_LAZY - 1 + _MASK_RAW = _V_RAW - 1 +) + +const ( + V_NONE = 0 + V_ERROR = 1 + V_NULL = 2 + V_TRUE = 3 + V_FALSE = 4 + V_ARRAY = 5 + V_OBJECT = 6 + V_STRING = 7 + V_NUMBER = int(_V_NUMBER) + V_ANY = int(_V_ANY) +) + +var ( + byteType = rt.UnpackType(reflect.TypeOf(byte(0))) +) + +type Node struct { + v int64 + t types.ValueType + p unsafe.Pointer +} + +// UnmarshalJSON is just an adapter to json.Unmarshaler. +// If you want better performance, use Searcher.GetByPath() directly +func (self *Node) UnmarshalJSON(data []byte) (err error) { + *self, err = NewSearcher(string(data)).GetByPath() + return +} + +/** Node Type Accessor **/ + +// Type returns json type represented by the node +// It will be one of belows: +// V_NONE = 0 (empty node) +// V_ERROR = 1 (error node) +// V_NULL = 2 (json value `null`) +// V_TRUE = 3 (json value `true`) +// V_FALSE = 4 (json value `false`) +// V_ARRAY = 5 (json value array) +// V_OBJECT = 6 (json value object) +// V_STRING = 7 (json value string) +// V_NUMBER = 33 (json value number ) +// V_ANY = 34 (golang interface{}) +func (self Node) Type() int { + return int(self.t & _MASK_LAZY & _MASK_RAW) +} + +func (self Node) itype() types.ValueType { + return self.t & _MASK_LAZY & _MASK_RAW +} + +// Exists returns false only if the self is nil or empty node V_NONE +func (self *Node) Exists() bool { + return self != nil && self.t != _V_NONE +} + +// Valid reports if self is NOT V_ERROR or nil +func (self *Node) Valid() bool { + if self == nil { + return false + } + return self.t != V_ERROR +} + +// Check checks if the node itself is valid, and return: +// - ErrNotFound If the node is nil +// - Its underlying error If the node is V_ERROR +func (self *Node) Check() error { + if self == nil { + return ErrNotExist + } else if self.t != V_ERROR { + return nil + } else { + return self + } +} + +// Error returns error message if the node is invalid +func (self Node) Error() string { + if self.t != V_ERROR { + return "" + } else { + return *(*string)(self.p) + } +} + +// IsRaw returns true if node's underlying value is raw json +func (self Node) IsRaw() bool { + return self.t&_V_RAW != 0 +} + +func (self *Node) isLazy() bool { + return self != nil && self.t&_V_LAZY != 0 +} + +func (self *Node) isAny() bool { + return self != nil && self.t == _V_ANY +} + +/** Simple Value Methods **/ + +// Raw returns json representation of the node, +func (self *Node) Raw() (string, error) { + if !self.IsRaw() { + buf, err := self.MarshalJSON() + return rt.Mem2Str(buf), err + } + return rt.StrFrom(self.p, self.v), nil +} + +func (self *Node) checkRaw() error { + if err := self.Check(); err != nil { + return err + } + if self.IsRaw() { + self.parseRaw(false) + } + return nil +} + +// Bool returns bool value represented by this node, +// including types.V_TRUE|V_FALSE|V_NUMBER|V_STRING|V_ANY|V_NULL, +// V_NONE will return error +func (self *Node) Bool() (bool, error) { + if err := self.checkRaw(); err != nil { + return false, err + } + switch self.t { + case types.V_TRUE : return true , nil + case types.V_FALSE : return false, nil + case types.V_NULL : return false, nil + case _V_NUMBER : + if i, err := numberToInt64(self); err == nil { + return i != 0, nil + } else if f, err := numberToFloat64(self); err == nil { + return f != 0, nil + } else { + return false, err + } + case types.V_STRING: return strconv.ParseBool(rt.StrFrom(self.p, self.v)) + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case bool : return v, nil + case int : return v != 0, nil + case int8 : return v != 0, nil + case int16 : return v != 0, nil + case int32 : return v != 0, nil + case int64 : return v != 0, nil + case uint : return v != 0, nil + case uint8 : return v != 0, nil + case uint16 : return v != 0, nil + case uint32 : return v != 0, nil + case uint64 : return v != 0, nil + case float32: return v != 0, nil + case float64: return v != 0, nil + case string : return strconv.ParseBool(v) + case json.Number: + if i, err := v.Int64(); err == nil { + return i != 0, nil + } else if f, err := v.Float64(); err == nil { + return f != 0, nil + } else { + return false, err + } + default: return false, ErrUnsupportType + } + default : return false, ErrUnsupportType + } +} + +// Int64 casts the node to int64 value, +// including V_NUMBER|V_TRUE|V_FALSE|V_ANY|V_STRING +// V_NONE it will return error +func (self *Node) Int64() (int64, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } + switch self.t { + case _V_NUMBER, types.V_STRING : + if i, err := numberToInt64(self); err == nil { + return i, nil + } else if f, err := numberToFloat64(self); err == nil { + return int64(f), nil + } else { + return 0, err + } + case types.V_TRUE : return 1, nil + case types.V_FALSE : return 0, nil + case types.V_NULL : return 0, nil + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case bool : if v { return 1, nil } else { return 0, nil } + case int : return int64(v), nil + case int8 : return int64(v), nil + case int16 : return int64(v), nil + case int32 : return int64(v), nil + case int64 : return int64(v), nil + case uint : return int64(v), nil + case uint8 : return int64(v), nil + case uint16 : return int64(v), nil + case uint32 : return int64(v), nil + case uint64 : return int64(v), nil + case float32: return int64(v), nil + case float64: return int64(v), nil + case string : + if i, err := strconv.ParseInt(v, 10, 64); err == nil { + return i, nil + } else if f, err := strconv.ParseFloat(v, 64); err == nil { + return int64(f), nil + } else { + return 0, err + } + case json.Number: + if i, err := v.Int64(); err == nil { + return i, nil + } else if f, err := v.Float64(); err == nil { + return int64(f), nil + } else { + return 0, err + } + default: return 0, ErrUnsupportType + } + default : return 0, ErrUnsupportType + } +} + +// StrictInt64 exports underlying int64 value, including V_NUMBER, V_ANY +func (self *Node) StrictInt64() (int64, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } + switch self.t { + case _V_NUMBER : return numberToInt64(self) + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case int : return int64(v), nil + case int8 : return int64(v), nil + case int16 : return int64(v), nil + case int32 : return int64(v), nil + case int64 : return int64(v), nil + case uint : return int64(v), nil + case uint8 : return int64(v), nil + case uint16: return int64(v), nil + case uint32: return int64(v), nil + case uint64: return int64(v), nil + case json.Number: + if i, err := v.Int64(); err == nil { + return i, nil + } else { + return 0, err + } + default: return 0, ErrUnsupportType + } + default : return 0, ErrUnsupportType + } +} + +func castNumber(v bool) json.Number { + if v { + return json.Number("1") + } else { + return json.Number("0") + } +} + +// Number casts node to float64, +// including V_NUMBER|V_TRUE|V_FALSE|V_ANY|V_STRING|V_NULL, +// V_NONE it will return error +func (self *Node) Number() (json.Number, error) { + if err := self.checkRaw(); err != nil { + return json.Number(""), err + } + switch self.t { + case _V_NUMBER : return toNumber(self) , nil + case types.V_STRING : + if _, err := numberToInt64(self); err == nil { + return toNumber(self), nil + } else if _, err := numberToFloat64(self); err == nil { + return toNumber(self), nil + } else { + return json.Number(""), err + } + case types.V_TRUE : return json.Number("1"), nil + case types.V_FALSE : return json.Number("0"), nil + case types.V_NULL : return json.Number("0"), nil + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case bool : return castNumber(v), nil + case int : return castNumber(v != 0), nil + case int8 : return castNumber(v != 0), nil + case int16 : return castNumber(v != 0), nil + case int32 : return castNumber(v != 0), nil + case int64 : return castNumber(v != 0), nil + case uint : return castNumber(v != 0), nil + case uint8 : return castNumber(v != 0), nil + case uint16 : return castNumber(v != 0), nil + case uint32 : return castNumber(v != 0), nil + case uint64 : return castNumber(v != 0), nil + case float32: return castNumber(v != 0), nil + case float64: return castNumber(v != 0), nil + case string : + if _, err := strconv.ParseFloat(v, 64); err == nil { + return json.Number(v), nil + } else { + return json.Number(""), err + } + case json.Number: return v, nil + default: return json.Number(""), ErrUnsupportType + } + default : return json.Number(""), ErrUnsupportType + } +} + +// Number exports underlying float64 value, including V_NUMBER, V_ANY of json.Number +func (self *Node) StrictNumber() (json.Number, error) { + if err := self.checkRaw(); err != nil { + return json.Number(""), err + } + switch self.t { + case _V_NUMBER : return toNumber(self) , nil + case _V_ANY : + if v, ok := self.packAny().(json.Number); ok { + return v, nil + } else { + return json.Number(""), ErrUnsupportType + } + default : return json.Number(""), ErrUnsupportType + } +} + +// String cast node to string, +// including V_NUMBER|V_TRUE|V_FALSE|V_ANY|V_STRING|V_NULL, +// V_NONE it will return error +func (self *Node) String() (string, error) { + if err := self.checkRaw(); err != nil { + return "", err + } + switch self.t { + case types.V_NULL : return "" , nil + case types.V_TRUE : return "true" , nil + case types.V_FALSE : return "false", nil + case types.V_STRING, _V_NUMBER : return rt.StrFrom(self.p, self.v), nil + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case bool : return strconv.FormatBool(v), nil + case int : return strconv.Itoa(v), nil + case int8 : return strconv.Itoa(int(v)), nil + case int16 : return strconv.Itoa(int(v)), nil + case int32 : return strconv.Itoa(int(v)), nil + case int64 : return strconv.Itoa(int(v)), nil + case uint : return strconv.Itoa(int(v)), nil + case uint8 : return strconv.Itoa(int(v)), nil + case uint16 : return strconv.Itoa(int(v)), nil + case uint32 : return strconv.Itoa(int(v)), nil + case uint64 : return strconv.Itoa(int(v)), nil + case float32: return strconv.FormatFloat(float64(v), 'g', -1, 64), nil + case float64: return strconv.FormatFloat(float64(v), 'g', -1, 64), nil + case string : return v, nil + case json.Number: return v.String(), nil + default: return "", ErrUnsupportType + } + default : return "" , ErrUnsupportType + } +} + +// StrictString returns string value (unescaped), includeing 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 { + return "", err + } + switch self.t { + case types.V_STRING : return rt.StrFrom(self.p, self.v), nil + case _V_ANY : + if v, ok := self.packAny().(string); ok { + return v, nil + } else { + return "", ErrUnsupportType + } + default : return "", ErrUnsupportType + } +} + +// Float64 cast node to float64, +// including V_NUMBER|V_TRUE|V_FALSE|V_ANY|V_STRING|V_NULL, +// V_NONE it will return error +func (self *Node) Float64() (float64, error) { + if err := self.checkRaw(); err != nil { + return 0.0, err + } + switch self.t { + case _V_NUMBER, types.V_STRING : return numberToFloat64(self) + case types.V_TRUE : return 1.0, nil + case types.V_FALSE : return 0.0, nil + case types.V_NULL : return 0.0, nil + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case bool : + if v { + return 1.0, nil + } else { + return 0.0, nil + } + case int : return float64(v), nil + case int8 : return float64(v), nil + case int16 : return float64(v), nil + case int32 : return float64(v), nil + case int64 : return float64(v), nil + case uint : return float64(v), nil + case uint8 : return float64(v), nil + case uint16 : return float64(v), nil + case uint32 : return float64(v), nil + case uint64 : return float64(v), nil + case float32: return float64(v), nil + case float64: return float64(v), nil + case string : + if f, err := strconv.ParseFloat(v, 64); err == nil { + return float64(f), nil + } else { + return 0, err + } + case json.Number: + if f, err := v.Float64(); err == nil { + return float64(f), nil + } else { + return 0, err + } + default : return 0, ErrUnsupportType + } + default : return 0.0, ErrUnsupportType + } +} + +// Float64 exports underlying float64 value, includeing V_NUMBER, V_ANY +func (self *Node) StrictFloat64() (float64, error) { + if err := self.checkRaw(); err != nil { + return 0.0, err + } + switch self.t { + case _V_NUMBER : return numberToFloat64(self) + case _V_ANY : + any := self.packAny() + switch v := any.(type) { + case float32 : return float64(v), nil + case float64 : return float64(v), nil + default : return 0, ErrUnsupportType + } + default : return 0.0, ErrUnsupportType + } +} + +/** Sequencial Value Methods **/ + +// Len returns children count of a array|object|string node +// For partially loaded node, it also works but only counts the parsed children +func (self *Node) Len() (int, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } + if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { + return int(self.v & _LEN_MASK), nil + } else if self.t == types.V_STRING { + return int(self.v), nil + } else if self.t == _V_NONE || self.t == types.V_NULL { + return 0, nil + } else { + return 0, ErrUnsupportType + } +} + +func (self Node) len() int { + return int(self.v & _LEN_MASK) +} + +// Cap returns malloc capacity of a array|object node for children +func (self *Node) Cap() (int, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } + if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { + return int(self.v >> _CAP_BITS), nil + } else if self.t == _V_NONE || self.t == types.V_NULL { + return 0, nil + } else { + return 0, ErrUnsupportType + } +} + +func (self Node) cap() int { + return int(self.v >> _CAP_BITS) +} + +// Set sets the node of given key under self, and reports if the key has existed. +// +// If self is V_NONE or V_NULL, it becomes V_OBJECT and sets the node at the key. +func (self *Node) Set(key string, node Node) (bool, error) { + if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { + *self = NewObject([]Pair{{key, node}}) + return false, nil + } + + if err := node.Check(); err != nil { + return false, err + } + + p := self.Get(key) + if !p.Exists() { + l := self.len() + c := self.cap() + if l == c { + // TODO: maybe change append size in future + c += _DEFAULT_NODE_CAP + mem := unsafe_NewArray(_PAIR_TYPE, c) + memmove(mem, self.p, _PAIR_SIZE * uintptr(l)) + self.p = mem + } + v := self.pairAt(l) + v.Key = key + v.Value = node + self.setCapAndLen(c, l+1) + return false, nil + + } else if err := p.Check(); err != nil { + return false, err + } + + *p = node + return true, nil +} + +// SetAny wraps val with V_ANY node, and Set() the node. +func (self *Node) SetAny(key string, val interface{}) (bool, error) { + return self.Set(key, NewAny(val)) +} + +// Unset remove the node of given key under object parent, and reports if the key has existed. +func (self *Node) Unset(key string) (bool, error) { + self.must(types.V_OBJECT, "an object") + p, i := self.skipKey(key) + if !p.Exists() { + return false, nil + } else if err := p.Check(); err != nil { + return false, err + } + + self.removePair(i) + return true, nil +} + +// SetByIndex sets the node of given index, and reports if the key has existed. +// +// The index must be within self's children. +func (self *Node) SetByIndex(index int, node Node) (bool, error) { + if err := node.Check(); err != nil { + return false, err + } + + p := self.Index(index) + if !p.Exists() { + return false, ErrNotExist + } else if err := p.Check(); err != nil { + return false, err + } + + *p = node + return true, nil +} + +// SetAny wraps val with V_ANY node, and SetByIndex() the node. +func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) { + return self.SetByIndex(index, NewAny(val)) +} + +// UnsetByIndex remove the node of given index +func (self *Node) UnsetByIndex(index int) (bool, error) { + var p *Node + it := self.itype() + if it == types.V_ARRAY { + p = self.Index(index) + }else if it == types.V_OBJECT { + pr := self.skipIndexPair(index) + if pr == nil { + return false, ErrNotExist + } + p = &pr.Value + } else { + return false, ErrUnsupportType + } + + if !p.Exists() { + return false, ErrNotExist + } + + if it == types.V_ARRAY { + self.removeNode(index) + }else if it == types.V_OBJECT { + self.removePair(index) + } + return true, nil +} + +// Add appends the given node under self. +// +// If self is V_NONE or V_NULL, it becomes V_ARRAY and sets the node at index 0. +func (self *Node) Add(node Node) error { + if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { + *self = NewArray([]Node{node}) + return nil + } + + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return err + } + if err := self.skipAllIndex(); err != nil { + return err + } + + var p rt.GoSlice + p.Cap = self.cap() + p.Len = self.len() + p.Ptr = self.p + + s := *(*[]Node)(unsafe.Pointer(&p)) + s = append(s, node) + + self.p = unsafe.Pointer(&s[0]) + self.setCapAndLen(cap(s), len(s)) + return nil +} + +// SetAny wraps val with V_ANY node, and Add() the node. +func (self *Node) AddAny(val interface{}) error { + return self.Add(NewAny(val)) +} + +// GetByPath load given path on demands, +// which only ensure nodes before this path got parsed. +// +// Note, the api expects the json is well-formed at least, +// otherwise it may return unexpected result. +func (self *Node) GetByPath(path ...interface{}) *Node { + if !self.Valid() { + return self + } + var s = self + for _, p := range path { + switch p := p.(type) { + case int: + s = s.Index(p) + if !s.Valid() { + return s + } + case string: + s = s.Get(p) + if !s.Valid() { + return s + } + default: + panic("path must be either int or string") + } + } + return s +} + +// Get loads given key of an object node on demands +func (self *Node) Get(key string) *Node { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return unwrapError(err) + } + n, _ := self.skipKey(key) + return n +} + +// Index indexies node at given idx, +// node type CAN be either V_OBJECT or V_ARRAY +func (self *Node) Index(idx int) *Node { + if err := self.checkRaw(); err != nil { + return unwrapError(err) + } + + it := self.itype() + if it == types.V_ARRAY { + return self.skipIndex(idx) + + }else if it == types.V_OBJECT { + pr := self.skipIndexPair(idx) + if pr == nil { + return newError(_ERR_NOT_FOUND, "value not exists") + } + return &pr.Value + + } else { + return newError(_ERR_UNSUPPORT_TYPE, fmt.Sprintf("unsupported type: %v", self.itype())) + } +} + +// IndexPair indexies pair at given idx, +// node type MUST be either V_OBJECT +func (self *Node) IndexPair(idx int) *Pair { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil + } + return self.skipIndexPair(idx) +} + +// IndexOrGet firstly use idx to index a value and check if its key matches +// If not, then use the key to search value +func (self *Node) IndexOrGet(idx int, key string) *Node { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return unwrapError(err) + } + + pr := self.skipIndexPair(idx) + if pr != nil && pr.Key == key { + return &pr.Value + } + n, _ := self.skipKey(key) + return n +} + +/** Generic Value Converters **/ + +// Map loads all keys of an object node +func (self *Node) Map() (map[string]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.loadAllKey(); err != nil { + return nil, err + } + return self.toGenericObject() +} + +// MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number +func (self *Node) MapUseNumber() (map[string]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.loadAllKey(); err != nil { + return nil, err + } + return self.toGenericObjectUseNumber() +} + +// MapUseNode scans both parsed and non-parsed chidren nodes, +// and map them by their keys +func (self *Node) MapUseNode() (map[string]Node, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]Node); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.skipAllKey(); err != nil { + return nil, err + } + return self.toGenericObjectUseNode() +} + +// MapUnsafe exports the underlying pointer to its children map +// WARN: don't use it unless you know what you are doing +func (self *Node) UnsafeMap() ([]Pair, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.skipAllKey(); err != nil { + return nil, err + } + s := rt.Ptr2SlicePtr(self.p, int(self.len()), self.cap()) + return *(*[]Pair)(s), nil +} + +// SortKeys sorts children of a V_OBJECT node in ascending key-order. +// If recurse is true, it recursively sorts children's children as long as a V_OBJECT node is found. +func (self *Node) SortKeys(recurse bool) (err error) { + ps, err := self.UnsafeMap() + if err != nil { + return err + } + PairSlice(ps).Sort() + if recurse { + var sc Scanner + sc = func(path Sequence, node *Node) bool { + if node.itype() == types.V_OBJECT { + if err := node.SortKeys(recurse); err != nil { + return false + } + } + if node.itype() == types.V_ARRAY { + if err := node.ForEach(sc); err != nil { + return false + } + } + return true + } + self.ForEach(sc) + } + return nil +} + +// Array loads all indexes of an array node +func (self *Node) Array() ([]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } + return self.toGenericArray() +} + +// ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number +func (self *Node) ArrayUseNumber() ([]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } + return self.toGenericArrayUseNumber() +} + +// ArrayUseNode copys both parsed and non-parsed chidren nodes, +// and indexes them by original order +func (self *Node) ArrayUseNode() ([]Node, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]Node); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.skipAllIndex(); err != nil { + return nil, err + } + return self.toGenericArrayUseNode() +} + +// ArrayUnsafe exports the underlying pointer to its children array +// WARN: don't use it unless you know what you are doing +func (self *Node) UnsafeArray() ([]Node, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.skipAllIndex(); err != nil { + return nil, err + } + s := rt.Ptr2SlicePtr(self.p, self.len(), self.cap()) + return *(*[]Node)(s), nil +} + +// Interface loads all children under all pathes from this node, +// and converts itself as generic type. +// WARN: all numberic nodes are casted to float64 +func (self *Node) Interface() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } + switch self.t { + case V_ERROR : return nil, self.Check() + case types.V_NULL : return nil, nil + case types.V_TRUE : return true, nil + case types.V_FALSE : return false, nil + case types.V_ARRAY : return self.toGenericArray() + case types.V_OBJECT : return self.toGenericObject() + case types.V_STRING : return rt.StrFrom(self.p, self.v), nil + case _V_NUMBER : + v, err := numberToFloat64(self) + if err != nil { + return nil, err + } + return v, nil + case _V_ARRAY_LAZY : + if err := self.loadAllIndex(); err != nil { + return nil, err + } + return self.toGenericArray() + case _V_OBJECT_LAZY : + if err := self.loadAllKey(); err != nil { + return nil, err + } + return self.toGenericObject() + case _V_ANY: + switch v := self.packAny().(type) { + case Node : return v.Interface() + case *Node: return v.Interface() + default : return v, nil + } + default : return nil, ErrUnsupportType + } +} + +func (self *Node) packAny() interface{} { + return *(*interface{})(self.p) +} + +// InterfaceUseNumber works same with Interface() +// except numberic nodes are casted to json.Number +func (self *Node) InterfaceUseNumber() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } + switch self.t { + case V_ERROR : return nil, self.Check() + case types.V_NULL : return nil, nil + case types.V_TRUE : return true, nil + case types.V_FALSE : return false, nil + case types.V_ARRAY : return self.toGenericArrayUseNumber() + case types.V_OBJECT : return self.toGenericObjectUseNumber() + case types.V_STRING : return rt.StrFrom(self.p, self.v), nil + case _V_NUMBER : return toNumber(self), nil + case _V_ARRAY_LAZY : + if err := self.loadAllIndex(); err != nil { + return nil, err + } + return self.toGenericArrayUseNumber() + case _V_OBJECT_LAZY : + if err := self.loadAllKey(); err != nil { + return nil, err + } + return self.toGenericObjectUseNumber() + case _V_ANY : return self.packAny(), nil + default : return nil, ErrUnsupportType + } +} + +// InterfaceUseNode clone itself as a new node, +// or its children as map[string]Node (or []Node) +func (self *Node) InterfaceUseNode() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } + switch self.t { + case types.V_ARRAY : return self.toGenericArrayUseNode() + case types.V_OBJECT : return self.toGenericObjectUseNode() + case _V_ARRAY_LAZY : + if err := self.skipAllIndex(); err != nil { + return nil, err + } + return self.toGenericArrayUseNode() + case _V_OBJECT_LAZY : + if err := self.skipAllKey(); err != nil { + return nil, err + } + return self.toGenericObjectUseNode() + default : return *self, self.Check() + } +} + +// LoadAll loads all the node's children and children's children as parsed. +// After calling it, the node can be safely used on concurrency +func (self *Node) LoadAll() error { + if self.IsRaw() { + self.parseRaw(true) + return self.Check() + } + + switch self.itype() { + case types.V_ARRAY: + e := self.len() + if err := self.loadAllIndex(); err != nil { + return err + } + for i := 0; i < e; i++ { + n := self.nodeAt(i) + if n.IsRaw() { + n.parseRaw(true) + } + if err := n.Check(); err != nil { + return err + } + } + return nil + case types.V_OBJECT: + e := self.len() + if err := self.loadAllKey(); err != nil { + return err + } + for i := 0; i < e; i++ { + n := self.pairAt(i) + if n.Value.IsRaw() { + n.Value.parseRaw(true) + } + if err := n.Value.Check(); err != nil { + return err + } + } + return nil + default: + return self.Check() + } +} + +// Load loads the node's children as parsed. +// After calling it, only the node itself can be used on concurrency (not include its children) +func (self *Node) Load() error { + if self.IsRaw() { + self.parseRaw(false) + return self.Load() + } + + switch self.t { + case _V_ARRAY_LAZY: + return self.skipAllIndex() + case _V_OBJECT_LAZY: + return self.skipAllKey() + default: + return self.Check() + } +} + +/**---------------------------------- Internal Helper Methods ----------------------------------**/ + +var ( + _NODE_TYPE = rt.UnpackEface(Node{}).Type + _PAIR_TYPE = rt.UnpackEface(Pair{}).Type +) + +func (self *Node) setCapAndLen(cap int, len int) { + if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { + self.v = int64(len&_LEN_MASK | cap<<_CAP_BITS) + } else { + panic("value does not have a length") + } +} + +func (self *Node) unsafe_next() *Node { + return (*Node)(unsafe.Pointer(uintptr(unsafe.Pointer(self)) + _NODE_SIZE)) +} + +func (self *Pair) unsafe_next() *Pair { + return (*Pair)(unsafe.Pointer(uintptr(unsafe.Pointer(self)) + _PAIR_SIZE)) +} + +func (self *Node) must(t types.ValueType, s string) { + if err := self.checkRaw(); err != nil { + panic(err) + } + if err := self.Check(); err != nil { + panic(err) + } + if self.itype() != t { + panic("value cannot be represented as " + s) + } +} + +func (self *Node) should(t types.ValueType, s string) error { + if err := self.checkRaw(); err != nil { + return err + } + if self.itype() != t { + return ErrUnsupportType + } + return nil +} + +func (self *Node) nodeAt(i int) *Node { + var p = self.p + if self.isLazy() { + _, stack := self.getParserAndArrayStack() + p = *(*unsafe.Pointer)(unsafe.Pointer(&stack.v)) + } + return (*Node)(unsafe.Pointer(uintptr(p) + uintptr(i)*_NODE_SIZE)) +} + +func (self *Node) pairAt(i int) *Pair { + var p = self.p + if self.isLazy() { + _, stack := self.getParserAndObjectStack() + p = *(*unsafe.Pointer)(unsafe.Pointer(&stack.v)) + } + return (*Pair)(unsafe.Pointer(uintptr(p) + uintptr(i)*_PAIR_SIZE)) +} + +func (self *Node) getParserAndArrayStack() (*Parser, *parseArrayStack) { + stack := (*parseArrayStack)(self.p) + ret := (*rt.GoSlice)(unsafe.Pointer(&stack.v)) + ret.Len = self.len() + ret.Cap = self.cap() + return &stack.parser, stack +} + +func (self *Node) getParserAndObjectStack() (*Parser, *parseObjectStack) { + stack := (*parseObjectStack)(self.p) + ret := (*rt.GoSlice)(unsafe.Pointer(&stack.v)) + ret.Len = self.len() + ret.Cap = self.cap() + return &stack.parser, stack +} + +func (self *Node) skipAllIndex() error { + if !self.isLazy() { + return nil + } + var err types.ParsingError + parser, stack := self.getParserAndArrayStack() + parser.skipValue = true + parser.noLazy = true + *self, err = parser.decodeArray(stack.v) + if err != 0 { + return parser.ExportError(err) + } + return nil +} + +func (self *Node) skipAllKey() error { + if !self.isLazy() { + return nil + } + var err types.ParsingError + parser, stack := self.getParserAndObjectStack() + parser.skipValue = true + parser.noLazy = true + *self, err = parser.decodeObject(stack.v) + if err != 0 { + return parser.ExportError(err) + } + return nil +} + +func (self *Node) skipKey(key string) (*Node, int) { + nb := self.len() + lazy := self.isLazy() + + if nb > 0 { + /* linear search */ + var p *Pair + if lazy { + s := (*parseObjectStack)(self.p) + p = &s.v[0] + } else { + p = (*Pair)(self.p) + } + + if p.Key == key { + return &p.Value, 0 + } + for i := 1; i < nb; i++ { + p = p.unsafe_next() + if p.Key == key { + return &p.Value, i + } + } + } + + /* not found */ + if !lazy { + return nil, -1 + } + + // lazy load + for last, i := self.skipNextPair(), nb; last != nil; last, i = self.skipNextPair(), i+1 { + if last.Value.Check() != nil { + return &last.Value, -1 + } + if last.Key == key { + return &last.Value, i + } + } + + return nil, -1 +} + +func (self *Node) skipIndex(index int) *Node { + nb := self.len() + if nb > index { + v := self.nodeAt(index) + return v + } + if !self.isLazy() { + return nil + } + + // lazy load + for last := self.skipNextNode(); last != nil; last = self.skipNextNode(){ + if last.Check() != nil { + return last + } + if self.len() > index { + return last + } + } + + return nil +} + +func (self *Node) skipIndexPair(index int) *Pair { + nb := self.len() + if nb > index { + return self.pairAt(index) + } + if !self.isLazy() { + return nil + } + + // lazy load + for last := self.skipNextPair(); last != nil; last = self.skipNextPair(){ + if last.Value.Check() != nil { + return last + } + if self.len() > index { + return last + } + } + + return nil +} + +func (self *Node) loadAllIndex() error { + if !self.isLazy() { + return nil + } + var err types.ParsingError + parser, stack := self.getParserAndArrayStack() + parser.noLazy = true + *self, err = parser.decodeArray(stack.v) + if err != 0 { + return parser.ExportError(err) + } + return nil +} + +func (self *Node) loadAllKey() error { + if !self.isLazy() { + return nil + } + var err types.ParsingError + parser, stack := self.getParserAndObjectStack() + parser.noLazy = true + *self, err = parser.decodeObject(stack.v) + if err != 0 { + return parser.ExportError(err) + } + return nil +} + +func (self *Node) removeNode(i int) { + nb := self.len() - 1 + node := self.nodeAt(i) + if i == nb { + self.setCapAndLen(self.cap(), nb) + *node = Node{} + return + } + + from := self.nodeAt(i + 1) + memmove(unsafe.Pointer(node), unsafe.Pointer(from), _NODE_SIZE * uintptr(nb - i)) + + last := self.nodeAt(nb) + *last = Node{} + + self.setCapAndLen(self.cap(), nb) +} + +func (self *Node) removePair(i int) { + nb := self.len() - 1 + node := self.pairAt(i) + if i == nb { + self.setCapAndLen(self.cap(), nb) + *node = Pair{} + return + } + + from := self.pairAt(i + 1) + memmove(unsafe.Pointer(node), unsafe.Pointer(from), _PAIR_SIZE * uintptr(nb - i)) + + last := self.pairAt(nb) + *last = Pair{} + + self.setCapAndLen(self.cap(), nb) +} + +func (self *Node) toGenericArray() ([]interface{}, error) { + nb := self.len() + ret := make([]interface{}, nb) + if nb == 0 { + return ret, nil + } + + /* convert each item */ + var p = (*Node)(self.p) + x, err := p.Interface() + if err != nil { + return nil, err + } + ret[0] = x + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + x, err := p.Interface() + if err != nil { + return nil, err + } + ret[i] = x + } + + /* all done */ + return ret, nil +} + +func (self *Node) toGenericArrayUseNumber() ([]interface{}, error) { + nb := self.len() + ret := make([]interface{}, nb) + if nb == 0 { + return ret, nil + } + + /* convert each item */ + var p = (*Node)(self.p) + x, err := p.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[0] = x + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + x, err := p.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[i] = x + } + + /* all done */ + return ret, nil +} + +func (self *Node) toGenericArrayUseNode() ([]Node, error) { + var nb = self.len() + var out = make([]Node, nb) + if nb == 0 { + return out, nil + } + + var p = (*Node)(self.p) + out[0] = *p + if err := p.Check(); err != nil { + return nil, err + } + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + if err := p.Check(); err != nil { + return nil, err + } + out[i] = *p + } + + return out, nil +} + +func (self *Node) toGenericObject() (map[string]interface{}, error) { + nb := self.len() + ret := make(map[string]interface{}, nb) + if nb == 0 { + return ret, nil + } + + /* convert each item */ + var p = (*Pair)(self.p) + x, err := p.Value.Interface() + if err != nil { + return nil, err + } + ret[p.Key] = x + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + x, err := p.Value.Interface() + if err != nil { + return nil, err + } + ret[p.Key] = x + } + + /* all done */ + return ret, nil +} + + +func (self *Node) toGenericObjectUseNumber() (map[string]interface{}, error) { + nb := self.len() + ret := make(map[string]interface{}, nb) + if nb == 0 { + return ret, nil + } + + /* convert each item */ + var p = (*Pair)(self.p) + x, err := p.Value.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[p.Key] = x + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + x, err := p.Value.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[p.Key] = x + } + + /* all done */ + return ret, nil +} + +func (self *Node) toGenericObjectUseNode() (map[string]Node, error) { + var nb = self.len() + var out = make(map[string]Node, nb) + if nb == 0 { + return out, nil + } + + var p = (*Pair)(self.p) + out[p.Key] = p.Value + if err := p.Value.Check(); err != nil { + return nil, err + } + + for i := 1; i < nb; i++ { + p = p.unsafe_next() + if err := p.Value.Check(); err != nil { + return nil, err + } + out[p.Key] = p.Value + } + + /* all done */ + return out, nil +} + +/**------------------------------------ Factory Methods ------------------------------------**/ + +var ( + nullNode = Node{t: types.V_NULL} + trueNode = Node{t: types.V_TRUE} + falseNode = Node{t: types.V_FALSE} + + emptyArrayNode = Node{t: types.V_ARRAY} + emptyObjectNode = Node{t: types.V_OBJECT} +) + +// NewRaw creates a node of raw json. +// If the input json is invalid, NewRaw returns a error Node. +func NewRaw(json string) Node { + parser := NewParser(json) + start, err := parser.skip() + if err != 0 { + return *newError(err, err.Message()) + } + it := switchRawType(parser.s[start]) + if it == _V_NONE { + return Node{} + } + return newRawNode(parser.s[start:parser.p], it) +} + +// NewAny creates a node of type V_ANY if any's type isn't Node or *Node, +// which stores interface{} and can be only used for `.Interface()`\`.MarshalJSON()`. +func NewAny(any interface{}) Node { + switch n := any.(type) { + case Node: + return n + case *Node: + return *n + default: + return Node{ + t: _V_ANY, + v: 0, + p: unsafe.Pointer(&any), + } + } +} + +// NewBytes encodes given src with Base64 (RFC 4648), and creates a node of type V_STRING. +func NewBytes(src []byte) Node { + if len(src) == 0 { + panic("empty src bytes") + } + out := encodeBase64(src) + return NewString(out) +} + +// NewNull creates a node of type V_NULL +func NewNull() Node { + return Node{ + v: 0, + p: nil, + t: types.V_NULL, + } +} + +// NewBool creates a node of type bool: +// If v is true, returns V_TRUE node +// If v is false, returns V_FALSE node +func NewBool(v bool) Node { + var t = types.V_FALSE + if v { + t = types.V_TRUE + } + return Node{ + v: 0, + p: nil, + t: t, + } +} + +// NewNumber creates a json.Number node +// v must be a decimal string complying with RFC8259 +func NewNumber(v string) Node { + return Node{ + v: int64(len(v) & _LEN_MASK), + p: rt.StrPtr(v), + t: _V_NUMBER, + } +} + +func toNumber(node *Node) json.Number { + return json.Number(rt.StrFrom(node.p, node.v)) +} + +func numberToFloat64(node *Node) (float64, error) { + ret,err := toNumber(node).Float64() + if err != nil { + return 0, err + } + return ret, nil +} + +func numberToInt64(node *Node) (int64, error) { + ret,err := toNumber(node).Int64() + if err != nil { + return 0, err + } + return ret, nil +} + +func newBytes(v []byte) Node { + return Node{ + t: types.V_STRING, + p: mem2ptr(v), + v: int64(len(v) & _LEN_MASK), + } +} + +// NewString creates a node of type V_STRING. +// v is considered to be a valid UTF-8 string, +// which means it won't be validated and unescaped. +// when the node is encoded to json, v will be escaped. +func NewString(v string) Node { + return Node{ + t: types.V_STRING, + p: rt.StrPtr(v), + v: int64(len(v) & _LEN_MASK), + } +} + +// NewArray creates a node of type V_ARRAY, +// using v as its underlying children +func NewArray(v []Node) Node { + return Node{ + t: types.V_ARRAY, + v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS), + p: *(*unsafe.Pointer)(unsafe.Pointer(&v)), + } +} + +func (self *Node) setArray(v []Node) { + self.t = types.V_ARRAY + self.setCapAndLen(cap(v), len(v)) + self.p = *(*unsafe.Pointer)(unsafe.Pointer(&v)) +} + +// NewObject creates a node of type V_OBJECT, +// using v as its underlying children +func NewObject(v []Pair) Node { + return Node{ + t: types.V_OBJECT, + v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS), + p: *(*unsafe.Pointer)(unsafe.Pointer(&v)), + } +} + +func (self *Node) setObject(v []Pair) { + self.t = types.V_OBJECT + self.setCapAndLen(cap(v), len(v)) + self.p = *(*unsafe.Pointer)(unsafe.Pointer(&v)) +} + +type parseObjectStack struct { + parser Parser + v []Pair +} + +type parseArrayStack struct { + parser Parser + v []Node +} + +func newLazyArray(p *Parser, v []Node) Node { + s := new(parseArrayStack) + s.parser = *p + s.v = v + return Node{ + t: _V_ARRAY_LAZY, + v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS), + p: unsafe.Pointer(s), + } +} + +func (self *Node) setLazyArray(p *Parser, v []Node) { + s := new(parseArrayStack) + s.parser = *p + s.v = v + self.t = _V_ARRAY_LAZY + self.setCapAndLen(cap(v), len(v)) + self.p = (unsafe.Pointer)(s) +} + +func newLazyObject(p *Parser, v []Pair) Node { + s := new(parseObjectStack) + s.parser = *p + s.v = v + return Node{ + t: _V_OBJECT_LAZY, + v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS), + p: unsafe.Pointer(s), + } +} + +func (self *Node) setLazyObject(p *Parser, v []Pair) { + s := new(parseObjectStack) + s.parser = *p + s.v = v + self.t = _V_OBJECT_LAZY + self.setCapAndLen(cap(v), len(v)) + self.p = (unsafe.Pointer)(s) +} + +func newRawNode(str string, typ types.ValueType) Node { + return Node{ + t: _V_RAW | typ, + p: rt.StrPtr(str), + v: int64(len(str) & _LEN_MASK), + } +} + +func (self *Node) parseRaw(full bool) { + raw := rt.StrFrom(self.p, self.v) + parser := NewParser(raw) + if full { + parser.noLazy = true + parser.skipValue = false + } + var e types.ParsingError + *self, e = parser.Parse() + if e != 0 { + *self = *newSyntaxError(parser.syntaxError(e)) + } +} + +func newError(err types.ParsingError, msg string) *Node { + return &Node{ + t: V_ERROR, + v: int64(err), + p: unsafe.Pointer(&msg), + } +} + +var typeJumpTable = [256]types.ValueType{ + '"' : types.V_STRING, + '-' : _V_NUMBER, + '0' : _V_NUMBER, + '1' : _V_NUMBER, + '2' : _V_NUMBER, + '3' : _V_NUMBER, + '4' : _V_NUMBER, + '5' : _V_NUMBER, + '6' : _V_NUMBER, + '7' : _V_NUMBER, + '8' : _V_NUMBER, + '9' : _V_NUMBER, + '[' : types.V_ARRAY, + 'f' : types.V_FALSE, + 'n' : types.V_NULL, + 't' : types.V_TRUE, + '{' : types.V_OBJECT, +} + +func switchRawType(c byte) types.ValueType { + return typeJumpTable[c] +} + +func unwrapError(err error) *Node { + if se, ok := err.(*Node); ok { + return se + }else if sse, ok := err.(Node); ok { + return &sse + } else { + msg := err.Error() + return &Node{ + t: V_ERROR, + v: 0, + p: unsafe.Pointer(&msg), + } + } +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/parser.go b/vendor/github.com/bytedance/sonic/ast/parser.go new file mode 100644 index 0000000..0a8e7b0 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/parser.go @@ -0,0 +1,618 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `fmt` + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` +) + +const _DEFAULT_NODE_CAP int = 16 + +const ( + _ERR_NOT_FOUND types.ParsingError = 33 + _ERR_UNSUPPORT_TYPE types.ParsingError = 34 +) + +var ( + ErrNotExist error = newError(_ERR_NOT_FOUND, "value not exists") + ErrUnsupportType error = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") +) + +type Parser struct { + p int + s string + noLazy bool + skipValue bool +} + +/** Parser Private Methods **/ + +func (self *Parser) delim() types.ParsingError { + n := len(self.s) + p := self.lspace(self.p) + + /* check for EOF */ + if p >= n { + return types.ERR_EOF + } + + /* check for the delimtier */ + if self.s[p] != ':' { + return types.ERR_INVALID_CHAR + } + + /* update the read pointer */ + self.p = p + 1 + return 0 +} + +func (self *Parser) object() types.ParsingError { + n := len(self.s) + p := self.lspace(self.p) + + /* check for EOF */ + if p >= n { + return types.ERR_EOF + } + + /* check for the delimtier */ + if self.s[p] != '{' { + return types.ERR_INVALID_CHAR + } + + /* update the read pointer */ + self.p = p + 1 + return 0 +} + +func (self *Parser) array() types.ParsingError { + n := len(self.s) + p := self.lspace(self.p) + + /* check for EOF */ + if p >= n { + return types.ERR_EOF + } + + /* check for the delimtier */ + if self.s[p] != '[' { + return types.ERR_INVALID_CHAR + } + + /* update the read pointer */ + self.p = p + 1 + return 0 +} + +func (self *Parser) lspace(sp int) int { + ns := len(self.s) + for ; sp= ns { + return Node{}, types.ERR_EOF + } + + /* check for empty array */ + if self.s[self.p] == ']' { + self.p++ + return emptyArrayNode, 0 + } + + /* allocate array space and parse every element */ + for { + var val Node + var err types.ParsingError + + if self.skipValue { + /* skip the value */ + var start int + if start, err = self.skipFast(); err != 0 { + return Node{}, err + } + if self.p > ns { + return Node{}, types.ERR_EOF + } + t := switchRawType(self.s[start]) + if t == _V_NONE { + return Node{}, types.ERR_INVALID_CHAR + } + val = newRawNode(self.s[start:self.p], t) + }else{ + /* decode the value */ + if val, err = self.Parse(); err != 0 { + return Node{}, err + } + } + + /* add the value to result */ + ret = append(ret, val) + self.p = self.lspace(self.p) + + /* check for EOF */ + if self.p >= ns { + return Node{}, types.ERR_EOF + } + + /* check for the next character */ + switch self.s[self.p] { + case ',' : self.p++ + case ']' : self.p++; return NewArray(ret), 0 + default: + if val.isLazy() { + return newLazyArray(self, ret), 0 + } + return Node{}, types.ERR_INVALID_CHAR + } + } +} + +func (self *Parser) decodeObject(ret []Pair) (Node, types.ParsingError) { + sp := self.p + ns := len(self.s) + + /* check for EOF */ + if self.p = self.lspace(sp); self.p >= ns { + return Node{}, types.ERR_EOF + } + + /* check for empty object */ + if self.s[self.p] == '}' { + self.p++ + return emptyObjectNode, 0 + } + + /* decode each pair */ + for { + var val Node + var njs types.JsonState + var err types.ParsingError + + /* decode the key */ + if njs = self.decodeValue(); njs.Vt != types.V_STRING { + return Node{}, types.ERR_INVALID_CHAR + } + + /* extract the key */ + idx := self.p - 1 + key := self.s[njs.Iv:idx] + + /* check for escape sequence */ + if njs.Ep != -1 { + if key, err = unquote(key); err != 0 { + return Node{}, err + } + } + + /* expect a ':' delimiter */ + if err = self.delim(); err != 0 { + return Node{}, err + } + + + if self.skipValue { + /* skip the value */ + var start int + if start, err = self.skipFast(); err != 0 { + return Node{}, err + } + if self.p > ns { + return Node{}, types.ERR_EOF + } + t := switchRawType(self.s[start]) + if t == _V_NONE { + return Node{}, types.ERR_INVALID_CHAR + } + val = newRawNode(self.s[start:self.p], t) + } else { + /* decode the value */ + if val, err = self.Parse(); err != 0 { + return Node{}, err + } + } + + /* add the value to result */ + ret = append(ret, Pair{Key: key, Value: val}) + self.p = self.lspace(self.p) + + /* check for EOF */ + if self.p >= ns { + return Node{}, types.ERR_EOF + } + + /* check for the next character */ + switch self.s[self.p] { + case ',' : self.p++ + case '}' : self.p++; return NewObject(ret), 0 + default: + if val.isLazy() { + return newLazyObject(self, ret), 0 + } + return Node{}, types.ERR_INVALID_CHAR + } + } +} + +func (self *Parser) decodeString(iv int64, ep int) (Node, types.ParsingError) { + p := self.p - 1 + s := self.s[iv:p] + + /* fast path: no escape sequence */ + if ep == -1 { + return NewString(s), 0 + } + + /* unquote the string */ + out, err := unquote(s) + + /* check for errors */ + if err != 0 { + return Node{}, err + } else { + return newBytes(rt.Str2Mem(out)), 0 + } +} + +/** Parser Interface **/ + +func (self *Parser) Pos() int { + return self.p +} + +func (self *Parser) Parse() (Node, types.ParsingError) { + switch val := self.decodeValue(); val.Vt { + case types.V_EOF : return Node{}, types.ERR_EOF + case types.V_NULL : return nullNode, 0 + case types.V_TRUE : return trueNode, 0 + case types.V_FALSE : return falseNode, 0 + case types.V_STRING : return self.decodeString(val.Iv, val.Ep) + case types.V_ARRAY: + if self.noLazy { + return self.decodeArray(make([]Node, 0, _DEFAULT_NODE_CAP)) + } + return newLazyArray(self, make([]Node, 0, _DEFAULT_NODE_CAP)), 0 + case types.V_OBJECT: + if self.noLazy { + return self.decodeObject(make([]Pair, 0, _DEFAULT_NODE_CAP)) + } + return newLazyObject(self, make([]Pair, 0, _DEFAULT_NODE_CAP)), 0 + case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0 + case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0 + default : return Node{}, types.ParsingError(-val.Vt) + } +} + +func (self *Parser) searchKey(match string) types.ParsingError { + ns := len(self.s) + if err := self.object(); err != 0 { + return err + } + + /* check for EOF */ + if self.p = self.lspace(self.p); self.p >= ns { + return types.ERR_EOF + } + + /* check for empty object */ + if self.s[self.p] == '}' { + self.p++ + return _ERR_NOT_FOUND + } + + var njs types.JsonState + var err types.ParsingError + /* decode each pair */ + for { + + /* decode the key */ + if njs = self.decodeValue(); njs.Vt != types.V_STRING { + return types.ERR_INVALID_CHAR + } + + /* extract the key */ + idx := self.p - 1 + key := self.s[njs.Iv:idx] + + /* check for escape sequence */ + if njs.Ep != -1 { + if key, err = unquote(key); err != 0 { + return err + } + } + + /* expect a ':' delimiter */ + if err = self.delim(); err != 0 { + return err + } + + /* skip value */ + if key != match { + if _, err = self.skipFast(); err != 0 { + return err + } + } else { + return 0 + } + + /* check for EOF */ + self.p = self.lspace(self.p) + if self.p >= ns { + return types.ERR_EOF + } + + /* check for the next character */ + switch self.s[self.p] { + case ',': + self.p++ + case '}': + self.p++ + return _ERR_NOT_FOUND + default: + return types.ERR_INVALID_CHAR + } + } +} + +func (self *Parser) searchIndex(idx int) types.ParsingError { + ns := len(self.s) + if err := self.array(); err != 0 { + return err + } + + /* check for EOF */ + if self.p = self.lspace(self.p); self.p >= ns { + return types.ERR_EOF + } + + /* check for empty array */ + if self.s[self.p] == ']' { + self.p++ + return _ERR_NOT_FOUND + } + + var err types.ParsingError + /* allocate array space and parse every element */ + for i := 0; i < idx; i++ { + + /* decode the value */ + if _, err = self.skipFast(); err != 0 { + return err + } + + /* check for EOF */ + self.p = self.lspace(self.p) + if self.p >= ns { + return types.ERR_EOF + } + + /* check for the next character */ + switch self.s[self.p] { + case ',': + self.p++ + case ']': + self.p++ + return _ERR_NOT_FOUND + default: + return types.ERR_INVALID_CHAR + } + } + + return 0 +} + +func (self *Node) skipNextNode() *Node { + if !self.isLazy() { + return nil + } + + parser, stack := self.getParserAndArrayStack() + ret := stack.v + sp := parser.p + ns := len(parser.s) + + /* check for EOF */ + if parser.p = parser.lspace(sp); parser.p >= ns { + return newSyntaxError(parser.syntaxError(types.ERR_EOF)) + } + + /* check for empty array */ + if parser.s[parser.p] == ']' { + parser.p++ + self.setArray(ret) + return nil + } + + var val Node + /* skip the value */ + if start, err := parser.skipFast(); err != 0 { + return newSyntaxError(parser.syntaxError(err)) + } else { + t := switchRawType(parser.s[start]) + if t == _V_NONE { + return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) + } + val = newRawNode(parser.s[start:parser.p], t) + } + + /* add the value to result */ + ret = append(ret, val) + parser.p = parser.lspace(parser.p) + + /* check for EOF */ + if parser.p >= ns { + return newSyntaxError(parser.syntaxError(types.ERR_EOF)) + } + + /* check for the next character */ + switch parser.s[parser.p] { + case ',': + parser.p++ + self.setLazyArray(parser, ret) + return &ret[len(ret)-1] + case ']': + parser.p++ + self.setArray(ret) + return &ret[len(ret)-1] + default: + return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) + } +} + +func (self *Node) skipNextPair() (*Pair) { + if !self.isLazy() { + return nil + } + + parser, stack := self.getParserAndObjectStack() + ret := stack.v + sp := parser.p + ns := len(parser.s) + + /* check for EOF */ + if parser.p = parser.lspace(sp); parser.p >= ns { + return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_EOF))} + } + + /* check for empty object */ + if parser.s[parser.p] == '}' { + parser.p++ + self.setObject(ret) + return nil + } + + /* decode one pair */ + var val Node + var njs types.JsonState + var err types.ParsingError + + /* decode the key */ + if njs = parser.decodeValue(); njs.Vt != types.V_STRING { + return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + } + + /* extract the key */ + idx := parser.p - 1 + key := parser.s[njs.Iv:idx] + + /* check for escape sequence */ + if njs.Ep != -1 { + if key, err = unquote(key); err != 0 { + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + } + } + + /* expect a ':' delimiter */ + if err = parser.delim(); err != 0 { + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + } + + /* skip the value */ + if start, err := parser.skipFast(); err != 0 { + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + } else { + t := switchRawType(parser.s[start]) + if t == _V_NONE { + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + } + val = newRawNode(parser.s[start:parser.p], t) + } + + /* add the value to result */ + ret = append(ret, Pair{Key: key, Value: val}) + parser.p = parser.lspace(parser.p) + + /* check for EOF */ + if parser.p >= ns { + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_EOF))} + } + + /* check for the next character */ + switch parser.s[parser.p] { + case ',': + parser.p++ + self.setLazyObject(parser, ret) + return &ret[len(ret)-1] + case '}': + parser.p++ + self.setObject(ret) + return &ret[len(ret)-1] + default: + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + } +} + + +/** Parser Factory **/ + +// Loads parse all json into interface{} +func Loads(src string) (int, interface{}, error) { + ps := &Parser{s: src} + np, err := ps.Parse() + + /* check for errors */ + if err != 0 { + return 0, nil, ps.ExportError(err) + } else { + x, err := np.Interface() + if err != nil { + return 0, nil, err + } + return ps.Pos(), x, nil + } +} + +// LoadsUseNumber parse all json into interface{}, with numeric nodes casted to json.Number +func LoadsUseNumber(src string) (int, interface{}, error) { + ps := &Parser{s: src} + np, err := ps.Parse() + + /* check for errors */ + if err != 0 { + return 0, nil, err + } else { + x, err := np.InterfaceUseNumber() + if err != nil { + return 0, nil, err + } + return ps.Pos(), x, nil + } +} + +func NewParser(src string) *Parser { + return &Parser{s: src} +} + +// ExportError converts types.ParsingError to std Error +func (self *Parser) ExportError(err types.ParsingError) error { + if err == _ERR_NOT_FOUND { + return ErrNotExist + } + return fmt.Errorf("%q", SyntaxError{ + Pos : self.p, + Src : self.s, + Code: err, + }.Description()) +} \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/search.go b/vendor/github.com/bytedance/sonic/ast/search.go new file mode 100644 index 0000000..bb6fcea --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/search.go @@ -0,0 +1,30 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +type Searcher struct { + parser Parser +} + +func NewSearcher(str string) *Searcher { + return &Searcher{ + parser: Parser{ + s: str, + noLazy: false, + }, + } +} diff --git a/vendor/github.com/bytedance/sonic/ast/sort.go b/vendor/github.com/bytedance/sonic/ast/sort.go new file mode 100644 index 0000000..0a9f145 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/sort.go @@ -0,0 +1,206 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +// Algorithm 3-way Radix Quicksort, d means the radix. +// Reference: https://algs4.cs.princeton.edu/51radix/Quick3string.java.html +func radixQsort(kvs PairSlice, d, maxDepth int) { + for len(kvs) > 11 { + // To avoid the worst case of quickSort (time: O(n^2)), use introsort here. + // Reference: https://en.wikipedia.org/wiki/Introsort and + // https://github.com/golang/go/issues/467 + if maxDepth == 0 { + heapSort(kvs, 0, len(kvs)) + return + } + maxDepth-- + + p := pivot(kvs, d) + lt, i, gt := 0, 0, len(kvs) + for i < gt { + c := byteAt(kvs[i].Key, d) + if c < p { + swap(kvs, lt, i) + i++ + lt++ + } else if c > p { + gt-- + swap(kvs, i, gt) + } else { + i++ + } + } + + // kvs[0:lt] < v = kvs[lt:gt] < kvs[gt:len(kvs)] + // Native implemention: + // radixQsort(kvs[:lt], d, maxDepth) + // if p > -1 { + // radixQsort(kvs[lt:gt], d+1, maxDepth) + // } + // radixQsort(kvs[gt:], d, maxDepth) + // Optimize as follows: make recursive calls only for the smaller parts. + // Reference: https://www.geeksforgeeks.org/quicksort-tail-call-optimization-reducing-worst-case-space-log-n/ + if p == -1 { + if lt > len(kvs) - gt { + radixQsort(kvs[gt:], d, maxDepth) + kvs = kvs[:lt] + } else { + radixQsort(kvs[:lt], d, maxDepth) + kvs = kvs[gt:] + } + } else { + ml := maxThree(lt, gt-lt, len(kvs)-gt) + if ml == lt { + radixQsort(kvs[lt:gt], d+1, maxDepth) + radixQsort(kvs[gt:], d, maxDepth) + kvs = kvs[:lt] + } else if ml == gt-lt { + radixQsort(kvs[:lt], d, maxDepth) + radixQsort(kvs[gt:], d, maxDepth) + kvs = kvs[lt:gt] + d += 1 + } else { + radixQsort(kvs[:lt], d, maxDepth) + radixQsort(kvs[lt:gt], d+1, maxDepth) + kvs = kvs[gt:] + } + } + } + insertRadixSort(kvs, d) +} + +func insertRadixSort(kvs PairSlice, d int) { + for i := 1; i < len(kvs); i++ { + for j := i; j > 0 && lessFrom(kvs[j].Key, kvs[j-1].Key, d); j-- { + swap(kvs, j, j-1) + } + } +} + +func pivot(kvs PairSlice, d int) int { + m := len(kvs) >> 1 + if len(kvs) > 40 { + // Tukey's ``Ninther,'' median of three mediankvs of three. + t := len(kvs) / 8 + return medianThree( + medianThree(byteAt(kvs[0].Key, d), byteAt(kvs[t].Key, d), byteAt(kvs[2*t].Key, d)), + medianThree(byteAt(kvs[m].Key, d), byteAt(kvs[m-t].Key, d), byteAt(kvs[m+t].Key, d)), + medianThree(byteAt(kvs[len(kvs)-1].Key, d), + byteAt(kvs[len(kvs)-1-t].Key, d), + byteAt(kvs[len(kvs)-1-2*t].Key, d))) + } + return medianThree(byteAt(kvs[0].Key, d), byteAt(kvs[m].Key, d), byteAt(kvs[len(kvs)-1].Key, d)) +} + +func medianThree(i, j, k int) int { + if i > j { + i, j = j, i + } // i < j + if k < i { + return i + } + if k > j { + return j + } + return k +} + +func maxThree(i, j, k int) int { + max := i + if max < j { + max = j + } + if max < k { + max = k + } + return max +} + +// maxDepth returns a threshold at which quicksort should switch +// to heapsort. It returnkvs 2*ceil(lg(n+1)). +func maxDepth(n int) int { + var depth int + for i := n; i > 0; i >>= 1 { + depth++ + } + return depth * 2 +} + +// siftDown implements the heap property on kvs[lo:hi]. +// first is an offset into the array where the root of the heap lies. +func siftDown(kvs PairSlice, lo, hi, first int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && kvs[first+child].Key < kvs[first+child+1].Key { + child++ + } + if kvs[first+root].Key >= kvs[first+child].Key { + return + } + swap(kvs, first+root, first+child) + root = child + } +} + +func heapSort(kvs PairSlice, a, b int) { + first := a + lo := 0 + hi := b - a + + // Build heap with the greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDown(kvs, i, hi, first) + } + + // Pop elements, the largest first, into end of kvs. + for i := hi - 1; i >= 0; i-- { + swap(kvs, first, first+i) + siftDown(kvs, lo, i, first) + } +} + +// Note that Pair.Key is NOT pointed to Pair.m when map key is integer after swap +func swap(kvs PairSlice, a, b int) { + kvs[a].Key, kvs[b].Key = kvs[b].Key, kvs[a].Key + kvs[a].Value, kvs[b].Value = kvs[b].Value, kvs[a].Value +} + +// Compare two strings from the pos d. +func lessFrom(a, b string, d int) bool { + l := len(a) + if l > len(b) { + l = len(b) + } + for i := d; i < l; i++ { + if a[i] == b[i] { + continue + } + return a[i] < b[i] + } + return len(a) < len(b) +} + +func byteAt(b string, p int) int { + if p < len(b) { + return int(b[p]) + } + return -1 +} diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go115.go b/vendor/github.com/bytedance/sonic/ast/stubs_go115.go new file mode 100644 index 0000000..37b9451 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/stubs_go115.go @@ -0,0 +1,55 @@ +// +build !go1.20 + +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `unsafe` + `unicode/utf8` + + `github.com/bytedance/sonic/internal/rt` +) + +//go:noescape +//go:linkname memmove runtime.memmove +//goland:noinspection GoUnusedParameter +func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) + +//go:linkname unsafe_NewArray reflect.unsafe_NewArray +//goland:noinspection GoUnusedParameter +func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer + +//go:linkname growslice runtime.growslice +//goland:noinspection GoUnusedParameter +func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice + +//go:nosplit +func mem2ptr(s []byte) unsafe.Pointer { + return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr +} + +var ( + //go:linkname safeSet encoding/json.safeSet + safeSet [utf8.RuneSelf]bool + + //go:linkname hex encoding/json.hex + hex string +) + +//go:linkname unquoteBytes encoding/json.unquoteBytes +func unquoteBytes(s []byte) (t []byte, ok bool) \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go120.go b/vendor/github.com/bytedance/sonic/ast/stubs_go120.go new file mode 100644 index 0000000..bd6fff6 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/stubs_go120.go @@ -0,0 +1,55 @@ +// +build go1.20 + +/* + * Copyright 2021 ByteDance Inc. + * + * 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 ast + +import ( + `unsafe` + `unicode/utf8` + + `github.com/bytedance/sonic/internal/rt` +) + +//go:noescape +//go:linkname memmove runtime.memmove +//goland:noinspection GoUnusedParameter +func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) + +//go:linkname unsafe_NewArray reflect.unsafe_NewArray +//goland:noinspection GoUnusedParameter +func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer + +//go:linkname growslice reflect.growslice +//goland:noinspection GoUnusedParameter +func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice + +//go:nosplit +func mem2ptr(s []byte) unsafe.Pointer { + return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr +} + +var ( + //go:linkname safeSet encoding/json.safeSet + safeSet [utf8.RuneSelf]bool + + //go:linkname hex encoding/json.hex + hex string +) + +//go:linkname unquoteBytes encoding/json.unquoteBytes +func unquoteBytes(s []byte) (t []byte, ok bool) \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/bench-arm.sh b/vendor/github.com/bytedance/sonic/bench-arm.sh new file mode 100644 index 0000000..b47d627 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/bench-arm.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +pwd=$(pwd) +export SONIC_NO_ASYNC_GC=1 + +cd $pwd/ast +go test -benchmem -run=^$ -benchtime=1000000x -bench "^(BenchmarkGet.*|BenchmarkSet.*)$" + +go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_.*|BenchmarkEncode.*)$" + +go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$" + +unset SONIC_NO_ASYNC_GC +cd $pwd \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/bench.py b/vendor/github.com/bytedance/sonic/bench.py new file mode 100644 index 0000000..1d4c357 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/bench.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +# Copyright 2022 ByteDance Inc. +# +# 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. + +import tempfile +import os +import subprocess +import argparse + +gbench_prefix = "SONIC_NO_ASYNC_GC=1 go test -benchmem -run=none " + +def run(cmd): + print(cmd) + if os.system(cmd): + print ("Failed to run cmd: %s"%(cmd)) + exit(1) + +def run_s(cmd): + print (cmd) + try: + res = os.popen(cmd) + except subprocess.CalledProcessError as e: + if e.returncode: + print (e.output) + exit(1) + return res.read() + +def run_r(cmd): + print (cmd) + try: + cmds = cmd.split(' ') + data = subprocess.check_output(cmds, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + if e.returncode: + print (e.output) + exit(1) + return data.decode("utf-8") + +def compare(args): + # detech current branch. + # result = run_r("git branch") + current_branch = run_s("git status | head -n1 | sed 's/On branch //'") + # for br in result.split('\n'): + # if br.startswith("* "): + # current_branch = br.lstrip('* ') + # break + + if not current_branch: + print ("Failed to detech current branch") + return None + + # get the current diff + (fd, diff) = tempfile.mkstemp() + run("git diff > %s"%diff) + + # early return if currrent is main branch. + print ("Current branch: %s"%(current_branch)) + if current_branch == "main": + print ("Cannot compare at the main branch.Please build a new branch") + return None + + # benchmark current branch + (fd, target) = tempfile.mkstemp(".target.txt") + run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, args, target)) + + # trying to switch to the latest main branch + run("git checkout -- .") + if current_branch != "main": + run("git checkout main") + run("git pull --allow-unrelated-histories origin main") + + # benchmark main branch + (fd, main) = tempfile.mkstemp(".main.txt") + run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, args, main)) + + # diff the result + # benchstat = "go get golang.org/x/perf/cmd/benchstat && go install golang.org/x/perf/cmd/benchstat" + run( "benchstat -sort=delta %s %s"%(main, target)) + run("git checkout -- .") + + # restore branch + if current_branch != "main": + run("git checkout %s"%(current_branch)) + run("patch -p1 < %s" % (diff)) + return target + +def main(): + argparser = argparse.ArgumentParser(description='Tools to test the performance. Example: ./bench.py -b Decoder_Generic_Sonic -c') + argparser.add_argument('-b', '--bench', dest='filter', required=False, + help='Specify the filter for golang benchmark') + argparser.add_argument('-c', '--compare', dest='compare', action='store_true', required=False, + help='Compare with the main benchmarking') + argparser.add_argument('-t', '--times', dest='times', required=False, + help='benchmark the times') + argparser.add_argument('-r', '--repeat_times', dest='count', required=False, + help='benchmark the count') + args = argparser.parse_args() + + if args.filter: + gbench_args = "-bench=%s"%(args.filter) + else: + gbench_args = "-bench=." + + if args.times: + gbench_args += " -benchtime=%s"%(args.times) + + if args.count: + gbench_args += " -count=%s"%(args.count) + else: + gbench_args += " -count=10" + + if args.compare: + target = compare(gbench_args) + else: + target = None + + if not target: + (fd, target) = tempfile.mkstemp(".target.txt") + run("%s %s ./... 2>&1 | tee %s" %(gbench_prefix, gbench_args, target)) + +if __name__ == "__main__": + main() diff --git a/vendor/github.com/bytedance/sonic/bench.sh b/vendor/github.com/bytedance/sonic/bench.sh new file mode 100644 index 0000000..701986b --- /dev/null +++ b/vendor/github.com/bytedance/sonic/bench.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +pwd=$(pwd) +export SONIC_NO_ASYNC_GC=1 + +cd $pwd/encoder +go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkEncoder_.*)$" + +cd $pwd/decoder +go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkDecoder_.*)$" + +cd $pwd/ast +go test -benchmem -run=^$ -benchtime=1000000x -bench "^(BenchmarkGet.*|BenchmarkSet.*)$" + +go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_.*|BenchmarkEncode.*)$" + +go test -benchmem -run=^$ -benchtime=10000000x -bench "^(BenchmarkNodeGetByPath|BenchmarkStructGetByPath|BenchmarkNodeIndex|BenchmarkStructIndex|BenchmarkSliceIndex|BenchmarkMapIndex|BenchmarkNodeGet|BenchmarkSliceGet|BenchmarkMapGet|BenchmarkNodeSet|BenchmarkMapSet|BenchmarkNodeSetByIndex|BenchmarkSliceSetByIndex|BenchmarkStructSetByIndex|BenchmarkNodeUnset|BenchmarkMapUnset|BenchmarkNodUnsetByIndex|BenchmarkSliceUnsetByIndex|BenchmarkNodeAdd|BenchmarkSliceAdd|BenchmarkMapAdd)$" + +cd $pwd/external_jsonlib_test/benchmark_test +go test -benchmem -run=^$ -benchtime=100000x -bench "^(BenchmarkEncoder_.*|BenchmarkDecoder_.*)$" + +go test -benchmem -run=^$ -benchtime=1000000x -bench "^(BenchmarkGet.*|BenchmarkSet.*)$" + +go test -benchmem -run=^$ -benchtime=10000x -bench "^(BenchmarkParser_.*)$" + +unset SONIC_NO_ASYNC_GC +cd $pwd \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/check_branch_name.sh b/vendor/github.com/bytedance/sonic/check_branch_name.sh new file mode 100644 index 0000000..d1905da --- /dev/null +++ b/vendor/github.com/bytedance/sonic/check_branch_name.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +current=$(git status | head -n1 | sed 's/On branch //') +name=${1:-$current} +if [[ ! $name =~ ^(((opt(imize)?|feat(ure)?|doc|(bug|hot)?fix|test|refact(or)?|ci)/.+)|(main|develop)|(release/.+)|(release-v[0-9]+\.[0-9]+)|(release/v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.]+(\+[a-z0-9.]+)?)?)|revert-[a-z0-9]+)$ ]]; then + echo "branch name '$name' is invalid" + exit 1 +else + echo "branch name '$name' is valid" +fi diff --git a/vendor/github.com/bytedance/sonic/compat.go b/vendor/github.com/bytedance/sonic/compat.go new file mode 100644 index 0000000..015aa62 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/compat.go @@ -0,0 +1,131 @@ +// +build !amd64 go1.21 + +/* + * Copyright 2021 ByteDance Inc. + * + * 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 sonic + +import ( + `bytes` + `encoding/json` + `io` + `reflect` + + `github.com/bytedance/sonic/option` +) + +type frozenConfig struct { + Config +} + +// Froze convert the Config to API +func (cfg Config) Froze() API { + api := &frozenConfig{Config: cfg} + return api +} + +func (cfg frozenConfig) marshalOptions(val interface{}, prefix, indent string) ([]byte, error) { + w := bytes.NewBuffer([]byte{}) + enc := json.NewEncoder(w) + enc.SetEscapeHTML(cfg.EscapeHTML) + enc.SetIndent(prefix, indent) + err := enc.Encode(val) + out := w.Bytes() + + // json.Encoder always appends '\n' after encoding, + // which is not same with json.Marshal() + if len(out) > 0 && out[len(out)-1] == '\n' { + out = out[:len(out)-1] + } + return out, err +} + +// Marshal is implemented by sonic +func (cfg frozenConfig) Marshal(val interface{}) ([]byte, error) { + if !cfg.EscapeHTML { + return cfg.marshalOptions(val, "", "") + } + return json.Marshal(val) +} + +// MarshalToString is implemented by sonic +func (cfg frozenConfig) MarshalToString(val interface{}) (string, error) { + out, err := cfg.Marshal(val) + return string(out), err +} + +// MarshalIndent is implemented by sonic +func (cfg frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) { + if !cfg.EscapeHTML { + return cfg.marshalOptions(val, prefix, indent) + } + return json.MarshalIndent(val, prefix, indent) +} + +// UnmarshalFromString is implemented by sonic +func (cfg frozenConfig) UnmarshalFromString(buf string, val interface{}) error { + r := bytes.NewBufferString(buf) + dec := json.NewDecoder(r) + if cfg.UseNumber { + dec.UseNumber() + } + if cfg.DisallowUnknownFields { + dec.DisallowUnknownFields() + } + return dec.Decode(val) +} + +// Unmarshal is implemented by sonic +func (cfg frozenConfig) Unmarshal(buf []byte, val interface{}) error { + return cfg.UnmarshalFromString(string(buf), val) +} + +// NewEncoder is implemented by sonic +func (cfg frozenConfig) NewEncoder(writer io.Writer) Encoder { + enc := json.NewEncoder(writer) + if !cfg.EscapeHTML { + enc.SetEscapeHTML(cfg.EscapeHTML) + } + return enc +} + +// NewDecoder is implemented by sonic +func (cfg frozenConfig) NewDecoder(reader io.Reader) Decoder { + dec := json.NewDecoder(reader) + if cfg.UseNumber { + dec.UseNumber() + } + if cfg.DisallowUnknownFields { + dec.DisallowUnknownFields() + } + return dec +} + +// Valid is implemented by sonic +func (cfg frozenConfig) Valid(data []byte) bool { + return json.Valid(data) +} + +// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in +// order to reduce the first-hit latency at **amd64** Arch. +// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is +// a compile option to set the depth of recursive compile for the nested struct type. +// * This is the none implement for !amd64. +// It will be useful for someone who develop with !amd64 arch,like Mac M1. +func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { + return nil +} + diff --git a/vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go b/vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go new file mode 100644 index 0000000..2ef1995 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go @@ -0,0 +1,66 @@ +// +build amd64,go1.15,!go1.21 + +/* +* Copyright 2023 ByteDance Inc. +* +* 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 decoder + +import ( + `github.com/bytedance/sonic/internal/decoder` +) + +// Decoder is the decoder context object +type Decoder = decoder.Decoder + +type MismatchTypeError = decoder.MismatchTypeError + +// Options for decode. +type Options = decoder.Options + +const ( + OptionUseInt64 Options = decoder.OptionUseInt64 + OptionUseNumber Options = decoder.OptionUseNumber + OptionUseUnicodeErrors Options = decoder.OptionUseUnicodeErrors + OptionDisableUnknown Options = decoder.OptionDisableUnknown + OptionCopyString Options = decoder.OptionCopyString + OptionValidateString Options = decoder.OptionValidateString +) + +// StreamDecoder is the decoder context object for streaming input. +type StreamDecoder = decoder.StreamDecoder + +type SyntaxError = decoder.SyntaxError + +var ( + // NewDecoder creates a new decoder instance. + NewDecoder = decoder.NewDecoder + + // NewStreamDecoder adapts to encoding/json.NewDecoder API. + // + // NewStreamDecoder returns a new decoder that reads from r. + NewStreamDecoder = decoder.NewStreamDecoder + + // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in + // order to reduce the first-hit latency. + // + // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is + // a compile option to set the depth of recursive compile for the nested struct type. + Pretouch = decoder.Pretouch + + // Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid. + // Otherwise, returns negative error code using start and invalid character position using end + Skip = decoder.Skip +) diff --git a/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go b/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go new file mode 100644 index 0000000..e6b9463 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go @@ -0,0 +1,196 @@ +// +build !amd64 go1.21 + +/* +* Copyright 2023 ByteDance Inc. +* +* 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 decoder + +import ( + `encoding/json` + `bytes` + `reflect` + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/option` + `io` +) + +const ( + _F_use_int64 = iota + _F_use_number + _F_disable_urc + _F_disable_unknown + _F_copy_string + _F_validate_string + + _F_allow_control = 31 +) + +type Options uint64 + +const ( + OptionUseInt64 Options = 1 << _F_use_int64 + OptionUseNumber Options = 1 << _F_use_number + OptionUseUnicodeErrors Options = 1 << _F_disable_urc + OptionDisableUnknown Options = 1 << _F_disable_unknown + OptionCopyString Options = 1 << _F_copy_string + OptionValidateString Options = 1 << _F_validate_string +) + +func (self *Decoder) SetOptions(opts Options) { + if (opts & OptionUseNumber != 0) && (opts & OptionUseInt64 != 0) { + panic("can't set OptionUseInt64 and OptionUseNumber both!") + } + self.f = uint64(opts) +} + + +// Decoder is the decoder context object +type Decoder struct { + i int + f uint64 + s string +} + +// NewDecoder creates a new decoder instance. +func NewDecoder(s string) *Decoder { + return &Decoder{s: s} +} + +// Pos returns the current decoding position. +func (self *Decoder) Pos() int { + return self.i +} + +func (self *Decoder) Reset(s string) { + self.s = s + self.i = 0 + // self.f = 0 +} + +// NOTE: api fallback do nothing +func (self *Decoder) CheckTrailings() error { + pos := self.i + buf := self.s + /* skip all the trailing spaces */ + if pos != len(buf) { + for pos < len(buf) && (types.SPACE_MASK & (1 << buf[pos])) != 0 { + pos++ + } + } + + /* then it must be at EOF */ + if pos == len(buf) { + return nil + } + + /* junk after JSON value */ + return nil +} + + +// Decode parses the JSON-encoded data from current position and stores the result +// in the value pointed to by val. +func (self *Decoder) Decode(val interface{}) error { + r := bytes.NewBufferString(self.s) + dec := json.NewDecoder(r) + if (self.f | uint64(OptionUseNumber)) != 0 { + dec.UseNumber() + } + if (self.f | uint64(OptionDisableUnknown)) != 0 { + dec.DisallowUnknownFields() + } + return dec.Decode(val) +} + +// UseInt64 indicates the Decoder to unmarshal an integer into an interface{} as an +// int64 instead of as a float64. +func (self *Decoder) UseInt64() { + self.f |= 1 << _F_use_int64 + self.f &^= 1 << _F_use_number +} + +// UseNumber indicates the Decoder to unmarshal a number into an interface{} as a +// json.Number instead of as a float64. +func (self *Decoder) UseNumber() { + self.f &^= 1 << _F_use_int64 + self.f |= 1 << _F_use_number +} + +// UseUnicodeErrors indicates the Decoder to return an error when encounter invalid +// UTF-8 escape sequences. +func (self *Decoder) UseUnicodeErrors() { + self.f |= 1 << _F_disable_urc +} + +// DisallowUnknownFields indicates the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (self *Decoder) DisallowUnknownFields() { + self.f |= 1 << _F_disable_unknown +} + +// CopyString indicates the Decoder to decode string values by copying instead of referring. +func (self *Decoder) CopyString() { + self.f |= 1 << _F_copy_string +} + +// ValidateString causes the Decoder to validate string values when decoding string value +// in JSON. Validation is that, returning error when unescaped control chars(0x00-0x1f) or +// invalid UTF-8 chars in the string value of JSON. +func (self *Decoder) ValidateString() { + self.f |= 1 << _F_validate_string +} + +// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in +// order to reduce the first-hit latency. +// +// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is +// a compile option to set the depth of recursive compile for the nested struct type. +func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { + return nil +} + +type StreamDecoder struct { + r io.Reader + buf []byte + scanp int + scanned int64 + err error + Decoder +} + +// NewStreamDecoder adapts to encoding/json.NewDecoder API. +// +// NewStreamDecoder returns a new decoder that reads from r. +func NewStreamDecoder(r io.Reader) *StreamDecoder { + return &StreamDecoder{r : r} +} + +// Decode decodes input stream into val with corresponding data. +// Redundantly bytes may be read and left in its buffer, and can be used at next call. +// Either io error from underlying io.Reader (except io.EOF) +// or syntax error from data will be recorded and stop subsequently decoding. +func (self *StreamDecoder) Decode(val interface{}) (err error) { + dec := json.NewDecoder(self.r) + if (self.f | uint64(OptionUseNumber)) != 0 { + dec.UseNumber() + } + if (self.f | uint64(OptionDisableUnknown)) != 0 { + dec.DisallowUnknownFields() + } + return dec.Decode(val) +} + diff --git a/vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go b/vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go new file mode 100644 index 0000000..fa107c7 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go @@ -0,0 +1,108 @@ +// +build amd64,go1.15,!go1.21 + +/* + * Copyright 2023 ByteDance Inc. + * + * 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 encoder + +import ( + `github.com/bytedance/sonic/internal/encoder` +) + + +// Encoder represents a specific set of encoder configurations. +type Encoder = encoder.Encoder + +// StreamEncoder uses io.Writer as input. +type StreamEncoder = encoder.StreamEncoder + +// Options is a set of encoding options. +type Options = encoder.Options + +const ( + // SortMapKeys indicates that the keys of a map needs to be sorted + // before serializing into JSON. + // WARNING: This hurts performance A LOT, USE WITH CARE. + SortMapKeys Options = encoder.SortMapKeys + + // EscapeHTML indicates encoder to escape all HTML characters + // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape). + // WARNING: This hurts performance A LOT, USE WITH CARE. + EscapeHTML Options = encoder.EscapeHTML + + // CompactMarshaler indicates that the output JSON from json.Marshaler + // is always compact and needs no validation + CompactMarshaler Options = encoder.CompactMarshaler + + // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler + // is always escaped string and needs no quoting + NoQuoteTextMarshaler Options = encoder.NoQuoteTextMarshaler + + // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}', + // instead of 'null' + NoNullSliceOrMap Options = encoder.NoNullSliceOrMap + + // ValidateString indicates that encoder should validate the input string + // before encoding it into JSON. + ValidateString Options = encoder.ValidateString + + // CompatibleWithStd is used to be compatible with std encoder. + CompatibleWithStd Options = encoder.CompatibleWithStd +) + + +var ( + // Encode returns the JSON encoding of val, encoded with opts. + Encode = encoder.Encode + + // EncodeInto is like Encode but uses a user-supplied buffer instead of allocating a new one. + EncodeIndented = encoder.EncodeIndented + + // EncodeIndented is like Encode but applies Indent to format the output. + // Each JSON element in the output will begin on a new line beginning with prefix + // followed by one or more copies of indent according to the indentation nesting. + EncodeInto = encoder.EncodeInto + + // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 + // characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 + // so that the JSON will be safe to embed inside HTML - - -

Welcome, Ginner!

- - -`)) - -func main() { - r := gin.Default() - r.Static("/assets", "./assets") - r.SetHTMLTemplate(html) - - r.GET("/", func(c *gin.Context) { - if pusher := c.Writer.Pusher(); pusher != nil { - // use pusher.Push() to do server push - if err := pusher.Push("/assets/app.js", nil); err != nil { - log.Printf("Failed to push: %v", err) - } - } - c.HTML(http.StatusOK, "https", gin.H{ - "status": "success", - }) - }) - - // Listen and Server in https://127.0.0.1:8080 - r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key") -} -``` - -### Define format for the log of routes - -The default log of routes is: -``` -[GIN-debug] POST /foo --> main.main.func1 (3 handlers) -[GIN-debug] GET /bar --> main.main.func2 (3 handlers) -[GIN-debug] GET /status --> main.main.func3 (3 handlers) -``` - -If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`. -In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs. -```go -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -func main() { - r := gin.Default() - gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { - log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) - } - - r.POST("/foo", func(c *gin.Context) { - c.JSON(http.StatusOK, "foo") - }) - - r.GET("/bar", func(c *gin.Context) { - c.JSON(http.StatusOK, "bar") - }) - - r.GET("/status", func(c *gin.Context) { - c.JSON(http.StatusOK, "ok") - }) - - // Listen and Server in http://0.0.0.0:8080 - r.Run() -} -``` - -### Set and get a cookie - -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - - router.GET("/cookie", func(c *gin.Context) { - - cookie, err := c.Cookie("gin_cookie") - - if err != nil { - cookie = "NotSet" - c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true) - } - - fmt.Printf("Cookie value: %s \n", cookie) - }) - - router.Run() -} -``` - -## Don't trust all proxies - -Gin lets you specify which headers to hold the real client IP (if any), -as well as specifying which proxies (or direct clients) you trust to -specify one of these headers. - -Use function `SetTrustedProxies()` on your `gin.Engine` to specify network addresses -or network CIDRs from where clients which their request headers related to client -IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or -IPv6 CIDRs. - -**Attention:** Gin trust all proxies by default if you don't specify a trusted -proxy using the function above, **this is NOT safe**. At the same time, if you don't -use any proxy, you can disable this feature by using `Engine.SetTrustedProxies(nil)`, -then `Context.ClientIP()` will return the remote address directly to avoid some -unnecessary computation. - -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - router.SetTrustedProxies([]string{"192.168.1.2"}) - - router.GET("/", func(c *gin.Context) { - // If the client is 192.168.1.2, use the X-Forwarded-For - // header to deduce the original client IP from the trust- - // worthy parts of that header. - // Otherwise, simply return the direct client IP - fmt.Printf("ClientIP: %s\n", c.ClientIP()) - }) - router.Run() -} -``` - -**Notice:** If you are using a CDN service, you can set the `Engine.TrustedPlatform` -to skip TrustedProxies check, it has a higher priority than TrustedProxies. -Look at the example below: -```go -import ( - "fmt" - - "github.com/gin-gonic/gin" -) - -func main() { - - router := gin.Default() - // Use predefined header gin.PlatformXXX - router.TrustedPlatform = gin.PlatformGoogleAppEngine - // Or set your own trusted request header for another trusted proxy service - // Don't set it to any suspect request header, it's unsafe - router.TrustedPlatform = "X-CDN-IP" - - router.GET("/", func(c *gin.Context) { - // If you set TrustedPlatform, ClientIP() will resolve the - // corresponding header and return IP directly - fmt.Printf("ClientIP: %s\n", c.ClientIP()) - }) - router.Run() -} -``` - -## Testing - -The `net/http/httptest` package is preferable way for HTTP testing. - -```go -package main - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func setupRouter() *gin.Engine { - r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - return r -} - -func main() { - r := setupRouter() - r.Run(":8080") -} -``` - -Test for code example above: - -```go -package main - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPingRoute(t *testing.T) { - router := setupRouter() - - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/ping", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Equal(t, "pong", w.Body.String()) -} -``` - -## Users - -Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. - -* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. -* [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform. -* [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow. -* [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares. -* [picfit](https://github.com/thoas/picfit): An image resizing server written in Go. -* [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes. -* [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system. +Gin is the work of hundreds of contributors. We appreciate your help! +Please see [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the contribution workflow. diff --git a/vendor/github.com/gin-gonic/gin/any.go b/vendor/github.com/gin-gonic/gin/any.go deleted file mode 100644 index 42b1ea4..0000000 --- a/vendor/github.com/gin-gonic/gin/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gin - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/binding/any.go b/vendor/github.com/gin-gonic/gin/binding/any.go deleted file mode 100644 index d8251a7..0000000 --- a/vendor/github.com/gin-gonic/gin/binding/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package binding - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding.go b/vendor/github.com/gin-gonic/gin/binding/binding.go index a58924e..4094852 100644 --- a/vendor/github.com/gin-gonic/gin/binding/binding.go +++ b/vendor/github.com/gin-gonic/gin/binding/binding.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go b/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go index 7f6a904..93ad8ba 100644 --- a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go +++ b/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build nomsgpack -// +build nomsgpack package binding diff --git a/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/vendor/github.com/gin-gonic/gin/binding/default_validator.go index c03afe7..e216b85 100644 --- a/vendor/github.com/gin-gonic/gin/binding/default_validator.go +++ b/vendor/github.com/gin-gonic/gin/binding/default_validator.go @@ -43,7 +43,7 @@ func (err SliceValidationError) Error() string { } } -var _ StructValidator = &defaultValidator{} +var _ StructValidator = (*defaultValidator)(nil) // ValidateStruct receives any kind of type, but only performed struct or pointer to struct type. func (v *defaultValidator) ValidateStruct(obj any) error { diff --git a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go index 98cebfe..540bbbb 100644 --- a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go +++ b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go @@ -19,7 +19,7 @@ import ( var ( errUnknownType = errors.New("unknown type") - // ErrConvertMapStringSlice can not covert to map[string][]string + // ErrConvertMapStringSlice can not convert to map[string][]string ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings") // ErrConvertToMapString can not convert to map[string]string diff --git a/vendor/github.com/gin-gonic/gin/binding/json.go b/vendor/github.com/gin-gonic/gin/binding/json.go index 36eb27a..e21c2ee 100644 --- a/vendor/github.com/gin-gonic/gin/binding/json.go +++ b/vendor/github.com/gin-gonic/gin/binding/json.go @@ -15,7 +15,7 @@ import ( // EnableDecoderUseNumber is used to call the UseNumber method on the JSON // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an -// interface{} as a Number instead of as a float64. +// any as a Number instead of as a float64. var EnableDecoderUseNumber = false // EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method diff --git a/vendor/github.com/gin-gonic/gin/binding/msgpack.go b/vendor/github.com/gin-gonic/gin/binding/msgpack.go index d1f035e..22de9b5 100644 --- a/vendor/github.com/gin-gonic/gin/binding/msgpack.go +++ b/vendor/github.com/gin-gonic/gin/binding/msgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/vendor/github.com/gin-gonic/gin/binding/protobuf.go b/vendor/github.com/gin-gonic/gin/binding/protobuf.go index 44f2fdb..57721fc 100644 --- a/vendor/github.com/gin-gonic/gin/binding/protobuf.go +++ b/vendor/github.com/gin-gonic/gin/binding/protobuf.go @@ -6,7 +6,7 @@ package binding import ( "errors" - "io/ioutil" + "io" "net/http" "google.golang.org/protobuf/proto" @@ -19,7 +19,7 @@ func (protobufBinding) Name() string { } func (b protobufBinding) Bind(req *http.Request, obj any) error { - buf, err := ioutil.ReadAll(req.Body) + buf, err := io.ReadAll(req.Body) if err != nil { return err } diff --git a/vendor/github.com/gin-gonic/gin/binding/toml.go b/vendor/github.com/gin-gonic/gin/binding/toml.go index a6b8a90..a66b93a 100644 --- a/vendor/github.com/gin-gonic/gin/binding/toml.go +++ b/vendor/github.com/gin-gonic/gin/binding/toml.go @@ -18,14 +18,6 @@ func (tomlBinding) Name() string { return "toml" } -func decodeToml(r io.Reader, obj any) error { - decoder := toml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return decoder.Decode(obj) -} - func (tomlBinding) Bind(req *http.Request, obj any) error { return decodeToml(req.Body, obj) } @@ -33,3 +25,11 @@ func (tomlBinding) Bind(req *http.Request, obj any) error { func (tomlBinding) BindBody(body []byte, obj any) error { return decodeToml(bytes.NewReader(body), obj) } + +func decodeToml(r io.Reader, obj any) error { + decoder := toml.NewDecoder(r) + if err := decoder.Decode(obj); err != nil { + return err + } + return decoder.Decode(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/binding/yaml.go b/vendor/github.com/gin-gonic/gin/binding/yaml.go index b0d36a3..2535f8c 100644 --- a/vendor/github.com/gin-gonic/gin/binding/yaml.go +++ b/vendor/github.com/gin-gonic/gin/binding/yaml.go @@ -9,7 +9,7 @@ import ( "io" "net/http" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) type yamlBinding struct{} diff --git a/vendor/github.com/gin-gonic/gin/codecov.yml b/vendor/github.com/gin-gonic/gin/codecov.yml deleted file mode 100644 index c9c9a52..0000000 --- a/vendor/github.com/gin-gonic/gin/codecov.yml +++ /dev/null @@ -1,5 +0,0 @@ -coverage: - notify: - gitter: - default: - url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165 diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go index b1ad95e..420ff16 100644 --- a/vendor/github.com/gin-gonic/gin/context.go +++ b/vendor/github.com/gin-gonic/gin/context.go @@ -7,7 +7,6 @@ package gin import ( "errors" "io" - "io/ioutil" "log" "math" "mime/multipart" @@ -15,6 +14,7 @@ import ( "net/http" "net/url" "os" + "path/filepath" "strings" "sync" "time" @@ -153,9 +153,10 @@ func (c *Context) Handler() HandlerFunc { // FullPath returns a matched route full path. For not found routes // returns an empty string. -// router.GET("/user/:id", func(c *gin.Context) { -// c.FullPath() == "/user/:id" // true -// }) +// +// router.GET("/user/:id", func(c *gin.Context) { +// c.FullPath() == "/user/:id" // true +// }) func (c *Context) FullPath() string { return c.fullPath } @@ -247,20 +248,20 @@ func (c *Context) Error(err error) *Error { // It also lazy initializes c.Keys if it was not used previously. func (c *Context) Set(key string, value any) { c.mu.Lock() + defer c.mu.Unlock() if c.Keys == nil { c.Keys = make(map[string]any) } c.Keys[key] = value - c.mu.Unlock() } // Get returns the value for the given key, ie: (value, true). // If the value does not exist it returns (nil, false) func (c *Context) Get(key string) (value any, exists bool) { c.mu.RLock() + defer c.mu.RUnlock() value, exists = c.Keys[key] - c.mu.RUnlock() return } @@ -382,10 +383,13 @@ func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) // Param returns the value of the URL param. // It is a shortcut for c.Params.ByName(key) -// router.GET("/user/:id", func(c *gin.Context) { -// // a GET request to /user/john -// id := c.Param("id") // id == "john" -// }) +// +// router.GET("/user/:id", func(c *gin.Context) { +// // a GET request to /user/john +// id := c.Param("id") // id == "/john" +// // a GET request to /user/john/ +// id := c.Param("id") // id == "/john/" +// }) func (c *Context) Param(key string) string { return c.Params.ByName(key) } @@ -402,11 +406,12 @@ func (c *Context) AddParam(key, value string) { // Query returns the keyed url query value if it exists, // otherwise it returns an empty string `("")`. // It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /path?id=1234&name=Manu&value= -// c.Query("id") == "1234" -// c.Query("name") == "Manu" -// c.Query("value") == "" -// c.Query("wtf") == "" +// +// GET /path?id=1234&name=Manu&value= +// c.Query("id") == "1234" +// c.Query("name") == "Manu" +// c.Query("value") == "" +// c.Query("wtf") == "" func (c *Context) Query(key string) (value string) { value, _ = c.GetQuery(key) return @@ -415,10 +420,11 @@ func (c *Context) Query(key string) (value string) { // DefaultQuery returns the keyed url query value if it exists, // otherwise it returns the specified defaultValue string. // See: Query() and GetQuery() for further information. -// GET /?name=Manu&lastname= -// c.DefaultQuery("name", "unknown") == "Manu" -// c.DefaultQuery("id", "none") == "none" -// c.DefaultQuery("lastname", "none") == "" +// +// GET /?name=Manu&lastname= +// c.DefaultQuery("name", "unknown") == "Manu" +// c.DefaultQuery("id", "none") == "none" +// c.DefaultQuery("lastname", "none") == "" func (c *Context) DefaultQuery(key, defaultValue string) string { if value, ok := c.GetQuery(key); ok { return value @@ -430,10 +436,11 @@ func (c *Context) DefaultQuery(key, defaultValue string) string { // if it exists `(value, true)` (even when the value is an empty string), // otherwise it returns `("", false)`. // It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /?name=Manu&lastname= -// ("Manu", true) == c.GetQuery("name") -// ("", false) == c.GetQuery("id") -// ("", true) == c.GetQuery("lastname") +// +// GET /?name=Manu&lastname= +// ("Manu", true) == c.GetQuery("name") +// ("", false) == c.GetQuery("id") +// ("", true) == c.GetQuery("lastname") func (c *Context) GetQuery(key string) (string, bool) { if values, ok := c.GetQueryArray(key); ok { return values[0], ok @@ -500,9 +507,10 @@ func (c *Context) DefaultPostForm(key, defaultValue string) string { // form or multipart form when it exists `(value, true)` (even when the value is an empty string), // otherwise it returns ("", false). // For example, during a PATCH request to update the user's email: -// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" -// email= --> ("", true) := GetPostForm("email") // set email to "" -// --> ("", false) := GetPostForm("email") // do nothing with email +// +// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" +// email= --> ("", true) := GetPostForm("email") // set email to "" +// --> ("", false) := GetPostForm("email") // do nothing with email func (c *Context) GetPostForm(key string) (string, bool) { if values, ok := c.GetPostFormArray(key); ok { return values[0], ok @@ -551,7 +559,7 @@ func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { return c.get(c.formCache, key) } -// get is an internal method and returns a map which satisfy conditions. +// get is an internal method and returns a map which satisfies conditions. func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { dicts := make(map[string]string) exist := false @@ -595,6 +603,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error } defer src.Close() + if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil { + return err + } + out, err := os.Create(dst) if err != nil { return err @@ -607,8 +619,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error // Bind checks the Method and Content-Type to select a binding engine automatically, // Depending on the "Content-Type" header different bindings are used, for example: -// "application/json" --> JSON binding -// "application/xml" --> XML binding +// +// "application/json" --> JSON binding +// "application/xml" --> XML binding +// // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. // It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. @@ -638,7 +652,7 @@ func (c *Context) BindYAML(obj any) error { } // BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML). -func (c *Context) BindTOML(obj interface{}) error { +func (c *Context) BindTOML(obj any) error { return c.MustBindWith(obj, binding.TOML) } @@ -651,7 +665,7 @@ func (c *Context) BindHeader(obj any) error { // It will abort the request with HTTP 400 if any error occurs. func (c *Context) BindUri(obj any) error { if err := c.ShouldBindUri(obj); err != nil { - c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck + c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck return err } return nil @@ -662,7 +676,7 @@ func (c *Context) BindUri(obj any) error { // See the binding package. func (c *Context) MustBindWith(obj any, b binding.Binding) error { if err := c.ShouldBindWith(obj, b); err != nil { - c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck + c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck return err } return nil @@ -670,8 +684,10 @@ func (c *Context) MustBindWith(obj any, b binding.Binding) error { // ShouldBind checks the Method and Content-Type to select a binding engine automatically, // Depending on the "Content-Type" header different bindings are used, for example: -// "application/json" --> JSON binding -// "application/xml" --> XML binding +// +// "application/json" --> JSON binding +// "application/xml" --> XML binding +// // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. // Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid. @@ -701,7 +717,7 @@ func (c *Context) ShouldBindYAML(obj any) error { } // ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML). -func (c *Context) ShouldBindTOML(obj interface{}) error { +func (c *Context) ShouldBindTOML(obj any) error { return c.ShouldBindWith(obj, binding.TOML) } @@ -738,7 +754,7 @@ func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error } } if body == nil { - body, err = ioutil.ReadAll(c.Request.Body) + body, err = io.ReadAll(c.Request.Body) if err != nil { return err } @@ -748,7 +764,7 @@ func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error } // ClientIP implements one best effort algorithm to return the real client IP. -// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. +// It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. // If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). // If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy, // the remote IP (coming from Request.RemoteAddr) is returned. @@ -857,7 +873,7 @@ func (c *Context) GetHeader(key string) string { // GetRawData returns stream data. func (c *Context) GetRawData() ([]byte, error) { - return ioutil.ReadAll(c.Request.Body) + return io.ReadAll(c.Request.Body) } // SetSameSite with cookie @@ -908,7 +924,9 @@ func (c *Context) Render(code int, r render.Render) { } if err := r.Render(c.Writer); err != nil { - panic(err) + // Pushing error to c.Errors + _ = c.Error(err) + c.Abort() } } @@ -977,7 +995,7 @@ func (c *Context) YAML(code int, obj any) { } // TOML serializes the given struct as TOML into the response body. -func (c *Context) TOML(code int, obj interface{}) { +func (c *Context) TOML(code int, obj any) { c.Render(code, render.TOML{Data: obj}) } @@ -1034,11 +1052,17 @@ func (c *Context) FileFromFS(filepath string, fs http.FileSystem) { http.FileServer(fs).ServeHTTP(c.Writer, c.Request) } +var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") + +func escapeQuotes(s string) string { + return quoteEscaper.Replace(s) +} + // FileAttachment writes the specified file into the body stream in an efficient way // On the client side, the file will typically be downloaded with the given filename func (c *Context) FileAttachment(filepath, filename string) { if isASCII(filename) { - c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`) + c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+escapeQuotes(filename)+`"`) } else { c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename)) } @@ -1112,7 +1136,7 @@ func (c *Context) Negotiate(code int, config Negotiate) { c.TOML(code, data) default: - c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck + c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck } } @@ -1131,7 +1155,7 @@ func (c *Context) NegotiateFormat(offered ...string) string { // According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers, // therefore we can just iterate over the string without casting it into []rune i := 0 - for ; i < len(accepted); i++ { + for ; i < len(accepted) && i < len(offer); i++ { if accepted[i] == '*' || offer[i] == '*' { return offer } @@ -1156,9 +1180,16 @@ func (c *Context) SetAccepted(formats ...string) { /***** GOLANG.ORG/X/NET/CONTEXT *****/ /************************************/ +// hasRequestContext returns whether c.Request has Context and fallback. +func (c *Context) hasRequestContext() bool { + hasFallback := c.engine != nil && c.engine.ContextWithFallback + hasRequestContext := c.Request != nil && c.Request.Context() != nil + return hasFallback && hasRequestContext +} + // Deadline returns that there is no deadline (ok==false) when c.Request has no Context. func (c *Context) Deadline() (deadline time.Time, ok bool) { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { + if !c.hasRequestContext() { return } return c.Request.Context().Deadline() @@ -1166,7 +1197,7 @@ func (c *Context) Deadline() (deadline time.Time, ok bool) { // Done returns nil (chan which will wait forever) when c.Request has no Context. func (c *Context) Done() <-chan struct{} { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { + if !c.hasRequestContext() { return nil } return c.Request.Context().Done() @@ -1174,7 +1205,7 @@ func (c *Context) Done() <-chan struct{} { // Err returns nil when c.Request has no Context. func (c *Context) Err() error { - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { + if !c.hasRequestContext() { return nil } return c.Request.Context().Err() @@ -1195,7 +1226,7 @@ func (c *Context) Value(key any) any { return val } } - if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil { + if !c.hasRequestContext() { return nil } return c.Request.Context().Value(key) diff --git a/vendor/github.com/gin-gonic/gin/context_appengine.go b/vendor/github.com/gin-gonic/gin/context_appengine.go index 931313f..96b339c 100644 --- a/vendor/github.com/gin-gonic/gin/context_appengine.go +++ b/vendor/github.com/gin-gonic/gin/context_appengine.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build appengine -// +build appengine package gin diff --git a/vendor/github.com/gin-gonic/gin/debug.go b/vendor/github.com/gin-gonic/gin/debug.go index 25fd7c8..1fc0caf 100644 --- a/vendor/github.com/gin-gonic/gin/debug.go +++ b/vendor/github.com/gin-gonic/gin/debug.go @@ -12,7 +12,7 @@ import ( "strings" ) -const ginSupportMinGoVer = 14 +const ginSupportMinGoVer = 18 // IsDebugging returns true if the framework is running in debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode. @@ -66,8 +66,8 @@ func getMinVer(v string) (uint64, error) { } func debugPrintWARNINGDefault() { - if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer { - debugPrint(`[WARNING] Now Gin requires Go 1.14+. + if v, e := getMinVer(runtime.Version()); e == nil && v < ginSupportMinGoVer { + debugPrint(`[WARNING] Now Gin requires Go 1.18+. `) } diff --git a/vendor/github.com/gin-gonic/gin/deprecated.go b/vendor/github.com/gin-gonic/gin/deprecated.go index fdad855..9521308 100644 --- a/vendor/github.com/gin-gonic/gin/deprecated.go +++ b/vendor/github.com/gin-gonic/gin/deprecated.go @@ -13,7 +13,7 @@ import ( // BindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) BindWith(obj any, b binding.Binding) error { - log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to + log.Println(`BindWith(\"any, binding.Binding\") error is going to be deprecated, please check issue #662 and either use MustBindWith() if you want HTTP 400 to be automatically returned if any error occur, or use ShouldBindWith() if you need to manage the error.`) diff --git a/vendor/github.com/gin-gonic/gin/errors.go b/vendor/github.com/gin-gonic/gin/errors.go index 2853ce8..06b53c2 100644 --- a/vendor/github.com/gin-gonic/gin/errors.go +++ b/vendor/github.com/gin-gonic/gin/errors.go @@ -39,7 +39,7 @@ type Error struct { type errorMsgs []*Error -var _ error = &Error{} +var _ error = (*Error)(nil) // SetType sets the error's type. func (msg *Error) SetType(flags ErrorType) *Error { @@ -124,10 +124,11 @@ func (a errorMsgs) Last() *Error { // Errors returns an array with all the error messages. // Example: -// c.Error(errors.New("first")) -// c.Error(errors.New("second")) -// c.Error(errors.New("third")) -// c.Errors.Errors() // == []string{"first", "second", "third"} +// +// c.Error(errors.New("first")) +// c.Error(errors.New("second")) +// c.Error(errors.New("third")) +// c.Errors.Errors() // == []string{"first", "second", "third"} func (a errorMsgs) Errors() []string { if len(a) == 0 { return nil diff --git a/vendor/github.com/gin-gonic/gin/fs.go b/vendor/github.com/gin-gonic/gin/fs.go index 6427473..f17d743 100644 --- a/vendor/github.com/gin-gonic/gin/fs.go +++ b/vendor/github.com/gin-gonic/gin/fs.go @@ -39,7 +39,7 @@ func (fs onlyFilesFS) Open(name string) (http.File, error) { } // Readdir overrides the http.File default implementation. -func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { +func (f neuteredReaddirFile) Readdir(_ int) ([]os.FileInfo, error) { // this disables directory listing return nil, nil } diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go index 5513569..ed8b6da 100644 --- a/vendor/github.com/gin-gonic/gin/gin.go +++ b/vendor/github.com/gin-gonic/gin/gin.go @@ -11,6 +11,7 @@ import ( "net/http" "os" "path" + "regexp" "strings" "sync" @@ -40,6 +41,9 @@ var defaultTrustedCIDRs = []*net.IPNet{ }, } +var regSafePrefix = regexp.MustCompile("[^a-zA-Z0-9/-]+") +var regRemoveRepeatedChar = regexp.MustCompile("/{2,}") + // HandlerFunc defines the handler used by gin middleware as return value. type HandlerFunc func(*Context) @@ -166,7 +170,7 @@ type Engine struct { trustedCIDRs []*net.IPNet } -var _ IRouter = &Engine{} +var _ IRouter = (*Engine)(nil) // New returns a new blank Engine instance without any middleware attached. // By default, the configuration is: @@ -511,7 +515,7 @@ func (engine *Engine) RunUnix(file string) (err error) { if engine.isUnsafeTrustedProxies() { debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") + "Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.") } listener, err := net.Listen("unix", file) @@ -534,7 +538,7 @@ func (engine *Engine) RunFd(fd int) (err error) { if engine.isUnsafeTrustedProxies() { debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") + "Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.") } f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd)) @@ -555,7 +559,7 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) { if engine.isUnsafeTrustedProxies() { debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + - "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") + "Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.") } err = http.Serve(listener, engine.Handler()) @@ -668,6 +672,9 @@ func redirectTrailingSlash(c *Context) { req := c.Request p := req.URL.Path if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." { + prefix = regSafePrefix.ReplaceAllString(prefix, "") + prefix = regRemoveRepeatedChar.ReplaceAllString(prefix, "/") + p = prefix + "/" + req.URL.Path } req.URL.Path = p + "/" diff --git a/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go b/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.19.go similarity index 96% rename from vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go rename to vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.19.go index 86e4c4d..669c9c9 100644 --- a/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go +++ b/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.19.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. +//go:build !go1.20 + package bytesconv import ( diff --git a/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.20.go b/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.20.go new file mode 100644 index 0000000..5b6040a --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv_1.20.go @@ -0,0 +1,23 @@ +// Copyright 2023 Gin Core Team. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +//go:build go1.20 + +package bytesconv + +import ( + "unsafe" +) + +// StringToBytes converts string to byte slice without a memory allocation. +// For more details, see https://github.com/golang/go/issues/53003#issuecomment-1140276077. +func StringToBytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +// BytesToString converts byte slice to string without a memory allocation. +// For more details, see https://github.com/golang/go/issues/53003#issuecomment-1140276077. +func BytesToString(b []byte) string { + return unsafe.String(unsafe.SliceData(b), len(b)) +} diff --git a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go b/vendor/github.com/gin-gonic/gin/internal/json/go_json.go index 23f7172..47c3559 100644 --- a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go +++ b/vendor/github.com/gin-gonic/gin/internal/json/go_json.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build go_json -// +build go_json package json diff --git a/vendor/github.com/gin-gonic/gin/internal/json/json.go b/vendor/github.com/gin-gonic/gin/internal/json/json.go index a26d7db..c7ee83e 100644 --- a/vendor/github.com/gin-gonic/gin/internal/json/json.go +++ b/vendor/github.com/gin-gonic/gin/internal/json/json.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. -//go:build !jsoniter && !go_json -// +build !jsoniter,!go_json +//go:build !jsoniter && !go_json && !(sonic && avx && (linux || windows || darwin) && amd64) package json diff --git a/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go b/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go index 853b1a9..45ed16b 100644 --- a/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go +++ b/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build jsoniter -// +build jsoniter package json diff --git a/vendor/github.com/gin-gonic/gin/internal/json/sonic.go b/vendor/github.com/gin-gonic/gin/internal/json/sonic.go new file mode 100644 index 0000000..529e16d --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/internal/json/sonic.go @@ -0,0 +1,23 @@ +// Copyright 2022 Gin Core Team. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +//go:build sonic && avx && (linux || windows || darwin) && amd64 + +package json + +import "github.com/bytedance/sonic" + +var ( + json = sonic.ConfigStd + // Marshal is exported by gin/json package. + Marshal = json.Marshal + // Unmarshal is exported by gin/json package. + Unmarshal = json.Unmarshal + // MarshalIndent is exported by gin/json package. + MarshalIndent = json.MarshalIndent + // NewDecoder is exported by gin/json package. + NewDecoder = json.NewDecoder + // NewEncoder is exported by gin/json package. + NewEncoder = json.NewEncoder +) diff --git a/vendor/github.com/gin-gonic/gin/mode.go b/vendor/github.com/gin-gonic/gin/mode.go index 545fdaa..fd26d90 100644 --- a/vendor/github.com/gin-gonic/gin/mode.go +++ b/vendor/github.com/gin-gonic/gin/mode.go @@ -35,8 +35,9 @@ const ( // Note that both Logger and Recovery provides custom ways to configure their // output io.Writer. // To support coloring in Windows use: -// import "github.com/mattn/go-colorable" -// gin.DefaultWriter = colorable.NewColorableStdout() +// +// import "github.com/mattn/go-colorable" +// gin.DefaultWriter = colorable.NewColorableStdout() var DefaultWriter io.Writer = os.Stdout // DefaultErrorWriter is the default io.Writer used by Gin to debug errors diff --git a/vendor/github.com/gin-gonic/gin/path.go b/vendor/github.com/gin-gonic/gin/path.go index d42d6b9..82438c1 100644 --- a/vendor/github.com/gin-gonic/gin/path.go +++ b/vendor/github.com/gin-gonic/gin/path.go @@ -10,12 +10,12 @@ package gin // // The following rules are applied iteratively until no further processing can // be done: -// 1. Replace multiple slashes with a single slash. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path. +// 1. Replace multiple slashes with a single slash. +// 2. Eliminate each . path name element (the current directory). +// 3. Eliminate each inner .. path name element (the parent directory) +// along with the non-.. element that precedes it. +// 4. Eliminate .. elements that begin a rooted path: +// that is, replace "/.." by "/" at the beginning of a path. // // If the result of this process is an empty string, "/" is returned. func cleanPath(p string) string { diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go index abb6451..515f9d2 100644 --- a/vendor/github.com/gin-gonic/gin/recovery.go +++ b/vendor/github.com/gin-gonic/gin/recovery.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net" "net/http" @@ -63,7 +62,9 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { if ne, ok := err.(*net.OpError); ok { var se *os.SyscallError if errors.As(ne, &se) { - if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { + seStr := strings.ToLower(se.Error()) + if strings.Contains(seStr, "broken pipe") || + strings.Contains(seStr, "connection reset by peer") { brokenPipe = true } } @@ -91,7 +92,7 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { } if brokenPipe { // If the connection is dead, we can't write a status to it. - c.Error(err.(error)) // nolint: errcheck + c.Error(err.(error)) //nolint: errcheck c.Abort() } else { handle(c, err) @@ -102,7 +103,7 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { } } -func defaultHandleRecovery(c *Context, err any) { +func defaultHandleRecovery(c *Context, _ any) { c.AbortWithStatus(http.StatusInternalServerError) } @@ -121,7 +122,7 @@ func stack(skip int) []byte { // Print this much at least. If we can't find the source, it won't show. fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) if file != lastFile { - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) if err != nil { continue } @@ -163,7 +164,7 @@ func function(pc uintptr) []byte { if period := bytes.Index(name, dot); period >= 0 { name = name[period+1:] } - name = bytes.Replace(name, centerDot, dot, -1) + name = bytes.ReplaceAll(name, centerDot, dot) return name } diff --git a/vendor/github.com/gin-gonic/gin/render/any.go b/vendor/github.com/gin-gonic/gin/render/any.go deleted file mode 100644 index b19ad45..0000000 --- a/vendor/github.com/gin-gonic/gin/render/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package render - -type any = interface{} diff --git a/vendor/github.com/gin-gonic/gin/render/json.go b/vendor/github.com/gin-gonic/gin/render/json.go index af678e8..fc8dea4 100644 --- a/vendor/github.com/gin-gonic/gin/render/json.go +++ b/vendor/github.com/gin-gonic/gin/render/json.go @@ -53,11 +53,8 @@ var ( ) // Render (JSON) writes data with custom ContentType. -func (r JSON) Render(w http.ResponseWriter) (err error) { - if err = WriteJSON(w, r.Data); err != nil { - panic(err) - } - return +func (r JSON) Render(w http.ResponseWriter) error { + return WriteJSON(w, r.Data) } // WriteContentType (JSON) writes JSON ContentType. diff --git a/vendor/github.com/gin-gonic/gin/render/msgpack.go b/vendor/github.com/gin-gonic/gin/render/msgpack.go index e0f30f7..d1d8e84 100644 --- a/vendor/github.com/gin-gonic/gin/render/msgpack.go +++ b/vendor/github.com/gin-gonic/gin/render/msgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package render diff --git a/vendor/github.com/gin-gonic/gin/render/yaml.go b/vendor/github.com/gin-gonic/gin/render/yaml.go index 4f0ac01..fc927c1 100644 --- a/vendor/github.com/gin-gonic/gin/render/yaml.go +++ b/vendor/github.com/gin-gonic/gin/render/yaml.go @@ -7,7 +7,7 @@ package render import ( "net/http" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // YAML contains the given interface object. diff --git a/vendor/github.com/gin-gonic/gin/response_writer.go b/vendor/github.com/gin-gonic/gin/response_writer.go index 77c7ed8..753a0b0 100644 --- a/vendor/github.com/gin-gonic/gin/response_writer.go +++ b/vendor/github.com/gin-gonic/gin/response_writer.go @@ -49,7 +49,11 @@ type responseWriter struct { status int } -var _ ResponseWriter = &responseWriter{} +var _ ResponseWriter = (*responseWriter)(nil) + +func (w *responseWriter) Unwrap() http.ResponseWriter { + return w.ResponseWriter +} func (w *responseWriter) reset(writer http.ResponseWriter) { w.ResponseWriter = writer @@ -61,6 +65,7 @@ func (w *responseWriter) WriteHeader(code int) { if code > 0 && w.status != code { if w.Written() { debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) + return } w.status = code } diff --git a/vendor/github.com/gin-gonic/gin/routergroup.go b/vendor/github.com/gin-gonic/gin/routergroup.go index 3c082d9..c833fe8 100644 --- a/vendor/github.com/gin-gonic/gin/routergroup.go +++ b/vendor/github.com/gin-gonic/gin/routergroup.go @@ -42,6 +42,7 @@ type IRoutes interface { PUT(string, ...HandlerFunc) IRoutes OPTIONS(string, ...HandlerFunc) IRoutes HEAD(string, ...HandlerFunc) IRoutes + Match([]string, string, ...HandlerFunc) IRoutes StaticFile(string, string) IRoutes StaticFileFS(string, string, http.FileSystem) IRoutes @@ -58,7 +59,7 @@ type RouterGroup struct { root bool } -var _ IRouter = &RouterGroup{} +var _ IRouter = (*RouterGroup)(nil) // Use adds middleware to the group, see example code in GitHub. func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { @@ -106,37 +107,37 @@ func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...Ha return group.handle(httpMethod, relativePath, handlers) } -// POST is a shortcut for router.Handle("POST", path, handle). +// POST is a shortcut for router.Handle("POST", path, handlers). func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodPost, relativePath, handlers) } -// GET is a shortcut for router.Handle("GET", path, handle). +// GET is a shortcut for router.Handle("GET", path, handlers). func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodGet, relativePath, handlers) } -// DELETE is a shortcut for router.Handle("DELETE", path, handle). +// DELETE is a shortcut for router.Handle("DELETE", path, handlers). func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodDelete, relativePath, handlers) } -// PATCH is a shortcut for router.Handle("PATCH", path, handle). +// PATCH is a shortcut for router.Handle("PATCH", path, handlers). func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodPatch, relativePath, handlers) } -// PUT is a shortcut for router.Handle("PUT", path, handle). +// PUT is a shortcut for router.Handle("PUT", path, handlers). func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodPut, relativePath, handlers) } -// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle). +// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handlers). func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodOptions, relativePath, handlers) } -// HEAD is a shortcut for router.Handle("HEAD", path, handle). +// HEAD is a shortcut for router.Handle("HEAD", path, handlers). func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodHead, relativePath, handlers) } @@ -151,6 +152,15 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRou return group.returnObj() } +// Match registers a route that matches the specified methods that you declared. +func (group *RouterGroup) Match(methods []string, relativePath string, handlers ...HandlerFunc) IRoutes { + for _, method := range methods { + group.handle(method, relativePath, handlers) + } + + return group.returnObj() +} + // StaticFile registers a single route in order to serve a single file of the local filesystem. // router.StaticFile("favicon.ico", "./resources/favicon.ico") func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes { @@ -161,7 +171,7 @@ func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes { // StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead.. // router.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false}) -// Gin by default user: gin.Dir() +// Gin by default uses: gin.Dir() func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes { return group.staticFileHandler(relativePath, func(c *Context) { c.FileFromFS(filepath, fs) @@ -182,13 +192,14 @@ func (group *RouterGroup) staticFileHandler(relativePath string, handler Handler // of the Router's NotFound handler. // To use the operating system's file system implementation, // use : -// router.Static("/static", "/var/www") +// +// router.Static("/static", "/var/www") func (group *RouterGroup) Static(relativePath, root string) IRoutes { return group.StaticFS(relativePath, Dir(root, false)) } // StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead. -// Gin by default user: gin.Dir() +// Gin by default uses: gin.Dir() func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes { if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { panic("URL parameters can not be used when serving a static folder") diff --git a/vendor/github.com/gin-gonic/gin/tree.go b/vendor/github.com/gin-gonic/gin/tree.go index 0179aa0..dda8f4f 100644 --- a/vendor/github.com/gin-gonic/gin/tree.go +++ b/vendor/github.com/gin-gonic/gin/tree.go @@ -457,11 +457,11 @@ walk: // Outer loop for walking the tree if !n.wildChild { // If the path at the end of the loop is not equal to '/' and the current node has no child nodes - // the current node needs to roll back to last vaild skippedNode + // the current node needs to roll back to last valid skippedNode if path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] + for length := len(*skippedNodes); length > 0; length-- { + skippedNode := (*skippedNodes)[length-1] + *skippedNodes = (*skippedNodes)[:length-1] if strings.HasSuffix(skippedNode.path, path) { path = skippedNode.path n = skippedNode.node @@ -574,11 +574,11 @@ walk: // Outer loop for walking the tree if path == prefix { // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node - // the current node needs to roll back to last vaild skippedNode + // the current node needs to roll back to last valid skippedNode if n.handlers == nil && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] + for length := len(*skippedNodes); length > 0; length-- { + skippedNode := (*skippedNodes)[length-1] + *skippedNodes = (*skippedNodes)[:length-1] if strings.HasSuffix(skippedNode.path, path) { path = skippedNode.path n = skippedNode.node @@ -633,9 +633,9 @@ walk: // Outer loop for walking the tree // roll back to last valid skippedNode if !value.tsr && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] + for length := len(*skippedNodes); length > 0; length-- { + skippedNode := (*skippedNodes)[length-1] + *skippedNodes = (*skippedNodes)[:length-1] if strings.HasSuffix(skippedNode.path, path) { path = skippedNode.path n = skippedNode.node diff --git a/vendor/github.com/gin-gonic/gin/utils.go b/vendor/github.com/gin-gonic/gin/utils.go index 4021a2a..47106a7 100644 --- a/vendor/github.com/gin-gonic/gin/utils.go +++ b/vendor/github.com/gin-gonic/gin/utils.go @@ -50,7 +50,7 @@ func WrapH(h http.Handler) HandlerFunc { } } -// H is a shortcut for map[string]interface{} +// H is a shortcut for map[string]any type H map[string]any // MarshalXML allows type H to be used with xml.Marshal. diff --git a/vendor/github.com/gin-gonic/gin/version.go b/vendor/github.com/gin-gonic/gin/version.go index 37e27f2..85462e5 100644 --- a/vendor/github.com/gin-gonic/gin/version.go +++ b/vendor/github.com/gin-gonic/gin/version.go @@ -5,4 +5,4 @@ package gin // Version is the current gin framework's version. -const Version = "v1.8.2" +const Version = "v1.9.1" diff --git a/vendor/github.com/go-playground/locales/README.md b/vendor/github.com/go-playground/locales/README.md index 5b0694f..7b6be2c 100644 --- a/vendor/github.com/go-playground/locales/README.md +++ b/vendor/github.com/go-playground/locales/README.md @@ -1,10 +1,8 @@ ## locales -![Project status](https://img.shields.io/badge/version-0.14.0-green.svg) +![Project status](https://img.shields.io/badge/version-0.14.1-green.svg) [![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) [![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) ![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator). diff --git a/vendor/github.com/go-playground/universal-translator/README.md b/vendor/github.com/go-playground/universal-translator/README.md index 46dec6d..d9b6654 100644 --- a/vendor/github.com/go-playground/universal-translator/README.md +++ b/vendor/github.com/go-playground/universal-translator/README.md @@ -1,11 +1,9 @@ ## universal-translator -![Project status](https://img.shields.io/badge/version-0.18.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator) +![Project status](https://img.shields.io/badge/version-0.18.1-green.svg) [![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) [![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator) ![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules diff --git a/vendor/github.com/go-playground/universal-translator/import_export.go b/vendor/github.com/go-playground/universal-translator/import_export.go index 1216f19..87a1b46 100644 --- a/vendor/github.com/go-playground/universal-translator/import_export.go +++ b/vendor/github.com/go-playground/universal-translator/import_export.go @@ -3,7 +3,6 @@ package ut import ( "encoding/json" "fmt" - "io/ioutil" "os" "path/filepath" @@ -41,7 +40,6 @@ const ( func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error { _, err := os.Stat(dirname) - fmt.Println(dirname, err, os.IsNotExist(err)) if err != nil { if !os.IsNotExist(err) { @@ -138,7 +136,7 @@ func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) return err } - err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) + err = os.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) if err != nil { return err } @@ -200,7 +198,7 @@ func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilenam // NOTE: generally used when assets have been embedded into the binary and are already in memory. func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error { - b, err := ioutil.ReadAll(reader) + b, err := io.ReadAll(reader) if err != nil { return err } diff --git a/vendor/github.com/go-playground/validator/v10/.gitignore b/vendor/github.com/go-playground/validator/v10/.gitignore index 6e43fac..6305e52 100644 --- a/vendor/github.com/go-playground/validator/v10/.gitignore +++ b/vendor/github.com/go-playground/validator/v10/.gitignore @@ -26,5 +26,7 @@ _testmain.go *.test *.out *.txt +/**/*.DS_Store cover.html README.html +.idea diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md index 9d0a79e..931b341 100644 --- a/vendor/github.com/go-playground/validator/v10/README.md +++ b/vendor/github.com/go-playground/validator/v10/README.md @@ -1,7 +1,7 @@ Package validator ================= -[![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.11.1-green.svg) +[![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.14.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) @@ -73,8 +73,8 @@ Baked-in Validations | - | - | | eqcsfield | Field Equals Another Field (relative)| | eqfield | Field Equals Another Field | -| fieldcontains | NOT DOCUMENTED IN doc.go | -| fieldexcludes | NOT DOCUMENTED IN doc.go | +| fieldcontains | Check the indicated characters are present in the Field | +| fieldexcludes | Check the indicated characters are not present in the field | | gtcsfield | Field Greater Than Another Relative Field | | gtecsfield | Field Greater Than or Equal To Another Relative Field | | gtefield | Field Greater Than or Equal To Another Field | @@ -114,6 +114,7 @@ Baked-in Validations | unix_addr | Unix domain socket end point Address | | uri | URI String | | url | URL String | +| http_url | HTTP URL String | | url_encoded | URL Encoded | | urn_rfc2141 | Urn RFC 2141 String | @@ -137,7 +138,7 @@ Baked-in Validations | excludesrune | Excludes Rune | | lowercase | Lowercase | | multibyte | Multi-Byte Characters | -| number | NOT DOCUMENTED IN doc.go | +| number | Number | | numeric | Numeric | | printascii | Printable ASCII | | startsnotwith | Starts Not With | @@ -149,11 +150,14 @@ Baked-in Validations | - | - | | base64 | Base64 String | | base64url | Base64URL String | +| base64rawurl | Base64RawURL String | | bic | Business Identifier Code (ISO 9362) | | bcp47_language_tag | Language tag (BCP 47) | | btc_addr | Bitcoin Address | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | credit_card | Credit Card Number | +| mongodb | MongoDB ObjectID | +| cron | Cron | | datetime | Datetime | | e164 | e164 formatted phone number | | email | E-mail String @@ -176,6 +180,7 @@ Baked-in Validations | jwt | JSON Web Token (JWT) | | latitude | Latitude | | longitude | Longitude | +| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) | | postcode_iso3166_alpha2 | Postcode | | postcode_iso3166_alpha2_field | Postcode | | rgb | RGB String | @@ -202,22 +207,28 @@ Baked-in Validations | tiger192 | TIGER192 hash | | semver | Semantic Versioning 2.0.0 | | ulid | Universally Unique Lexicographically Sortable Identifier ULID | +| cve | Common Vulnerabilities and Exposures Identifier (CVE id) | ### Comparisons: | Tag | Description | | - | - | | eq | Equals | +| eq_ignore_case | Equals ignoring case | | gt | Greater than| | gte | Greater than or equal | | lt | Less Than | | lte | Less Than or Equal | | ne | Not Equal | +| ne_ignore_case | Not Equal ignoring case | ### Other: | Tag | Description | | - | - | -| dir | Directory | -| file | File path | +| dir | Existing Directory | +| dirpath | Directory Path | +| file | Existing File | +| filepath | File Path | +| image | Image | | isdefault | Is Default | | len | Length | | max | Maximum | diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go index c9b1db4..8e6b169 100644 --- a/vendor/github.com/go-playground/validator/v10/baked_in.go +++ b/vendor/github.com/go-playground/validator/v10/baked_in.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "io/fs" "net" "net/url" "os" @@ -14,13 +15,15 @@ import ( "strconv" "strings" "sync" + "syscall" "time" "unicode/utf8" "golang.org/x/crypto/sha3" "golang.org/x/text/language" - urn "github.com/leodido/go-urn" + "github.com/gabriel-vasile/mimetype" + "github.com/leodido/go-urn" ) // Func accepts a FieldLevel interface for all validation needs. The return @@ -31,7 +34,7 @@ type Func func(fl FieldLevel) bool // validation needs. The return value should be true when validation succeeds. type FuncCtx func(ctx context.Context, fl FieldLevel) bool -// wrapFunc wraps noramal Func makes it compatible with FuncCtx +// wrapFunc wraps normal Func makes it compatible with FuncCtx func wrapFunc(fn Func) FuncCtx { if fn == nil { return nil // be sure not to wrap a bad function. @@ -71,6 +74,7 @@ var ( "required": hasValue, "required_if": requiredIf, "required_unless": requiredUnless, + "skip_unless": skipUnless, "required_with": requiredWith, "required_with_all": requiredWithAll, "required_without": requiredWithout, @@ -86,7 +90,9 @@ var ( "min": hasMinOf, "max": hasMaxOf, "eq": isEq, + "eq_ignore_case": isEqIgnoreCase, "ne": isNe, + "ne_ignore_case": isNeIgnoreCase, "lt": isLt, "lte": isLte, "gt": isGt, @@ -121,11 +127,14 @@ var ( "e164": isE164, "email": isEmail, "url": isURL, + "http_url": isHttpURL, "uri": isURI, "urn_rfc2141": isUrnRFC2141, // RFC 2141 "file": isFile, + "filepath": isFilePath, "base64": isBase64, "base64url": isBase64URL, + "base64rawurl": isBase64RawURL, "contains": contains, "containsany": containsAny, "containsrune": containsRune, @@ -136,10 +145,12 @@ var ( "endswith": endsWith, "startsnotwith": startsNotWith, "endsnotwith": endsNotWith, + "image": isImage, "isbn": isISBN, "isbn10": isISBN10, "isbn13": isISBN13, "eth_addr": isEthereumAddress, + "eth_addr_checksum": isEthereumAddressChecksum, "btc_addr": isBitcoinAddress, "btc_addr_bech32": isBitcoinBech32Address, "uuid": isUUID, @@ -194,6 +205,7 @@ var ( "html_encoded": isHTMLEncoded, "url_encoded": isURLEncoded, "dir": isDir, + "dirpath": isDirPath, "json": isJSON, "jwt": isJWT, "hostname_port": isHostnamePort, @@ -214,6 +226,10 @@ var ( "semver": isSemverFormat, "dns_rfc1035_label": isDnsRFC1035LabelFormat, "credit_card": isCreditCard, + "cve": isCveFormat, + "luhn_checksum": hasLuhnChecksum, + "mongodb": isMongoDB, + "cron": isCron, } ) @@ -307,18 +323,42 @@ func isUnique(fl FieldLevel) bool { } m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) + var fieldlen int for i := 0; i < field.Len(); i++ { - m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) + key := reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)) + if key.IsValid() { + fieldlen++ + m.SetMapIndex(key, v) + } } - return field.Len() == m.Len() + return fieldlen == m.Len() case reflect.Map: - m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) + var m reflect.Value + if field.Type().Elem().Kind() == reflect.Ptr { + m = reflect.MakeMap(reflect.MapOf(field.Type().Elem().Elem(), v.Type())) + } else { + m = reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) + } for _, k := range field.MapKeys() { - m.SetMapIndex(field.MapIndex(k), v) + m.SetMapIndex(reflect.Indirect(field.MapIndex(k)), v) } + return field.Len() == m.Len() default: + if parent := fl.Parent(); parent.Kind() == reflect.Struct { + uniqueField := parent.FieldByName(param) + if uniqueField == reflect.ValueOf(nil) { + panic(fmt.Sprintf("Bad field name provided %s", param)) + } + + if uniqueField.Kind() != field.Kind() { + panic(fmt.Sprintf("Bad field type %T:%T", field.Interface(), uniqueField.Interface())) + } + + return field.Interface() != uniqueField.Interface() + } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) } } @@ -613,14 +653,16 @@ func isISBN10(fl FieldLevel) bool { func isEthereumAddress(fl FieldLevel) bool { address := fl.Field().String() + return ethAddressRegex.MatchString(address) +} + +// isEthereumAddressChecksum is the validation function for validating if the field's value is a valid checksumed Ethereum address. +func isEthereumAddressChecksum(fl FieldLevel) bool { + address := fl.Field().String() + if !ethAddressRegex.MatchString(address) { return false } - - if ethAddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { - return true - } - // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md address = address[2:] // Skip "0x" prefix. h := sha3.NewLegacyKeccak256() @@ -889,6 +931,12 @@ func isNe(fl FieldLevel) bool { return !isEq(fl) } +// isNeIgnoreCase is the validation function for validating that the field's string value does not equal the +// provided param value. The comparison is case-insensitive +func isNeIgnoreCase(fl FieldLevel) bool { + return !isEqIgnoreCase(fl) +} + // isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. func isLteCrossStructField(fl FieldLevel) bool { field := fl.Field() @@ -1260,6 +1308,22 @@ func isEq(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isEqIgnoreCase is the validation function for validating if the current field's string value is +// equal to the param's value. +// The comparison is case-insensitive. +func isEqIgnoreCase(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + switch field.Kind() { + + case reflect.String: + return strings.EqualFold(field.String(), param) + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + // isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 // example: `postcode_iso3166_alpha2=US` func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { @@ -1311,6 +1375,11 @@ func isBase64URL(fl FieldLevel) bool { return base64URLRegex.MatchString(fl.Field().String()) } +// isBase64RawURL is the validation function for validating if the current field's value is a valid base64 URL safe string without '=' padding. +func isBase64RawURL(fl FieldLevel) bool { + return base64RawURLRegex.MatchString(fl.Field().String()) +} + // isURI is the validation function for validating if the current field's value is a valid URI. func isURI(fl FieldLevel) bool { field := fl.Field() @@ -1370,6 +1439,23 @@ func isURL(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isHttpURL is the validation function for validating if the current field's value is a valid HTTP(s) URL. +func isHttpURL(fl FieldLevel) bool { + if !isURL(fl) { + return false + } + + field := fl.Field() + switch field.Kind() { + case reflect.String: + + s := strings.ToLower(field.String()) + return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + // isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. func isUrnRFC2141(fl FieldLevel) bool { field := fl.Field() @@ -1387,7 +1473,7 @@ func isUrnRFC2141(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } -// isFile is the validation function for validating if the current field's value is a valid file path. +// isFile is the validation function for validating if the current field's value is a valid existing file path. func isFile(fl FieldLevel) bool { field := fl.Field() @@ -1404,6 +1490,118 @@ func isFile(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isImage is the validation function for validating if the current field's value contains the path to a valid image file +func isImage(fl FieldLevel) bool { + mimetypes := map[string]bool{ + "image/bmp": true, + "image/cis-cod": true, + "image/gif": true, + "image/ief": true, + "image/jpeg": true, + "image/jp2": true, + "image/jpx": true, + "image/jpm": true, + "image/pipeg": true, + "image/png": true, + "image/svg+xml": true, + "image/tiff": true, + "image/webp": true, + "image/x-cmu-raster": true, + "image/x-cmx": true, + "image/x-icon": true, + "image/x-portable-anymap": true, + "image/x-portable-bitmap": true, + "image/x-portable-graymap": true, + "image/x-portable-pixmap": true, + "image/x-rgb": true, + "image/x-xbitmap": true, + "image/x-xpixmap": true, + "image/x-xwindowdump": true, + } + field := fl.Field() + + switch field.Kind() { + case reflect.String: + filePath := field.String() + fileInfo, err := os.Stat(filePath) + + if err != nil { + return false + } + + if fileInfo.IsDir() { + return false + } + + file, err := os.Open(filePath) + if err != nil { + return false + } + defer file.Close() + + mime, err := mimetype.DetectReader(file) + if err != nil { + return false + } + + if _, ok := mimetypes[mime.String()]; ok { + return true + } + } + return false +} + +// isFilePath is the validation function for validating if the current field's value is a valid file path. +func isFilePath(fl FieldLevel) bool { + + var exists bool + var err error + + field := fl.Field() + + // If it exists, it obviously is valid. + // This is done first to avoid code duplication and unnecessary additional logic. + if exists = isFile(fl); exists { + return true + } + + // It does not exist but may still be a valid filepath. + switch field.Kind() { + case reflect.String: + // Every OS allows for whitespace, but none + // let you use a file with no filename (to my knowledge). + // Unless you're dealing with raw inodes, but I digress. + if strings.TrimSpace(field.String()) == "" { + return false + } + // We make sure it isn't a directory. + if strings.HasSuffix(field.String(), string(os.PathSeparator)) { + return false + } + if _, err = os.Stat(field.String()); err != nil { + switch t := err.(type) { + case *fs.PathError: + if t.Err == syscall.EINVAL { + // It's definitely an invalid character in the filepath. + return false + } + // It could be a permission error, a does-not-exist error, etc. + // Out-of-scope for this validation, though. + return true + default: + // Something went *seriously* wrong. + /* + Per https://pkg.go.dev/os#Stat: + "If there is an error, it will be of type *PathError." + */ + panic(err) + } + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + // isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. func isE164(fl FieldLevel) bool { return e164Regex.MatchString(fl.Field().String()) @@ -1514,7 +1712,7 @@ func hasValue(fl FieldLevel) bool { } } -// requireCheckField is a func for check field kind +// requireCheckFieldKind is a func for check field kind func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool { field := fl.Field() kind := field.Kind() @@ -1539,7 +1737,9 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo } // requireCheckFieldValue is a func for check field value -func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { +func requireCheckFieldValue( + fl FieldLevel, param string, value string, defaultNotFoundValue bool, +) bool { field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) if !found { return defaultNotFoundValue @@ -1592,10 +1792,10 @@ func excludedIf(fl FieldLevel) bool { for i := 0; i < len(params); i += 2 { if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return false + return true } } - return true + return !hasValue(fl) } // requiredUnless is the validation function @@ -1614,6 +1814,21 @@ func requiredUnless(fl FieldLevel) bool { return hasValue(fl) } +// skipUnless is the validation function +// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. +func skipUnless(fl FieldLevel) bool { + params := parseOneOfParam2(fl.Param()) + if len(params)%2 != 0 { + panic(fmt.Sprintf("Bad param number for skip_unless %s", fl.FieldName())) + } + for i := 0; i < len(params); i += 2 { + if !requireCheckFieldValue(fl, params[i], params[i+1], false) { + return true + } + } + return hasValue(fl) +} + // excludedUnless is the validation function // The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field. func excludedUnless(fl FieldLevel) bool { @@ -1623,10 +1838,10 @@ func excludedUnless(fl FieldLevel) bool { } for i := 0; i < len(params); i += 2 { if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true + return !hasValue(fl) } } - return !hasValue(fl) + return true } // excludedWith is the validation function @@ -2275,7 +2490,7 @@ func isFQDN(fl FieldLevel) bool { return fqdnRegexRFC1123.MatchString(val) } -// isDir is the validation function for validating if the current field's value is a valid directory. +// isDir is the validation function for validating if the current field's value is a valid existing directory. func isDir(fl FieldLevel) bool { field := fl.Field() @@ -2291,6 +2506,64 @@ func isDir(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isDirPath is the validation function for validating if the current field's value is a valid directory. +func isDirPath(fl FieldLevel) bool { + + var exists bool + var err error + + field := fl.Field() + + // If it exists, it obviously is valid. + // This is done first to avoid code duplication and unnecessary additional logic. + if exists = isDir(fl); exists { + return true + } + + // It does not exist but may still be a valid path. + switch field.Kind() { + case reflect.String: + // Every OS allows for whitespace, but none + // let you use a dir with no name (to my knowledge). + // Unless you're dealing with raw inodes, but I digress. + if strings.TrimSpace(field.String()) == "" { + return false + } + if _, err = os.Stat(field.String()); err != nil { + switch t := err.(type) { + case *fs.PathError: + if t.Err == syscall.EINVAL { + // It's definitely an invalid character in the path. + return false + } + // It could be a permission error, a does-not-exist error, etc. + // Out-of-scope for this validation, though. + // Lastly, we make sure it is a directory. + if strings.HasSuffix(field.String(), string(os.PathSeparator)) { + return true + } else { + return false + } + default: + // Something went *seriously* wrong. + /* + Per https://pkg.go.dev/os#Stat: + "If there is an error, it will be of type *PathError." + */ + panic(err) + } + } + // We repeat the check here to make sure it is an explicit directory in case the above os.Stat didn't trigger an error. + if strings.HasSuffix(field.String(), string(os.PathSeparator)) { + return true + } else { + return false + } + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + // isJSON is the validation function for validating if the current field's value is a valid json string. func isJSON(fl FieldLevel) bool { field := fl.Field() @@ -2316,7 +2589,9 @@ func isHostnamePort(fl FieldLevel) bool { return false } // Port must be a iny <= 65535. - if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 { + if portNum, err := strconv.ParseInt( + port, 10, 32, + ); err != nil || portNum > 65535 || portNum < 1 { return false } @@ -2397,13 +2672,13 @@ func isIso3166Alpha2(fl FieldLevel) bool { return iso3166_1_alpha2[val] } -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. +// isIso3166Alpha3 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. func isIso3166Alpha3(fl FieldLevel) bool { val := fl.Field().String() return iso3166_1_alpha3[val] } -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. +// isIso3166AlphaNumeric is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. func isIso3166AlphaNumeric(fl FieldLevel) bool { field := fl.Field() @@ -2479,6 +2754,13 @@ func isSemverFormat(fl FieldLevel) bool { return semverRegex.MatchString(semverString) } +// isCveFormat is the validation function for validating if the current field's value is a valid cve id, defined in CVE mitre org +func isCveFormat(fl FieldLevel) bool { + cveString := fl.Field().String() + + return cveRegex.MatchString(cveString) +} + // isDnsRFC1035LabelFormat is the validation function // for validating if the current field's value is // a valid dns RFC 1035 label, defined in RFC 1035. @@ -2487,6 +2769,35 @@ func isDnsRFC1035LabelFormat(fl FieldLevel) bool { return dnsRegexRFC1035Label.MatchString(val) } +// digitsHaveLuhnChecksum returns true if and only if the last element of the given digits slice is the Luhn checksum of the previous elements +func digitsHaveLuhnChecksum(digits []string) bool { + size := len(digits) + sum := 0 + for i, digit := range digits { + value, err := strconv.Atoi(digit) + if err != nil { + return false + } + if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 { + v := value * 2 + if v >= 10 { + sum += 1 + (v % 10) + } else { + sum += v + } + } else { + sum += value + } + } + return (sum % 10) == 0 +} + +// isMongoDB is the validation function for validating if the current field's value is valid mongoDB objectID +func isMongoDB(fl FieldLevel) bool { + val := fl.Field().String() + return mongodbRegex.MatchString(val) +} + // isCreditCard is the validation function for validating if the current field's value is a valid credit card number func isCreditCard(fl FieldLevel) bool { val := fl.Field().String() @@ -2505,22 +2816,33 @@ func isCreditCard(fl FieldLevel) bool { return false } - sum := 0 - for i, digit := range ccDigits { - value, err := strconv.Atoi(digit) - if err != nil { - return false - } - if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 { - v := value * 2 - if v >= 10 { - sum += 1 + (v % 10) - } else { - sum += v - } - } else { - sum += value - } + return digitsHaveLuhnChecksum(ccDigits) +} + +// hasLuhnChecksum is the validation for validating if the current field's value has a valid Luhn checksum +func hasLuhnChecksum(fl FieldLevel) bool { + field := fl.Field() + var str string // convert to a string which will then be split into single digits; easier and more readable than shifting/extracting single digits from a number + switch field.Kind() { + case reflect.String: + str = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + str = strconv.FormatInt(field.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + str = strconv.FormatUint(field.Uint(), 10) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) } - return (sum % 10) == 0 + size := len(str) + if size < 2 { // there has to be at least one digit that carries a meaning + the checksum + return false + } + digits := strings.Split(str, "") + return digitsHaveLuhnChecksum(digits) +} + +// isCron is the validation function for validating if the current field's value is a valid cron expression +func isCron(fl FieldLevel) bool { + cronString := fl.Field().String() + return cronRegex.MatchString(cronString) } diff --git a/vendor/github.com/go-playground/validator/v10/cache.go b/vendor/github.com/go-playground/validator/v10/cache.go index 7b84c91..bbfd2a4 100644 --- a/vendor/github.com/go-playground/validator/v10/cache.go +++ b/vendor/github.com/go-playground/validator/v10/cache.go @@ -120,7 +120,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr var fld reflect.StructField var tag string var customName string - + for i := 0; i < numFields; i++ { fld = typ.Field(i) diff --git a/vendor/github.com/go-playground/validator/v10/country_codes.go b/vendor/github.com/go-playground/validator/v10/country_codes.go index 0d9eda0..0119f05 100644 --- a/vendor/github.com/go-playground/validator/v10/country_codes.go +++ b/vendor/github.com/go-playground/validator/v10/country_codes.go @@ -51,7 +51,7 @@ var iso3166_1_alpha2 = map[string]bool{ "TV": true, "UG": true, "UA": true, "AE": true, "GB": true, "US": true, "UM": true, "UY": true, "UZ": true, "VU": true, "VE": true, "VN": true, "VG": true, "VI": true, "WF": true, - "EH": true, "YE": true, "ZM": true, "ZW": true, + "EH": true, "YE": true, "ZM": true, "ZW": true, "XK": true, } var iso3166_1_alpha3 = map[string]bool{ @@ -105,7 +105,7 @@ var iso3166_1_alpha3 = map[string]bool{ "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, - "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, + "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, "UNK": true, } var iso3166_1_alpha_numeric = map[int]bool{ // see: https://www.iso.org/iso-3166-country-codes.html @@ -158,975 +158,993 @@ var iso3166_1_alpha_numeric = map[int]bool{ 800: true, 804: true, 784: true, 826: true, 581: true, 840: true, 858: true, 860: true, 548: true, 862: true, 704: true, 92: true, 850: true, 876: true, 732: true, - 887: true, 894: true, 716: true, 248: true, + 887: true, 894: true, 716: true, 248: true, 153: true, } var iso3166_2 = map[string]bool{ - "AD-02" : true, "AD-03" : true, "AD-04" : true, "AD-05" : true, "AD-06" : true, - "AD-07" : true, "AD-08" : true, "AE-AJ" : true, "AE-AZ" : true, "AE-DU" : true, - "AE-FU" : true, "AE-RK" : true, "AE-SH" : true, "AE-UQ" : true, "AF-BAL" : true, - "AF-BAM" : true, "AF-BDG" : true, "AF-BDS" : true, "AF-BGL" : true, "AF-DAY" : true, - "AF-FRA" : true, "AF-FYB" : true, "AF-GHA" : true, "AF-GHO" : true, "AF-HEL" : true, - "AF-HER" : true, "AF-JOW" : true, "AF-KAB" : true, "AF-KAN" : true, "AF-KAP" : true, - "AF-KDZ" : true, "AF-KHO" : true, "AF-KNR" : true, "AF-LAG" : true, "AF-LOG" : true, - "AF-NAN" : true, "AF-NIM" : true, "AF-NUR" : true, "AF-PAN" : true, "AF-PAR" : true, - "AF-PIA" : true, "AF-PKA" : true, "AF-SAM" : true, "AF-SAR" : true, "AF-TAK" : true, - "AF-URU" : true, "AF-WAR" : true, "AF-ZAB" : true, "AG-03" : true, "AG-04" : true, - "AG-05" : true, "AG-06" : true, "AG-07" : true, "AG-08" : true, "AG-10" : true, - "AG-11" : true, "AL-01" : true, "AL-02" : true, "AL-03" : true, "AL-04" : true, - "AL-05" : true, "AL-06" : true, "AL-07" : true, "AL-08" : true, "AL-09" : true, - "AL-10" : true, "AL-11" : true, "AL-12" : true, "AL-BR" : true, "AL-BU" : true, - "AL-DI" : true, "AL-DL" : true, "AL-DR" : true, "AL-DV" : true, "AL-EL" : true, - "AL-ER" : true, "AL-FR" : true, "AL-GJ" : true, "AL-GR" : true, "AL-HA" : true, - "AL-KA" : true, "AL-KB" : true, "AL-KC" : true, "AL-KO" : true, "AL-KR" : true, - "AL-KU" : true, "AL-LB" : true, "AL-LE" : true, "AL-LU" : true, "AL-MK" : true, - "AL-MM" : true, "AL-MR" : true, "AL-MT" : true, "AL-PG" : true, "AL-PQ" : true, - "AL-PR" : true, "AL-PU" : true, "AL-SH" : true, "AL-SK" : true, "AL-SR" : true, - "AL-TE" : true, "AL-TP" : true, "AL-TR" : true, "AL-VL" : true, "AM-AG" : true, - "AM-AR" : true, "AM-AV" : true, "AM-ER" : true, "AM-GR" : true, "AM-KT" : true, - "AM-LO" : true, "AM-SH" : true, "AM-SU" : true, "AM-TV" : true, "AM-VD" : true, - "AO-BGO" : true, "AO-BGU" : true, "AO-BIE" : true, "AO-CAB" : true, "AO-CCU" : true, - "AO-CNN" : true, "AO-CNO" : true, "AO-CUS" : true, "AO-HUA" : true, "AO-HUI" : true, - "AO-LNO" : true, "AO-LSU" : true, "AO-LUA" : true, "AO-MAL" : true, "AO-MOX" : true, - "AO-NAM" : true, "AO-UIG" : true, "AO-ZAI" : true, "AR-A" : true, "AR-B" : true, - "AR-C" : true, "AR-D" : true, "AR-E" : true, "AR-G" : true, "AR-H" : true, - "AR-J" : true, "AR-K" : true, "AR-L" : true, "AR-M" : true, "AR-N" : true, - "AR-P" : true, "AR-Q" : true, "AR-R" : true, "AR-S" : true, "AR-T" : true, - "AR-U" : true, "AR-V" : true, "AR-W" : true, "AR-X" : true, "AR-Y" : true, - "AR-Z" : true, "AT-1" : true, "AT-2" : true, "AT-3" : true, "AT-4" : true, - "AT-5" : true, "AT-6" : true, "AT-7" : true, "AT-8" : true, "AT-9" : true, - "AU-ACT" : true, "AU-NSW" : true, "AU-NT" : true, "AU-QLD" : true, "AU-SA" : true, - "AU-TAS" : true, "AU-VIC" : true, "AU-WA" : true, "AZ-ABS" : true, "AZ-AGA" : true, - "AZ-AGC" : true, "AZ-AGM" : true, "AZ-AGS" : true, "AZ-AGU" : true, "AZ-AST" : true, - "AZ-BA" : true, "AZ-BAB" : true, "AZ-BAL" : true, "AZ-BAR" : true, "AZ-BEY" : true, - "AZ-BIL" : true, "AZ-CAB" : true, "AZ-CAL" : true, "AZ-CUL" : true, "AZ-DAS" : true, - "AZ-FUZ" : true, "AZ-GA" : true, "AZ-GAD" : true, "AZ-GOR" : true, "AZ-GOY" : true, - "AZ-GYG" : true, "AZ-HAC" : true, "AZ-IMI" : true, "AZ-ISM" : true, "AZ-KAL" : true, - "AZ-KAN" : true, "AZ-KUR" : true, "AZ-LA" : true, "AZ-LAC" : true, "AZ-LAN" : true, - "AZ-LER" : true, "AZ-MAS" : true, "AZ-MI" : true, "AZ-NA" : true, "AZ-NEF" : true, - "AZ-NV" : true, "AZ-NX" : true, "AZ-OGU" : true, "AZ-ORD" : true, "AZ-QAB" : true, - "AZ-QAX" : true, "AZ-QAZ" : true, "AZ-QBA" : true, "AZ-QBI" : true, "AZ-QOB" : true, - "AZ-QUS" : true, "AZ-SA" : true, "AZ-SAB" : true, "AZ-SAD" : true, "AZ-SAH" : true, - "AZ-SAK" : true, "AZ-SAL" : true, "AZ-SAR" : true, "AZ-SAT" : true, "AZ-SBN" : true, - "AZ-SIY" : true, "AZ-SKR" : true, "AZ-SM" : true, "AZ-SMI" : true, "AZ-SMX" : true, - "AZ-SR" : true, "AZ-SUS" : true, "AZ-TAR" : true, "AZ-TOV" : true, "AZ-UCA" : true, - "AZ-XA" : true, "AZ-XAC" : true, "AZ-XCI" : true, "AZ-XIZ" : true, "AZ-XVD" : true, - "AZ-YAR" : true, "AZ-YE" : true, "AZ-YEV" : true, "AZ-ZAN" : true, "AZ-ZAQ" : true, - "AZ-ZAR" : true, "BA-01" : true, "BA-02" : true, "BA-03" : true, "BA-04" : true, - "BA-05" : true, "BA-06" : true, "BA-07" : true, "BA-08" : true, "BA-09" : true, - "BA-10" : true, "BA-BIH" : true, "BA-BRC" : true, "BA-SRP" : true, "BB-01" : true, - "BB-02" : true, "BB-03" : true, "BB-04" : true, "BB-05" : true, "BB-06" : true, - "BB-07" : true, "BB-08" : true, "BB-09" : true, "BB-10" : true, "BB-11" : true, - "BD-01" : true, "BD-02" : true, "BD-03" : true, "BD-04" : true, "BD-05" : true, - "BD-06" : true, "BD-07" : true, "BD-08" : true, "BD-09" : true, "BD-10" : true, - "BD-11" : true, "BD-12" : true, "BD-13" : true, "BD-14" : true, "BD-15" : true, - "BD-16" : true, "BD-17" : true, "BD-18" : true, "BD-19" : true, "BD-20" : true, - "BD-21" : true, "BD-22" : true, "BD-23" : true, "BD-24" : true, "BD-25" : true, - "BD-26" : true, "BD-27" : true, "BD-28" : true, "BD-29" : true, "BD-30" : true, - "BD-31" : true, "BD-32" : true, "BD-33" : true, "BD-34" : true, "BD-35" : true, - "BD-36" : true, "BD-37" : true, "BD-38" : true, "BD-39" : true, "BD-40" : true, - "BD-41" : true, "BD-42" : true, "BD-43" : true, "BD-44" : true, "BD-45" : true, - "BD-46" : true, "BD-47" : true, "BD-48" : true, "BD-49" : true, "BD-50" : true, - "BD-51" : true, "BD-52" : true, "BD-53" : true, "BD-54" : true, "BD-55" : true, - "BD-56" : true, "BD-57" : true, "BD-58" : true, "BD-59" : true, "BD-60" : true, - "BD-61" : true, "BD-62" : true, "BD-63" : true, "BD-64" : true, "BD-A" : true, - "BD-B" : true, "BD-C" : true, "BD-D" : true, "BD-E" : true, "BD-F" : true, - "BD-G" : true, "BE-BRU" : true, "BE-VAN" : true, "BE-VBR" : true, "BE-VLG" : true, - "BE-VLI" : true, "BE-VOV" : true, "BE-VWV" : true, "BE-WAL" : true, "BE-WBR" : true, - "BE-WHT" : true, "BE-WLG" : true, "BE-WLX" : true, "BE-WNA" : true, "BF-01" : true, - "BF-02" : true, "BF-03" : true, "BF-04" : true, "BF-05" : true, "BF-06" : true, - "BF-07" : true, "BF-08" : true, "BF-09" : true, "BF-10" : true, "BF-11" : true, - "BF-12" : true, "BF-13" : true, "BF-BAL" : true, "BF-BAM" : true, "BF-BAN" : true, - "BF-BAZ" : true, "BF-BGR" : true, "BF-BLG" : true, "BF-BLK" : true, "BF-COM" : true, - "BF-GAN" : true, "BF-GNA" : true, "BF-GOU" : true, "BF-HOU" : true, "BF-IOB" : true, - "BF-KAD" : true, "BF-KEN" : true, "BF-KMD" : true, "BF-KMP" : true, "BF-KOP" : true, - "BF-KOS" : true, "BF-KOT" : true, "BF-KOW" : true, "BF-LER" : true, "BF-LOR" : true, - "BF-MOU" : true, "BF-NAM" : true, "BF-NAO" : true, "BF-NAY" : true, "BF-NOU" : true, - "BF-OUB" : true, "BF-OUD" : true, "BF-PAS" : true, "BF-PON" : true, "BF-SEN" : true, - "BF-SIS" : true, "BF-SMT" : true, "BF-SNG" : true, "BF-SOM" : true, "BF-SOR" : true, - "BF-TAP" : true, "BF-TUI" : true, "BF-YAG" : true, "BF-YAT" : true, "BF-ZIR" : true, - "BF-ZON" : true, "BF-ZOU" : true, "BG-01" : true, "BG-02" : true, "BG-03" : true, - "BG-04" : true, "BG-05" : true, "BG-06" : true, "BG-07" : true, "BG-08" : true, - "BG-09" : true, "BG-10" : true, "BG-11" : true, "BG-12" : true, "BG-13" : true, - "BG-14" : true, "BG-15" : true, "BG-16" : true, "BG-17" : true, "BG-18" : true, - "BG-19" : true, "BG-20" : true, "BG-21" : true, "BG-22" : true, "BG-23" : true, - "BG-24" : true, "BG-25" : true, "BG-26" : true, "BG-27" : true, "BG-28" : true, - "BH-13" : true, "BH-14" : true, "BH-15" : true, "BH-16" : true, "BH-17" : true, - "BI-BB" : true, "BI-BL" : true, "BI-BM" : true, "BI-BR" : true, "BI-CA" : true, - "BI-CI" : true, "BI-GI" : true, "BI-KI" : true, "BI-KR" : true, "BI-KY" : true, - "BI-MA" : true, "BI-MU" : true, "BI-MW" : true, "BI-NG" : true, "BI-RT" : true, - "BI-RY" : true, "BJ-AK" : true, "BJ-AL" : true, "BJ-AQ" : true, "BJ-BO" : true, - "BJ-CO" : true, "BJ-DO" : true, "BJ-KO" : true, "BJ-LI" : true, "BJ-MO" : true, - "BJ-OU" : true, "BJ-PL" : true, "BJ-ZO" : true, "BN-BE" : true, "BN-BM" : true, - "BN-TE" : true, "BN-TU" : true, "BO-B" : true, "BO-C" : true, "BO-H" : true, - "BO-L" : true, "BO-N" : true, "BO-O" : true, "BO-P" : true, "BO-S" : true, - "BO-T" : true, "BQ-BO" : true, "BQ-SA" : true, "BQ-SE" : true, "BR-AC" : true, - "BR-AL" : true, "BR-AM" : true, "BR-AP" : true, "BR-BA" : true, "BR-CE" : true, - "BR-DF" : true, "BR-ES" : true, "BR-FN" : true, "BR-GO" : true, "BR-MA" : true, - "BR-MG" : true, "BR-MS" : true, "BR-MT" : true, "BR-PA" : true, "BR-PB" : true, - "BR-PE" : true, "BR-PI" : true, "BR-PR" : true, "BR-RJ" : true, "BR-RN" : true, - "BR-RO" : true, "BR-RR" : true, "BR-RS" : true, "BR-SC" : true, "BR-SE" : true, - "BR-SP" : true, "BR-TO" : true, "BS-AK" : true, "BS-BI" : true, "BS-BP" : true, - "BS-BY" : true, "BS-CE" : true, "BS-CI" : true, "BS-CK" : true, "BS-CO" : true, - "BS-CS" : true, "BS-EG" : true, "BS-EX" : true, "BS-FP" : true, "BS-GC" : true, - "BS-HI" : true, "BS-HT" : true, "BS-IN" : true, "BS-LI" : true, "BS-MC" : true, - "BS-MG" : true, "BS-MI" : true, "BS-NE" : true, "BS-NO" : true, "BS-NS" : true, - "BS-RC" : true, "BS-RI" : true, "BS-SA" : true, "BS-SE" : true, "BS-SO" : true, - "BS-SS" : true, "BS-SW" : true, "BS-WG" : true, "BT-11" : true, "BT-12" : true, - "BT-13" : true, "BT-14" : true, "BT-15" : true, "BT-21" : true, "BT-22" : true, - "BT-23" : true, "BT-24" : true, "BT-31" : true, "BT-32" : true, "BT-33" : true, - "BT-34" : true, "BT-41" : true, "BT-42" : true, "BT-43" : true, "BT-44" : true, - "BT-45" : true, "BT-GA" : true, "BT-TY" : true, "BW-CE" : true, "BW-GH" : true, - "BW-KG" : true, "BW-KL" : true, "BW-KW" : true, "BW-NE" : true, "BW-NW" : true, - "BW-SE" : true, "BW-SO" : true, "BY-BR" : true, "BY-HM" : true, "BY-HO" : true, - "BY-HR" : true, "BY-MA" : true, "BY-MI" : true, "BY-VI" : true, "BZ-BZ" : true, - "BZ-CY" : true, "BZ-CZL" : true, "BZ-OW" : true, "BZ-SC" : true, "BZ-TOL" : true, - "CA-AB" : true, "CA-BC" : true, "CA-MB" : true, "CA-NB" : true, "CA-NL" : true, - "CA-NS" : true, "CA-NT" : true, "CA-NU" : true, "CA-ON" : true, "CA-PE" : true, - "CA-QC" : true, "CA-SK" : true, "CA-YT" : true, "CD-BC" : true, "CD-BN" : true, - "CD-EQ" : true, "CD-KA" : true, "CD-KE" : true, "CD-KN" : true, "CD-KW" : true, - "CD-MA" : true, "CD-NK" : true, "CD-OR" : true, "CD-SK" : true, "CF-AC" : true, - "CF-BB" : true, "CF-BGF" : true, "CF-BK" : true, "CF-HK" : true, "CF-HM" : true, - "CF-HS" : true, "CF-KB" : true, "CF-KG" : true, "CF-LB" : true, "CF-MB" : true, - "CF-MP" : true, "CF-NM" : true, "CF-OP" : true, "CF-SE" : true, "CF-UK" : true, - "CF-VK" : true, "CG-11" : true, "CG-12" : true, "CG-13" : true, "CG-14" : true, - "CG-15" : true, "CG-2" : true, "CG-5" : true, "CG-7" : true, "CG-8" : true, - "CG-9" : true, "CG-BZV" : true, "CH-AG" : true, "CH-AI" : true, "CH-AR" : true, - "CH-BE" : true, "CH-BL" : true, "CH-BS" : true, "CH-FR" : true, "CH-GE" : true, - "CH-GL" : true, "CH-GR" : true, "CH-JU" : true, "CH-LU" : true, "CH-NE" : true, - "CH-NW" : true, "CH-OW" : true, "CH-SG" : true, "CH-SH" : true, "CH-SO" : true, - "CH-SZ" : true, "CH-TG" : true, "CH-TI" : true, "CH-UR" : true, "CH-VD" : true, - "CH-VS" : true, "CH-ZG" : true, "CH-ZH" : true, "CI-01" : true, "CI-02" : true, - "CI-03" : true, "CI-04" : true, "CI-05" : true, "CI-06" : true, "CI-07" : true, - "CI-08" : true, "CI-09" : true, "CI-10" : true, "CI-11" : true, "CI-12" : true, - "CI-13" : true, "CI-14" : true, "CI-15" : true, "CI-16" : true, "CI-17" : true, - "CI-18" : true, "CI-19" : true, "CL-AI" : true, "CL-AN" : true, "CL-AP" : true, - "CL-AR" : true, "CL-AT" : true, "CL-BI" : true, "CL-CO" : true, "CL-LI" : true, - "CL-LL" : true, "CL-LR" : true, "CL-MA" : true, "CL-ML" : true, "CL-RM" : true, - "CL-TA" : true, "CL-VS" : true, "CM-AD" : true, "CM-CE" : true, "CM-EN" : true, - "CM-ES" : true, "CM-LT" : true, "CM-NO" : true, "CM-NW" : true, "CM-OU" : true, - "CM-SU" : true, "CM-SW" : true, "CN-11" : true, "CN-12" : true, "CN-13" : true, - "CN-14" : true, "CN-15" : true, "CN-21" : true, "CN-22" : true, "CN-23" : true, - "CN-31" : true, "CN-32" : true, "CN-33" : true, "CN-34" : true, "CN-35" : true, - "CN-36" : true, "CN-37" : true, "CN-41" : true, "CN-42" : true, "CN-43" : true, - "CN-44" : true, "CN-45" : true, "CN-46" : true, "CN-50" : true, "CN-51" : true, - "CN-52" : true, "CN-53" : true, "CN-54" : true, "CN-61" : true, "CN-62" : true, - "CN-63" : true, "CN-64" : true, "CN-65" : true, "CN-71" : true, "CN-91" : true, - "CN-92" : true, "CO-AMA" : true, "CO-ANT" : true, "CO-ARA" : true, "CO-ATL" : true, - "CO-BOL" : true, "CO-BOY" : true, "CO-CAL" : true, "CO-CAQ" : true, "CO-CAS" : true, - "CO-CAU" : true, "CO-CES" : true, "CO-CHO" : true, "CO-COR" : true, "CO-CUN" : true, - "CO-DC" : true, "CO-GUA" : true, "CO-GUV" : true, "CO-HUI" : true, "CO-LAG" : true, - "CO-MAG" : true, "CO-MET" : true, "CO-NAR" : true, "CO-NSA" : true, "CO-PUT" : true, - "CO-QUI" : true, "CO-RIS" : true, "CO-SAN" : true, "CO-SAP" : true, "CO-SUC" : true, - "CO-TOL" : true, "CO-VAC" : true, "CO-VAU" : true, "CO-VID" : true, "CR-A" : true, - "CR-C" : true, "CR-G" : true, "CR-H" : true, "CR-L" : true, "CR-P" : true, - "CR-SJ" : true, "CU-01" : true, "CU-02" : true, "CU-03" : true, "CU-04" : true, - "CU-05" : true, "CU-06" : true, "CU-07" : true, "CU-08" : true, "CU-09" : true, - "CU-10" : true, "CU-11" : true, "CU-12" : true, "CU-13" : true, "CU-14" : true, - "CU-99" : true, "CV-B" : true, "CV-BR" : true, "CV-BV" : true, "CV-CA" : true, - "CV-CF" : true, "CV-CR" : true, "CV-MA" : true, "CV-MO" : true, "CV-PA" : true, - "CV-PN" : true, "CV-PR" : true, "CV-RB" : true, "CV-RG" : true, "CV-RS" : true, - "CV-S" : true, "CV-SD" : true, "CV-SF" : true, "CV-SL" : true, "CV-SM" : true, - "CV-SO" : true, "CV-SS" : true, "CV-SV" : true, "CV-TA" : true, "CV-TS" : true, - "CY-01" : true, "CY-02" : true, "CY-03" : true, "CY-04" : true, "CY-05" : true, - "CY-06" : true, "CZ-10" : true, "CZ-101" : true, "CZ-102" : true, "CZ-103" : true, - "CZ-104" : true, "CZ-105" : true, "CZ-106" : true, "CZ-107" : true, "CZ-108" : true, - "CZ-109" : true, "CZ-110" : true, "CZ-111" : true, "CZ-112" : true, "CZ-113" : true, - "CZ-114" : true, "CZ-115" : true, "CZ-116" : true, "CZ-117" : true, "CZ-118" : true, - "CZ-119" : true, "CZ-120" : true, "CZ-121" : true, "CZ-122" : true, "CZ-20" : true, - "CZ-201" : true, "CZ-202" : true, "CZ-203" : true, "CZ-204" : true, "CZ-205" : true, - "CZ-206" : true, "CZ-207" : true, "CZ-208" : true, "CZ-209" : true, "CZ-20A" : true, - "CZ-20B" : true, "CZ-20C" : true, "CZ-31" : true, "CZ-311" : true, "CZ-312" : true, - "CZ-313" : true, "CZ-314" : true, "CZ-315" : true, "CZ-316" : true, "CZ-317" : true, - "CZ-32" : true, "CZ-321" : true, "CZ-322" : true, "CZ-323" : true, "CZ-324" : true, - "CZ-325" : true, "CZ-326" : true, "CZ-327" : true, "CZ-41" : true, "CZ-411" : true, - "CZ-412" : true, "CZ-413" : true, "CZ-42" : true, "CZ-421" : true, "CZ-422" : true, - "CZ-423" : true, "CZ-424" : true, "CZ-425" : true, "CZ-426" : true, "CZ-427" : true, - "CZ-51" : true, "CZ-511" : true, "CZ-512" : true, "CZ-513" : true, "CZ-514" : true, - "CZ-52" : true, "CZ-521" : true, "CZ-522" : true, "CZ-523" : true, "CZ-524" : true, - "CZ-525" : true, "CZ-53" : true, "CZ-531" : true, "CZ-532" : true, "CZ-533" : true, - "CZ-534" : true, "CZ-63" : true, "CZ-631" : true, "CZ-632" : true, "CZ-633" : true, - "CZ-634" : true, "CZ-635" : true, "CZ-64" : true, "CZ-641" : true, "CZ-642" : true, - "CZ-643" : true, "CZ-644" : true, "CZ-645" : true, "CZ-646" : true, "CZ-647" : true, - "CZ-71" : true, "CZ-711" : true, "CZ-712" : true, "CZ-713" : true, "CZ-714" : true, - "CZ-715" : true, "CZ-72" : true, "CZ-721" : true, "CZ-722" : true, "CZ-723" : true, - "CZ-724" : true, "CZ-80" : true, "CZ-801" : true, "CZ-802" : true, "CZ-803" : true, - "CZ-804" : true, "CZ-805" : true, "CZ-806" : true, "DE-BB" : true, "DE-BE" : true, - "DE-BW" : true, "DE-BY" : true, "DE-HB" : true, "DE-HE" : true, "DE-HH" : true, - "DE-MV" : true, "DE-NI" : true, "DE-NW" : true, "DE-RP" : true, "DE-SH" : true, - "DE-SL" : true, "DE-SN" : true, "DE-ST" : true, "DE-TH" : true, "DJ-AR" : true, - "DJ-AS" : true, "DJ-DI" : true, "DJ-DJ" : true, "DJ-OB" : true, "DJ-TA" : true, - "DK-81" : true, "DK-82" : true, "DK-83" : true, "DK-84" : true, "DK-85" : true, - "DM-01" : true, "DM-02" : true, "DM-03" : true, "DM-04" : true, "DM-05" : true, - "DM-06" : true, "DM-07" : true, "DM-08" : true, "DM-09" : true, "DM-10" : true, - "DO-01" : true, "DO-02" : true, "DO-03" : true, "DO-04" : true, "DO-05" : true, - "DO-06" : true, "DO-07" : true, "DO-08" : true, "DO-09" : true, "DO-10" : true, - "DO-11" : true, "DO-12" : true, "DO-13" : true, "DO-14" : true, "DO-15" : true, - "DO-16" : true, "DO-17" : true, "DO-18" : true, "DO-19" : true, "DO-20" : true, - "DO-21" : true, "DO-22" : true, "DO-23" : true, "DO-24" : true, "DO-25" : true, - "DO-26" : true, "DO-27" : true, "DO-28" : true, "DO-29" : true, "DO-30" : true, - "DZ-01" : true, "DZ-02" : true, "DZ-03" : true, "DZ-04" : true, "DZ-05" : true, - "DZ-06" : true, "DZ-07" : true, "DZ-08" : true, "DZ-09" : true, "DZ-10" : true, - "DZ-11" : true, "DZ-12" : true, "DZ-13" : true, "DZ-14" : true, "DZ-15" : true, - "DZ-16" : true, "DZ-17" : true, "DZ-18" : true, "DZ-19" : true, "DZ-20" : true, - "DZ-21" : true, "DZ-22" : true, "DZ-23" : true, "DZ-24" : true, "DZ-25" : true, - "DZ-26" : true, "DZ-27" : true, "DZ-28" : true, "DZ-29" : true, "DZ-30" : true, - "DZ-31" : true, "DZ-32" : true, "DZ-33" : true, "DZ-34" : true, "DZ-35" : true, - "DZ-36" : true, "DZ-37" : true, "DZ-38" : true, "DZ-39" : true, "DZ-40" : true, - "DZ-41" : true, "DZ-42" : true, "DZ-43" : true, "DZ-44" : true, "DZ-45" : true, - "DZ-46" : true, "DZ-47" : true, "DZ-48" : true, "EC-A" : true, "EC-B" : true, - "EC-C" : true, "EC-D" : true, "EC-E" : true, "EC-F" : true, "EC-G" : true, - "EC-H" : true, "EC-I" : true, "EC-L" : true, "EC-M" : true, "EC-N" : true, - "EC-O" : true, "EC-P" : true, "EC-R" : true, "EC-S" : true, "EC-SD" : true, - "EC-SE" : true, "EC-T" : true, "EC-U" : true, "EC-W" : true, "EC-X" : true, - "EC-Y" : true, "EC-Z" : true, "EE-37" : true, "EE-39" : true, "EE-44" : true, - "EE-49" : true, "EE-51" : true, "EE-57" : true, "EE-59" : true, "EE-65" : true, - "EE-67" : true, "EE-70" : true, "EE-74" : true, "EE-78" : true, "EE-82" : true, - "EE-84" : true, "EE-86" : true, "EG-ALX" : true, "EG-ASN" : true, "EG-AST" : true, - "EG-BA" : true, "EG-BH" : true, "EG-BNS" : true, "EG-C" : true, "EG-DK" : true, - "EG-DT" : true, "EG-FYM" : true, "EG-GH" : true, "EG-GZ" : true, "EG-HU" : true, - "EG-IS" : true, "EG-JS" : true, "EG-KB" : true, "EG-KFS" : true, "EG-KN" : true, - "EG-MN" : true, "EG-MNF" : true, "EG-MT" : true, "EG-PTS" : true, "EG-SHG" : true, - "EG-SHR" : true, "EG-SIN" : true, "EG-SU" : true, "EG-SUZ" : true, "EG-WAD" : true, - "ER-AN" : true, "ER-DK" : true, "ER-DU" : true, "ER-GB" : true, "ER-MA" : true, - "ER-SK" : true, "ES-A" : true, "ES-AB" : true, "ES-AL" : true, "ES-AN" : true, - "ES-AR" : true, "ES-AS" : true, "ES-AV" : true, "ES-B" : true, "ES-BA" : true, - "ES-BI" : true, "ES-BU" : true, "ES-C" : true, "ES-CA" : true, "ES-CB" : true, - "ES-CC" : true, "ES-CE" : true, "ES-CL" : true, "ES-CM" : true, "ES-CN" : true, - "ES-CO" : true, "ES-CR" : true, "ES-CS" : true, "ES-CT" : true, "ES-CU" : true, - "ES-EX" : true, "ES-GA" : true, "ES-GC" : true, "ES-GI" : true, "ES-GR" : true, - "ES-GU" : true, "ES-H" : true, "ES-HU" : true, "ES-IB" : true, "ES-J" : true, - "ES-L" : true, "ES-LE" : true, "ES-LO" : true, "ES-LU" : true, "ES-M" : true, - "ES-MA" : true, "ES-MC" : true, "ES-MD" : true, "ES-ML" : true, "ES-MU" : true, - "ES-NA" : true, "ES-NC" : true, "ES-O" : true, "ES-OR" : true, "ES-P" : true, - "ES-PM" : true, "ES-PO" : true, "ES-PV" : true, "ES-RI" : true, "ES-S" : true, - "ES-SA" : true, "ES-SE" : true, "ES-SG" : true, "ES-SO" : true, "ES-SS" : true, - "ES-T" : true, "ES-TE" : true, "ES-TF" : true, "ES-TO" : true, "ES-V" : true, - "ES-VA" : true, "ES-VC" : true, "ES-VI" : true, "ES-Z" : true, "ES-ZA" : true, - "ET-AA" : true, "ET-AF" : true, "ET-AM" : true, "ET-BE" : true, "ET-DD" : true, - "ET-GA" : true, "ET-HA" : true, "ET-OR" : true, "ET-SN" : true, "ET-SO" : true, - "ET-TI" : true, "FI-01" : true, "FI-02" : true, "FI-03" : true, "FI-04" : true, - "FI-05" : true, "FI-06" : true, "FI-07" : true, "FI-08" : true, "FI-09" : true, - "FI-10" : true, "FI-11" : true, "FI-12" : true, "FI-13" : true, "FI-14" : true, - "FI-15" : true, "FI-16" : true, "FI-17" : true, "FI-18" : true, "FI-19" : true, - "FJ-C" : true, "FJ-E" : true, "FJ-N" : true, "FJ-R" : true, "FJ-W" : true, - "FM-KSA" : true, "FM-PNI" : true, "FM-TRK" : true, "FM-YAP" : true, "FR-01" : true, - "FR-02" : true, "FR-03" : true, "FR-04" : true, "FR-05" : true, "FR-06" : true, - "FR-07" : true, "FR-08" : true, "FR-09" : true, "FR-10" : true, "FR-11" : true, - "FR-12" : true, "FR-13" : true, "FR-14" : true, "FR-15" : true, "FR-16" : true, - "FR-17" : true, "FR-18" : true, "FR-19" : true, "FR-21" : true, "FR-22" : true, - "FR-23" : true, "FR-24" : true, "FR-25" : true, "FR-26" : true, "FR-27" : true, - "FR-28" : true, "FR-29" : true, "FR-2A" : true, "FR-2B" : true, "FR-30" : true, - "FR-31" : true, "FR-32" : true, "FR-33" : true, "FR-34" : true, "FR-35" : true, - "FR-36" : true, "FR-37" : true, "FR-38" : true, "FR-39" : true, "FR-40" : true, - "FR-41" : true, "FR-42" : true, "FR-43" : true, "FR-44" : true, "FR-45" : true, - "FR-46" : true, "FR-47" : true, "FR-48" : true, "FR-49" : true, "FR-50" : true, - "FR-51" : true, "FR-52" : true, "FR-53" : true, "FR-54" : true, "FR-55" : true, - "FR-56" : true, "FR-57" : true, "FR-58" : true, "FR-59" : true, "FR-60" : true, - "FR-61" : true, "FR-62" : true, "FR-63" : true, "FR-64" : true, "FR-65" : true, - "FR-66" : true, "FR-67" : true, "FR-68" : true, "FR-69" : true, "FR-70" : true, - "FR-71" : true, "FR-72" : true, "FR-73" : true, "FR-74" : true, "FR-75" : true, - "FR-76" : true, "FR-77" : true, "FR-78" : true, "FR-79" : true, "FR-80" : true, - "FR-81" : true, "FR-82" : true, "FR-83" : true, "FR-84" : true, "FR-85" : true, - "FR-86" : true, "FR-87" : true, "FR-88" : true, "FR-89" : true, "FR-90" : true, - "FR-91" : true, "FR-92" : true, "FR-93" : true, "FR-94" : true, "FR-95" : true, - "FR-ARA" : true, "FR-BFC" : true, "FR-BL" : true, "FR-BRE" : true, "FR-COR" : true, - "FR-CP" : true, "FR-CVL" : true, "FR-GES" : true, "FR-GF" : true, "FR-GP" : true, - "FR-GUA" : true, "FR-HDF" : true, "FR-IDF" : true, "FR-LRE" : true, "FR-MAY" : true, - "FR-MF" : true, "FR-MQ" : true, "FR-NAQ" : true, "FR-NC" : true, "FR-NOR" : true, - "FR-OCC" : true, "FR-PAC" : true, "FR-PDL" : true, "FR-PF" : true, "FR-PM" : true, - "FR-RE" : true, "FR-TF" : true, "FR-WF" : true, "FR-YT" : true, "GA-1" : true, - "GA-2" : true, "GA-3" : true, "GA-4" : true, "GA-5" : true, "GA-6" : true, - "GA-7" : true, "GA-8" : true, "GA-9" : true, "GB-ABC" : true, "GB-ABD" : true, - "GB-ABE" : true, "GB-AGB" : true, "GB-AGY" : true, "GB-AND" : true, "GB-ANN" : true, - "GB-ANS" : true, "GB-BAS" : true, "GB-BBD" : true, "GB-BDF" : true, "GB-BDG" : true, - "GB-BEN" : true, "GB-BEX" : true, "GB-BFS" : true, "GB-BGE" : true, "GB-BGW" : true, - "GB-BIR" : true, "GB-BKM" : true, "GB-BMH" : true, "GB-BNE" : true, "GB-BNH" : true, - "GB-BNS" : true, "GB-BOL" : true, "GB-BPL" : true, "GB-BRC" : true, "GB-BRD" : true, - "GB-BRY" : true, "GB-BST" : true, "GB-BUR" : true, "GB-CAM" : true, "GB-CAY" : true, - "GB-CBF" : true, "GB-CCG" : true, "GB-CGN" : true, "GB-CHE" : true, "GB-CHW" : true, - "GB-CLD" : true, "GB-CLK" : true, "GB-CMA" : true, "GB-CMD" : true, "GB-CMN" : true, - "GB-CON" : true, "GB-COV" : true, "GB-CRF" : true, "GB-CRY" : true, "GB-CWY" : true, - "GB-DAL" : true, "GB-DBY" : true, "GB-DEN" : true, "GB-DER" : true, "GB-DEV" : true, - "GB-DGY" : true, "GB-DNC" : true, "GB-DND" : true, "GB-DOR" : true, "GB-DRS" : true, - "GB-DUD" : true, "GB-DUR" : true, "GB-EAL" : true, "GB-EAW" : true, "GB-EAY" : true, - "GB-EDH" : true, "GB-EDU" : true, "GB-ELN" : true, "GB-ELS" : true, "GB-ENF" : true, - "GB-ENG" : true, "GB-ERW" : true, "GB-ERY" : true, "GB-ESS" : true, "GB-ESX" : true, - "GB-FAL" : true, "GB-FIF" : true, "GB-FLN" : true, "GB-FMO" : true, "GB-GAT" : true, - "GB-GBN" : true, "GB-GLG" : true, "GB-GLS" : true, "GB-GRE" : true, "GB-GWN" : true, - "GB-HAL" : true, "GB-HAM" : true, "GB-HAV" : true, "GB-HCK" : true, "GB-HEF" : true, - "GB-HIL" : true, "GB-HLD" : true, "GB-HMF" : true, "GB-HNS" : true, "GB-HPL" : true, - "GB-HRT" : true, "GB-HRW" : true, "GB-HRY" : true, "GB-IOS" : true, "GB-IOW" : true, - "GB-ISL" : true, "GB-IVC" : true, "GB-KEC" : true, "GB-KEN" : true, "GB-KHL" : true, - "GB-KIR" : true, "GB-KTT" : true, "GB-KWL" : true, "GB-LAN" : true, "GB-LBC" : true, - "GB-LBH" : true, "GB-LCE" : true, "GB-LDS" : true, "GB-LEC" : true, "GB-LEW" : true, - "GB-LIN" : true, "GB-LIV" : true, "GB-LND" : true, "GB-LUT" : true, "GB-MAN" : true, - "GB-MDB" : true, "GB-MDW" : true, "GB-MEA" : true, "GB-MIK" : true, "GD-01" : true, - "GB-MLN" : true, "GB-MON" : true, "GB-MRT" : true, "GB-MRY" : true, "GB-MTY" : true, - "GB-MUL" : true, "GB-NAY" : true, "GB-NBL" : true, "GB-NEL" : true, "GB-NET" : true, - "GB-NFK" : true, "GB-NGM" : true, "GB-NIR" : true, "GB-NLK" : true, "GB-NLN" : true, - "GB-NMD" : true, "GB-NSM" : true, "GB-NTH" : true, "GB-NTL" : true, "GB-NTT" : true, - "GB-NTY" : true, "GB-NWM" : true, "GB-NWP" : true, "GB-NYK" : true, "GB-OLD" : true, - "GB-ORK" : true, "GB-OXF" : true, "GB-PEM" : true, "GB-PKN" : true, "GB-PLY" : true, - "GB-POL" : true, "GB-POR" : true, "GB-POW" : true, "GB-PTE" : true, "GB-RCC" : true, - "GB-RCH" : true, "GB-RCT" : true, "GB-RDB" : true, "GB-RDG" : true, "GB-RFW" : true, - "GB-RIC" : true, "GB-ROT" : true, "GB-RUT" : true, "GB-SAW" : true, "GB-SAY" : true, - "GB-SCB" : true, "GB-SCT" : true, "GB-SFK" : true, "GB-SFT" : true, "GB-SGC" : true, - "GB-SHF" : true, "GB-SHN" : true, "GB-SHR" : true, "GB-SKP" : true, "GB-SLF" : true, - "GB-SLG" : true, "GB-SLK" : true, "GB-SND" : true, "GB-SOL" : true, "GB-SOM" : true, - "GB-SOS" : true, "GB-SRY" : true, "GB-STE" : true, "GB-STG" : true, "GB-STH" : true, - "GB-STN" : true, "GB-STS" : true, "GB-STT" : true, "GB-STY" : true, "GB-SWA" : true, - "GB-SWD" : true, "GB-SWK" : true, "GB-TAM" : true, "GB-TFW" : true, "GB-THR" : true, - "GB-TOB" : true, "GB-TOF" : true, "GB-TRF" : true, "GB-TWH" : true, "GB-UKM" : true, - "GB-VGL" : true, "GB-WAR" : true, "GB-WBK" : true, "GB-WDU" : true, "GB-WFT" : true, - "GB-WGN" : true, "GB-WIL" : true, "GB-WKF" : true, "GB-WLL" : true, "GB-WLN" : true, - "GB-WLS" : true, "GB-WLV" : true, "GB-WND" : true, "GB-WNM" : true, "GB-WOK" : true, - "GB-WOR" : true, "GB-WRL" : true, "GB-WRT" : true, "GB-WRX" : true, "GB-WSM" : true, - "GB-WSX" : true, "GB-YOR" : true, "GB-ZET" : true, "GD-02" : true, "GD-03" : true, - "GD-04" : true, "GD-05" : true, "GD-06" : true, "GD-10" : true, "GE-AB" : true, - "GE-AJ" : true, "GE-GU" : true, "GE-IM" : true, "GE-KA" : true, "GE-KK" : true, - "GE-MM" : true, "GE-RL" : true, "GE-SJ" : true, "GE-SK" : true, "GE-SZ" : true, - "GE-TB" : true, "GH-AA" : true, "GH-AH" : true, "GH-BA" : true, "GH-CP" : true, - "GH-EP" : true, "GH-NP" : true, "GH-TV" : true, "GH-UE" : true, "GH-UW" : true, - "GH-WP" : true, "GL-KU" : true, "GL-QA" : true, "GL-QE" : true, "GL-SM" : true, - "GM-B" : true, "GM-L" : true, "GM-M" : true, "GM-N" : true, "GM-U" : true, - "GM-W" : true, "GN-B" : true, "GN-BE" : true, "GN-BF" : true, "GN-BK" : true, - "GN-C" : true, "GN-CO" : true, "GN-D" : true, "GN-DB" : true, "GN-DI" : true, - "GN-DL" : true, "GN-DU" : true, "GN-F" : true, "GN-FA" : true, "GN-FO" : true, - "GN-FR" : true, "GN-GA" : true, "GN-GU" : true, "GN-K" : true, "GN-KA" : true, - "GN-KB" : true, "GN-KD" : true, "GN-KE" : true, "GN-KN" : true, "GN-KO" : true, - "GN-KS" : true, "GN-L" : true, "GN-LA" : true, "GN-LE" : true, "GN-LO" : true, - "GN-M" : true, "GN-MC" : true, "GN-MD" : true, "GN-ML" : true, "GN-MM" : true, - "GN-N" : true, "GN-NZ" : true, "GN-PI" : true, "GN-SI" : true, "GN-TE" : true, - "GN-TO" : true, "GN-YO" : true, "GQ-AN" : true, "GQ-BN" : true, "GQ-BS" : true, - "GQ-C" : true, "GQ-CS" : true, "GQ-I" : true, "GQ-KN" : true, "GQ-LI" : true, - "GQ-WN" : true, "GR-01" : true, "GR-03" : true, "GR-04" : true, "GR-05" : true, - "GR-06" : true, "GR-07" : true, "GR-11" : true, "GR-12" : true, "GR-13" : true, - "GR-14" : true, "GR-15" : true, "GR-16" : true, "GR-17" : true, "GR-21" : true, - "GR-22" : true, "GR-23" : true, "GR-24" : true, "GR-31" : true, "GR-32" : true, - "GR-33" : true, "GR-34" : true, "GR-41" : true, "GR-42" : true, "GR-43" : true, - "GR-44" : true, "GR-51" : true, "GR-52" : true, "GR-53" : true, "GR-54" : true, - "GR-55" : true, "GR-56" : true, "GR-57" : true, "GR-58" : true, "GR-59" : true, - "GR-61" : true, "GR-62" : true, "GR-63" : true, "GR-64" : true, "GR-69" : true, - "GR-71" : true, "GR-72" : true, "GR-73" : true, "GR-81" : true, "GR-82" : true, - "GR-83" : true, "GR-84" : true, "GR-85" : true, "GR-91" : true, "GR-92" : true, - "GR-93" : true, "GR-94" : true, "GR-A" : true, "GR-A1" : true, "GR-B" : true, - "GR-C" : true, "GR-D" : true, "GR-E" : true, "GR-F" : true, "GR-G" : true, - "GR-H" : true, "GR-I" : true, "GR-J" : true, "GR-K" : true, "GR-L" : true, - "GR-M" : true, "GT-AV" : true, "GT-BV" : true, "GT-CM" : true, "GT-CQ" : true, - "GT-ES" : true, "GT-GU" : true, "GT-HU" : true, "GT-IZ" : true, "GT-JA" : true, - "GT-JU" : true, "GT-PE" : true, "GT-PR" : true, "GT-QC" : true, "GT-QZ" : true, - "GT-RE" : true, "GT-SA" : true, "GT-SM" : true, "GT-SO" : true, "GT-SR" : true, - "GT-SU" : true, "GT-TO" : true, "GT-ZA" : true, "GW-BA" : true, "GW-BL" : true, - "GW-BM" : true, "GW-BS" : true, "GW-CA" : true, "GW-GA" : true, "GW-L" : true, - "GW-N" : true, "GW-OI" : true, "GW-QU" : true, "GW-S" : true, "GW-TO" : true, - "GY-BA" : true, "GY-CU" : true, "GY-DE" : true, "GY-EB" : true, "GY-ES" : true, - "GY-MA" : true, "GY-PM" : true, "GY-PT" : true, "GY-UD" : true, "GY-UT" : true, - "HN-AT" : true, "HN-CH" : true, "HN-CL" : true, "HN-CM" : true, "HN-CP" : true, - "HN-CR" : true, "HN-EP" : true, "HN-FM" : true, "HN-GD" : true, "HN-IB" : true, - "HN-IN" : true, "HN-LE" : true, "HN-LP" : true, "HN-OC" : true, "HN-OL" : true, - "HN-SB" : true, "HN-VA" : true, "HN-YO" : true, "HR-01" : true, "HR-02" : true, - "HR-03" : true, "HR-04" : true, "HR-05" : true, "HR-06" : true, "HR-07" : true, - "HR-08" : true, "HR-09" : true, "HR-10" : true, "HR-11" : true, "HR-12" : true, - "HR-13" : true, "HR-14" : true, "HR-15" : true, "HR-16" : true, "HR-17" : true, - "HR-18" : true, "HR-19" : true, "HR-20" : true, "HR-21" : true, "HT-AR" : true, - "HT-CE" : true, "HT-GA" : true, "HT-ND" : true, "HT-NE" : true, "HT-NO" : true, - "HT-OU" : true, "HT-SD" : true, "HT-SE" : true, "HU-BA" : true, "HU-BC" : true, - "HU-BE" : true, "HU-BK" : true, "HU-BU" : true, "HU-BZ" : true, "HU-CS" : true, - "HU-DE" : true, "HU-DU" : true, "HU-EG" : true, "HU-ER" : true, "HU-FE" : true, - "HU-GS" : true, "HU-GY" : true, "HU-HB" : true, "HU-HE" : true, "HU-HV" : true, - "HU-JN" : true, "HU-KE" : true, "HU-KM" : true, "HU-KV" : true, "HU-MI" : true, - "HU-NK" : true, "HU-NO" : true, "HU-NY" : true, "HU-PE" : true, "HU-PS" : true, - "HU-SD" : true, "HU-SF" : true, "HU-SH" : true, "HU-SK" : true, "HU-SN" : true, - "HU-SO" : true, "HU-SS" : true, "HU-ST" : true, "HU-SZ" : true, "HU-TB" : true, - "HU-TO" : true, "HU-VA" : true, "HU-VE" : true, "HU-VM" : true, "HU-ZA" : true, - "HU-ZE" : true, "ID-AC" : true, "ID-BA" : true, "ID-BB" : true, "ID-BE" : true, - "ID-BT" : true, "ID-GO" : true, "ID-IJ" : true, "ID-JA" : true, "ID-JB" : true, - "ID-JI" : true, "ID-JK" : true, "ID-JT" : true, "ID-JW" : true, "ID-KA" : true, - "ID-KB" : true, "ID-KI" : true, "ID-KR" : true, "ID-KS" : true, "ID-KT" : true, - "ID-LA" : true, "ID-MA" : true, "ID-ML" : true, "ID-MU" : true, "ID-NB" : true, - "ID-NT" : true, "ID-NU" : true, "ID-PA" : true, "ID-PB" : true, "ID-RI" : true, - "ID-SA" : true, "ID-SB" : true, "ID-SG" : true, "ID-SL" : true, "ID-SM" : true, - "ID-SN" : true, "ID-SR" : true, "ID-SS" : true, "ID-ST" : true, "ID-SU" : true, - "ID-YO" : true, "IE-C" : true, "IE-CE" : true, "IE-CN" : true, "IE-CO" : true, - "IE-CW" : true, "IE-D" : true, "IE-DL" : true, "IE-G" : true, "IE-KE" : true, - "IE-KK" : true, "IE-KY" : true, "IE-L" : true, "IE-LD" : true, "IE-LH" : true, - "IE-LK" : true, "IE-LM" : true, "IE-LS" : true, "IE-M" : true, "IE-MH" : true, - "IE-MN" : true, "IE-MO" : true, "IE-OY" : true, "IE-RN" : true, "IE-SO" : true, - "IE-TA" : true, "IE-U" : true, "IE-WD" : true, "IE-WH" : true, "IE-WW" : true, - "IE-WX" : true, "IL-D" : true, "IL-HA" : true, "IL-JM" : true, "IL-M" : true, - "IL-TA" : true, "IL-Z" : true, "IN-AN" : true, "IN-AP" : true, "IN-AR" : true, - "IN-AS" : true, "IN-BR" : true, "IN-CH" : true, "IN-CT" : true, "IN-DD" : true, - "IN-DL" : true, "IN-DN" : true, "IN-GA" : true, "IN-GJ" : true, "IN-HP" : true, - "IN-HR" : true, "IN-JH" : true, "IN-JK" : true, "IN-KA" : true, "IN-KL" : true, - "IN-LD" : true, "IN-MH" : true, "IN-ML" : true, "IN-MN" : true, "IN-MP" : true, - "IN-MZ" : true, "IN-NL" : true, "IN-OR" : true, "IN-PB" : true, "IN-PY" : true, - "IN-RJ" : true, "IN-SK" : true, "IN-TN" : true, "IN-TR" : true, "IN-UP" : true, - "IN-UT" : true, "IN-WB" : true, "IQ-AN" : true, "IQ-AR" : true, "IQ-BA" : true, - "IQ-BB" : true, "IQ-BG" : true, "IQ-DA" : true, "IQ-DI" : true, "IQ-DQ" : true, - "IQ-KA" : true, "IQ-MA" : true, "IQ-MU" : true, "IQ-NA" : true, "IQ-NI" : true, - "IQ-QA" : true, "IQ-SD" : true, "IQ-SW" : true, "IQ-TS" : true, "IQ-WA" : true, - "IR-01" : true, "IR-02" : true, "IR-03" : true, "IR-04" : true, "IR-05" : true, - "IR-06" : true, "IR-07" : true, "IR-08" : true, "IR-10" : true, "IR-11" : true, - "IR-12" : true, "IR-13" : true, "IR-14" : true, "IR-15" : true, "IR-16" : true, - "IR-17" : true, "IR-18" : true, "IR-19" : true, "IR-20" : true, "IR-21" : true, - "IR-22" : true, "IR-23" : true, "IR-24" : true, "IR-25" : true, "IR-26" : true, - "IR-27" : true, "IR-28" : true, "IR-29" : true, "IR-30" : true, "IR-31" : true, - "IS-0" : true, "IS-1" : true, "IS-2" : true, "IS-3" : true, "IS-4" : true, - "IS-5" : true, "IS-6" : true, "IS-7" : true, "IS-8" : true, "IT-21" : true, - "IT-23" : true, "IT-25" : true, "IT-32" : true, "IT-34" : true, "IT-36" : true, - "IT-42" : true, "IT-45" : true, "IT-52" : true, "IT-55" : true, "IT-57" : true, - "IT-62" : true, "IT-65" : true, "IT-67" : true, "IT-72" : true, "IT-75" : true, - "IT-77" : true, "IT-78" : true, "IT-82" : true, "IT-88" : true, "IT-AG" : true, - "IT-AL" : true, "IT-AN" : true, "IT-AO" : true, "IT-AP" : true, "IT-AQ" : true, - "IT-AR" : true, "IT-AT" : true, "IT-AV" : true, "IT-BA" : true, "IT-BG" : true, - "IT-BI" : true, "IT-BL" : true, "IT-BN" : true, "IT-BO" : true, "IT-BR" : true, - "IT-BS" : true, "IT-BT" : true, "IT-BZ" : true, "IT-CA" : true, "IT-CB" : true, - "IT-CE" : true, "IT-CH" : true, "IT-CI" : true, "IT-CL" : true, "IT-CN" : true, - "IT-CO" : true, "IT-CR" : true, "IT-CS" : true, "IT-CT" : true, "IT-CZ" : true, - "IT-EN" : true, "IT-FC" : true, "IT-FE" : true, "IT-FG" : true, "IT-FI" : true, - "IT-FM" : true, "IT-FR" : true, "IT-GE" : true, "IT-GO" : true, "IT-GR" : true, - "IT-IM" : true, "IT-IS" : true, "IT-KR" : true, "IT-LC" : true, "IT-LE" : true, - "IT-LI" : true, "IT-LO" : true, "IT-LT" : true, "IT-LU" : true, "IT-MB" : true, - "IT-MC" : true, "IT-ME" : true, "IT-MI" : true, "IT-MN" : true, "IT-MO" : true, - "IT-MS" : true, "IT-MT" : true, "IT-NA" : true, "IT-NO" : true, "IT-NU" : true, - "IT-OG" : true, "IT-OR" : true, "IT-OT" : true, "IT-PA" : true, "IT-PC" : true, - "IT-PD" : true, "IT-PE" : true, "IT-PG" : true, "IT-PI" : true, "IT-PN" : true, - "IT-PO" : true, "IT-PR" : true, "IT-PT" : true, "IT-PU" : true, "IT-PV" : true, - "IT-PZ" : true, "IT-RA" : true, "IT-RC" : true, "IT-RE" : true, "IT-RG" : true, - "IT-RI" : true, "IT-RM" : true, "IT-RN" : true, "IT-RO" : true, "IT-SA" : true, - "IT-SI" : true, "IT-SO" : true, "IT-SP" : true, "IT-SR" : true, "IT-SS" : true, - "IT-SV" : true, "IT-TA" : true, "IT-TE" : true, "IT-TN" : true, "IT-TO" : true, - "IT-TP" : true, "IT-TR" : true, "IT-TS" : true, "IT-TV" : true, "IT-UD" : true, - "IT-VA" : true, "IT-VB" : true, "IT-VC" : true, "IT-VE" : true, "IT-VI" : true, - "IT-VR" : true, "IT-VS" : true, "IT-VT" : true, "IT-VV" : true, "JM-01" : true, - "JM-02" : true, "JM-03" : true, "JM-04" : true, "JM-05" : true, "JM-06" : true, - "JM-07" : true, "JM-08" : true, "JM-09" : true, "JM-10" : true, "JM-11" : true, - "JM-12" : true, "JM-13" : true, "JM-14" : true, "JO-AJ" : true, "JO-AM" : true, - "JO-AQ" : true, "JO-AT" : true, "JO-AZ" : true, "JO-BA" : true, "JO-IR" : true, - "JO-JA" : true, "JO-KA" : true, "JO-MA" : true, "JO-MD" : true, "JO-MN" : true, - "JP-01" : true, "JP-02" : true, "JP-03" : true, "JP-04" : true, "JP-05" : true, - "JP-06" : true, "JP-07" : true, "JP-08" : true, "JP-09" : true, "JP-10" : true, - "JP-11" : true, "JP-12" : true, "JP-13" : true, "JP-14" : true, "JP-15" : true, - "JP-16" : true, "JP-17" : true, "JP-18" : true, "JP-19" : true, "JP-20" : true, - "JP-21" : true, "JP-22" : true, "JP-23" : true, "JP-24" : true, "JP-25" : true, - "JP-26" : true, "JP-27" : true, "JP-28" : true, "JP-29" : true, "JP-30" : true, - "JP-31" : true, "JP-32" : true, "JP-33" : true, "JP-34" : true, "JP-35" : true, - "JP-36" : true, "JP-37" : true, "JP-38" : true, "JP-39" : true, "JP-40" : true, - "JP-41" : true, "JP-42" : true, "JP-43" : true, "JP-44" : true, "JP-45" : true, - "JP-46" : true, "JP-47" : true, "KE-110" : true, "KE-200" : true, "KE-300" : true, - "KE-400" : true, "KE-500" : true, "KE-700" : true, "KE-800" : true, "KG-B" : true, - "KG-C" : true, "KG-GB" : true, "KG-J" : true, "KG-N" : true, "KG-O" : true, - "KG-T" : true, "KG-Y" : true, "KH-1" : true, "KH-10" : true, "KH-11" : true, - "KH-12" : true, "KH-13" : true, "KH-14" : true, "KH-15" : true, "KH-16" : true, - "KH-17" : true, "KH-18" : true, "KH-19" : true, "KH-2" : true, "KH-20" : true, - "KH-21" : true, "KH-22" : true, "KH-23" : true, "KH-24" : true, "KH-3" : true, - "KH-4" : true, "KH-5" : true, "KH-6" : true, "KH-7" : true, "KH-8" : true, - "KH-9" : true, "KI-G" : true, "KI-L" : true, "KI-P" : true, "KM-A" : true, - "KM-G" : true, "KM-M" : true, "KN-01" : true, "KN-02" : true, "KN-03" : true, - "KN-04" : true, "KN-05" : true, "KN-06" : true, "KN-07" : true, "KN-08" : true, - "KN-09" : true, "KN-10" : true, "KN-11" : true, "KN-12" : true, "KN-13" : true, - "KN-15" : true, "KN-K" : true, "KN-N" : true, "KP-01" : true, "KP-02" : true, - "KP-03" : true, "KP-04" : true, "KP-05" : true, "KP-06" : true, "KP-07" : true, - "KP-08" : true, "KP-09" : true, "KP-10" : true, "KP-13" : true, "KR-11" : true, - "KR-26" : true, "KR-27" : true, "KR-28" : true, "KR-29" : true, "KR-30" : true, - "KR-31" : true, "KR-41" : true, "KR-42" : true, "KR-43" : true, "KR-44" : true, - "KR-45" : true, "KR-46" : true, "KR-47" : true, "KR-48" : true, "KR-49" : true, - "KW-AH" : true, "KW-FA" : true, "KW-HA" : true, "KW-JA" : true, "KW-KU" : true, - "KW-MU" : true, "KZ-AKM" : true, "KZ-AKT" : true, "KZ-ALA" : true, "KZ-ALM" : true, - "KZ-AST" : true, "KZ-ATY" : true, "KZ-KAR" : true, "KZ-KUS" : true, "KZ-KZY" : true, - "KZ-MAN" : true, "KZ-PAV" : true, "KZ-SEV" : true, "KZ-VOS" : true, "KZ-YUZ" : true, - "KZ-ZAP" : true, "KZ-ZHA" : true, "LA-AT" : true, "LA-BK" : true, "LA-BL" : true, - "LA-CH" : true, "LA-HO" : true, "LA-KH" : true, "LA-LM" : true, "LA-LP" : true, - "LA-OU" : true, "LA-PH" : true, "LA-SL" : true, "LA-SV" : true, "LA-VI" : true, - "LA-VT" : true, "LA-XA" : true, "LA-XE" : true, "LA-XI" : true, "LA-XS" : true, - "LB-AK" : true, "LB-AS" : true, "LB-BA" : true, "LB-BH" : true, "LB-BI" : true, - "LB-JA" : true, "LB-JL" : true, "LB-NA" : true, "LI-01" : true, "LI-02" : true, - "LI-03" : true, "LI-04" : true, "LI-05" : true, "LI-06" : true, "LI-07" : true, - "LI-08" : true, "LI-09" : true, "LI-10" : true, "LI-11" : true, "LK-1" : true, - "LK-11" : true, "LK-12" : true, "LK-13" : true, "LK-2" : true, "LK-21" : true, - "LK-22" : true, "LK-23" : true, "LK-3" : true, "LK-31" : true, "LK-32" : true, - "LK-33" : true, "LK-4" : true, "LK-41" : true, "LK-42" : true, "LK-43" : true, - "LK-44" : true, "LK-45" : true, "LK-5" : true, "LK-51" : true, "LK-52" : true, - "LK-53" : true, "LK-6" : true, "LK-61" : true, "LK-62" : true, "LK-7" : true, - "LK-71" : true, "LK-72" : true, "LK-8" : true, "LK-81" : true, "LK-82" : true, - "LK-9" : true, "LK-91" : true, "LK-92" : true, "LR-BG" : true, "LR-BM" : true, - "LR-CM" : true, "LR-GB" : true, "LR-GG" : true, "LR-GK" : true, "LR-LO" : true, - "LR-MG" : true, "LR-MO" : true, "LR-MY" : true, "LR-NI" : true, "LR-RI" : true, - "LR-SI" : true, "LS-A" : true, "LS-B" : true, "LS-C" : true, "LS-D" : true, - "LS-E" : true, "LS-F" : true, "LS-G" : true, "LS-H" : true, "LS-J" : true, - "LS-K" : true, "LT-AL" : true, "LT-KL" : true, "LT-KU" : true, "LT-MR" : true, - "LT-PN" : true, "LT-SA" : true, "LT-TA" : true, "LT-TE" : true, "LT-UT" : true, - "LT-VL" : true, "LU-D" : true, "LU-G" : true, "LU-L" : true, "LV-001" : true, - "LV-002" : true, "LV-003" : true, "LV-004" : true, "LV-005" : true, "LV-006" : true, - "LV-007" : true, "LV-008" : true, "LV-009" : true, "LV-010" : true, "LV-011" : true, - "LV-012" : true, "LV-013" : true, "LV-014" : true, "LV-015" : true, "LV-016" : true, - "LV-017" : true, "LV-018" : true, "LV-019" : true, "LV-020" : true, "LV-021" : true, - "LV-022" : true, "LV-023" : true, "LV-024" : true, "LV-025" : true, "LV-026" : true, - "LV-027" : true, "LV-028" : true, "LV-029" : true, "LV-030" : true, "LV-031" : true, - "LV-032" : true, "LV-033" : true, "LV-034" : true, "LV-035" : true, "LV-036" : true, - "LV-037" : true, "LV-038" : true, "LV-039" : true, "LV-040" : true, "LV-041" : true, - "LV-042" : true, "LV-043" : true, "LV-044" : true, "LV-045" : true, "LV-046" : true, - "LV-047" : true, "LV-048" : true, "LV-049" : true, "LV-050" : true, "LV-051" : true, - "LV-052" : true, "LV-053" : true, "LV-054" : true, "LV-055" : true, "LV-056" : true, - "LV-057" : true, "LV-058" : true, "LV-059" : true, "LV-060" : true, "LV-061" : true, - "LV-062" : true, "LV-063" : true, "LV-064" : true, "LV-065" : true, "LV-066" : true, - "LV-067" : true, "LV-068" : true, "LV-069" : true, "LV-070" : true, "LV-071" : true, - "LV-072" : true, "LV-073" : true, "LV-074" : true, "LV-075" : true, "LV-076" : true, - "LV-077" : true, "LV-078" : true, "LV-079" : true, "LV-080" : true, "LV-081" : true, - "LV-082" : true, "LV-083" : true, "LV-084" : true, "LV-085" : true, "LV-086" : true, - "LV-087" : true, "LV-088" : true, "LV-089" : true, "LV-090" : true, "LV-091" : true, - "LV-092" : true, "LV-093" : true, "LV-094" : true, "LV-095" : true, "LV-096" : true, - "LV-097" : true, "LV-098" : true, "LV-099" : true, "LV-100" : true, "LV-101" : true, - "LV-102" : true, "LV-103" : true, "LV-104" : true, "LV-105" : true, "LV-106" : true, - "LV-107" : true, "LV-108" : true, "LV-109" : true, "LV-110" : true, "LV-DGV" : true, - "LV-JEL" : true, "LV-JKB" : true, "LV-JUR" : true, "LV-LPX" : true, "LV-REZ" : true, - "LV-RIX" : true, "LV-VEN" : true, "LV-VMR" : true, "LY-BA" : true, "LY-BU" : true, - "LY-DR" : true, "LY-GT" : true, "LY-JA" : true, "LY-JB" : true, "LY-JG" : true, - "LY-JI" : true, "LY-JU" : true, "LY-KF" : true, "LY-MB" : true, "LY-MI" : true, - "LY-MJ" : true, "LY-MQ" : true, "LY-NL" : true, "LY-NQ" : true, "LY-SB" : true, - "LY-SR" : true, "LY-TB" : true, "LY-WA" : true, "LY-WD" : true, "LY-WS" : true, - "LY-ZA" : true, "MA-01" : true, "MA-02" : true, "MA-03" : true, "MA-04" : true, - "MA-05" : true, "MA-06" : true, "MA-07" : true, "MA-08" : true, "MA-09" : true, - "MA-10" : true, "MA-11" : true, "MA-12" : true, "MA-13" : true, "MA-14" : true, - "MA-15" : true, "MA-16" : true, "MA-AGD" : true, "MA-AOU" : true, "MA-ASZ" : true, - "MA-AZI" : true, "MA-BEM" : true, "MA-BER" : true, "MA-BES" : true, "MA-BOD" : true, - "MA-BOM" : true, "MA-CAS" : true, "MA-CHE" : true, "MA-CHI" : true, "MA-CHT" : true, - "MA-ERR" : true, "MA-ESI" : true, "MA-ESM" : true, "MA-FAH" : true, "MA-FES" : true, - "MA-FIG" : true, "MA-GUE" : true, "MA-HAJ" : true, "MA-HAO" : true, "MA-HOC" : true, - "MA-IFR" : true, "MA-INE" : true, "MA-JDI" : true, "MA-JRA" : true, "MA-KEN" : true, - "MA-KES" : true, "MA-KHE" : true, "MA-KHN" : true, "MA-KHO" : true, "MA-LAA" : true, - "MA-LAR" : true, "MA-MED" : true, "MA-MEK" : true, "MA-MMD" : true, "MA-MMN" : true, - "MA-MOH" : true, "MA-MOU" : true, "MA-NAD" : true, "MA-NOU" : true, "MA-OUA" : true, - "MA-OUD" : true, "MA-OUJ" : true, "MA-RAB" : true, "MA-SAF" : true, "MA-SAL" : true, - "MA-SEF" : true, "MA-SET" : true, "MA-SIK" : true, "MA-SKH" : true, "MA-SYB" : true, - "MA-TAI" : true, "MA-TAO" : true, "MA-TAR" : true, "MA-TAT" : true, "MA-TAZ" : true, - "MA-TET" : true, "MA-TIZ" : true, "MA-TNG" : true, "MA-TNT" : true, "MA-ZAG" : true, - "MC-CL" : true, "MC-CO" : true, "MC-FO" : true, "MC-GA" : true, "MC-JE" : true, - "MC-LA" : true, "MC-MA" : true, "MC-MC" : true, "MC-MG" : true, "MC-MO" : true, - "MC-MU" : true, "MC-PH" : true, "MC-SD" : true, "MC-SO" : true, "MC-SP" : true, - "MC-SR" : true, "MC-VR" : true, "MD-AN" : true, "MD-BA" : true, "MD-BD" : true, - "MD-BR" : true, "MD-BS" : true, "MD-CA" : true, "MD-CL" : true, "MD-CM" : true, - "MD-CR" : true, "MD-CS" : true, "MD-CT" : true, "MD-CU" : true, "MD-DO" : true, - "MD-DR" : true, "MD-DU" : true, "MD-ED" : true, "MD-FA" : true, "MD-FL" : true, - "MD-GA" : true, "MD-GL" : true, "MD-HI" : true, "MD-IA" : true, "MD-LE" : true, - "MD-NI" : true, "MD-OC" : true, "MD-OR" : true, "MD-RE" : true, "MD-RI" : true, - "MD-SD" : true, "MD-SI" : true, "MD-SN" : true, "MD-SO" : true, "MD-ST" : true, - "MD-SV" : true, "MD-TA" : true, "MD-TE" : true, "MD-UN" : true, "ME-01" : true, - "ME-02" : true, "ME-03" : true, "ME-04" : true, "ME-05" : true, "ME-06" : true, - "ME-07" : true, "ME-08" : true, "ME-09" : true, "ME-10" : true, "ME-11" : true, - "ME-12" : true, "ME-13" : true, "ME-14" : true, "ME-15" : true, "ME-16" : true, - "ME-17" : true, "ME-18" : true, "ME-19" : true, "ME-20" : true, "ME-21" : true, - "MG-A" : true, "MG-D" : true, "MG-F" : true, "MG-M" : true, "MG-T" : true, - "MG-U" : true, "MH-ALK" : true, "MH-ALL" : true, "MH-ARN" : true, "MH-AUR" : true, - "MH-EBO" : true, "MH-ENI" : true, "MH-JAB" : true, "MH-JAL" : true, "MH-KIL" : true, - "MH-KWA" : true, "MH-L" : true, "MH-LAE" : true, "MH-LIB" : true, "MH-LIK" : true, - "MH-MAJ" : true, "MH-MAL" : true, "MH-MEJ" : true, "MH-MIL" : true, "MH-NMK" : true, - "MH-NMU" : true, "MH-RON" : true, "MH-T" : true, "MH-UJA" : true, "MH-UTI" : true, - "MH-WTJ" : true, "MH-WTN" : true, "MK-01" : true, "MK-02" : true, "MK-03" : true, - "MK-04" : true, "MK-05" : true, "MK-06" : true, "MK-07" : true, "MK-08" : true, - "MK-09" : true, "MK-10" : true, "MK-11" : true, "MK-12" : true, "MK-13" : true, - "MK-14" : true, "MK-15" : true, "MK-16" : true, "MK-17" : true, "MK-18" : true, - "MK-19" : true, "MK-20" : true, "MK-21" : true, "MK-22" : true, "MK-23" : true, - "MK-24" : true, "MK-25" : true, "MK-26" : true, "MK-27" : true, "MK-28" : true, - "MK-29" : true, "MK-30" : true, "MK-31" : true, "MK-32" : true, "MK-33" : true, - "MK-34" : true, "MK-35" : true, "MK-36" : true, "MK-37" : true, "MK-38" : true, - "MK-39" : true, "MK-40" : true, "MK-41" : true, "MK-42" : true, "MK-43" : true, - "MK-44" : true, "MK-45" : true, "MK-46" : true, "MK-47" : true, "MK-48" : true, - "MK-49" : true, "MK-50" : true, "MK-51" : true, "MK-52" : true, "MK-53" : true, - "MK-54" : true, "MK-55" : true, "MK-56" : true, "MK-57" : true, "MK-58" : true, - "MK-59" : true, "MK-60" : true, "MK-61" : true, "MK-62" : true, "MK-63" : true, - "MK-64" : true, "MK-65" : true, "MK-66" : true, "MK-67" : true, "MK-68" : true, - "MK-69" : true, "MK-70" : true, "MK-71" : true, "MK-72" : true, "MK-73" : true, - "MK-74" : true, "MK-75" : true, "MK-76" : true, "MK-77" : true, "MK-78" : true, - "MK-79" : true, "MK-80" : true, "MK-81" : true, "MK-82" : true, "MK-83" : true, - "MK-84" : true, "ML-1" : true, "ML-2" : true, "ML-3" : true, "ML-4" : true, - "ML-5" : true, "ML-6" : true, "ML-7" : true, "ML-8" : true, "ML-BK0" : true, - "MM-01" : true, "MM-02" : true, "MM-03" : true, "MM-04" : true, "MM-05" : true, - "MM-06" : true, "MM-07" : true, "MM-11" : true, "MM-12" : true, "MM-13" : true, - "MM-14" : true, "MM-15" : true, "MM-16" : true, "MM-17" : true, "MN-035" : true, - "MN-037" : true, "MN-039" : true, "MN-041" : true, "MN-043" : true, "MN-046" : true, - "MN-047" : true, "MN-049" : true, "MN-051" : true, "MN-053" : true, "MN-055" : true, - "MN-057" : true, "MN-059" : true, "MN-061" : true, "MN-063" : true, "MN-064" : true, - "MN-065" : true, "MN-067" : true, "MN-069" : true, "MN-071" : true, "MN-073" : true, - "MN-1" : true, "MR-01" : true, "MR-02" : true, "MR-03" : true, "MR-04" : true, - "MR-05" : true, "MR-06" : true, "MR-07" : true, "MR-08" : true, "MR-09" : true, - "MR-10" : true, "MR-11" : true, "MR-12" : true, "MR-NKC" : true, "MT-01" : true, - "MT-02" : true, "MT-03" : true, "MT-04" : true, "MT-05" : true, "MT-06" : true, - "MT-07" : true, "MT-08" : true, "MT-09" : true, "MT-10" : true, "MT-11" : true, - "MT-12" : true, "MT-13" : true, "MT-14" : true, "MT-15" : true, "MT-16" : true, - "MT-17" : true, "MT-18" : true, "MT-19" : true, "MT-20" : true, "MT-21" : true, - "MT-22" : true, "MT-23" : true, "MT-24" : true, "MT-25" : true, "MT-26" : true, - "MT-27" : true, "MT-28" : true, "MT-29" : true, "MT-30" : true, "MT-31" : true, - "MT-32" : true, "MT-33" : true, "MT-34" : true, "MT-35" : true, "MT-36" : true, - "MT-37" : true, "MT-38" : true, "MT-39" : true, "MT-40" : true, "MT-41" : true, - "MT-42" : true, "MT-43" : true, "MT-44" : true, "MT-45" : true, "MT-46" : true, - "MT-47" : true, "MT-48" : true, "MT-49" : true, "MT-50" : true, "MT-51" : true, - "MT-52" : true, "MT-53" : true, "MT-54" : true, "MT-55" : true, "MT-56" : true, - "MT-57" : true, "MT-58" : true, "MT-59" : true, "MT-60" : true, "MT-61" : true, - "MT-62" : true, "MT-63" : true, "MT-64" : true, "MT-65" : true, "MT-66" : true, - "MT-67" : true, "MT-68" : true, "MU-AG" : true, "MU-BL" : true, "MU-BR" : true, - "MU-CC" : true, "MU-CU" : true, "MU-FL" : true, "MU-GP" : true, "MU-MO" : true, - "MU-PA" : true, "MU-PL" : true, "MU-PU" : true, "MU-PW" : true, "MU-QB" : true, - "MU-RO" : true, "MU-RP" : true, "MU-SA" : true, "MU-VP" : true, "MV-00" : true, - "MV-01" : true, "MV-02" : true, "MV-03" : true, "MV-04" : true, "MV-05" : true, - "MV-07" : true, "MV-08" : true, "MV-12" : true, "MV-13" : true, "MV-14" : true, - "MV-17" : true, "MV-20" : true, "MV-23" : true, "MV-24" : true, "MV-25" : true, - "MV-26" : true, "MV-27" : true, "MV-28" : true, "MV-29" : true, "MV-CE" : true, - "MV-MLE" : true, "MV-NC" : true, "MV-NO" : true, "MV-SC" : true, "MV-SU" : true, - "MV-UN" : true, "MV-US" : true, "MW-BA" : true, "MW-BL" : true, "MW-C" : true, - "MW-CK" : true, "MW-CR" : true, "MW-CT" : true, "MW-DE" : true, "MW-DO" : true, - "MW-KR" : true, "MW-KS" : true, "MW-LI" : true, "MW-LK" : true, "MW-MC" : true, - "MW-MG" : true, "MW-MH" : true, "MW-MU" : true, "MW-MW" : true, "MW-MZ" : true, - "MW-N" : true, "MW-NB" : true, "MW-NE" : true, "MW-NI" : true, "MW-NK" : true, - "MW-NS" : true, "MW-NU" : true, "MW-PH" : true, "MW-RU" : true, "MW-S" : true, - "MW-SA" : true, "MW-TH" : true, "MW-ZO" : true, "MX-AGU" : true, "MX-BCN" : true, - "MX-BCS" : true, "MX-CAM" : true, "MX-CHH" : true, "MX-CHP" : true, "MX-COA" : true, - "MX-COL" : true, "MX-DIF" : true, "MX-DUR" : true, "MX-GRO" : true, "MX-GUA" : true, - "MX-HID" : true, "MX-JAL" : true, "MX-MEX" : true, "MX-MIC" : true, "MX-MOR" : true, - "MX-NAY" : true, "MX-NLE" : true, "MX-OAX" : true, "MX-PUE" : true, "MX-QUE" : true, - "MX-ROO" : true, "MX-SIN" : true, "MX-SLP" : true, "MX-SON" : true, "MX-TAB" : true, - "MX-TAM" : true, "MX-TLA" : true, "MX-VER" : true, "MX-YUC" : true, "MX-ZAC" : true, - "MY-01" : true, "MY-02" : true, "MY-03" : true, "MY-04" : true, "MY-05" : true, - "MY-06" : true, "MY-07" : true, "MY-08" : true, "MY-09" : true, "MY-10" : true, - "MY-11" : true, "MY-12" : true, "MY-13" : true, "MY-14" : true, "MY-15" : true, - "MY-16" : true, "MZ-A" : true, "MZ-B" : true, "MZ-G" : true, "MZ-I" : true, - "MZ-L" : true, "MZ-MPM" : true, "MZ-N" : true, "MZ-P" : true, "MZ-Q" : true, - "MZ-S" : true, "MZ-T" : true, "NA-CA" : true, "NA-ER" : true, "NA-HA" : true, - "NA-KA" : true, "NA-KH" : true, "NA-KU" : true, "NA-OD" : true, "NA-OH" : true, - "NA-OK" : true, "NA-ON" : true, "NA-OS" : true, "NA-OT" : true, "NA-OW" : true, - "NE-1" : true, "NE-2" : true, "NE-3" : true, "NE-4" : true, "NE-5" : true, - "NE-6" : true, "NE-7" : true, "NE-8" : true, "NG-AB" : true, "NG-AD" : true, - "NG-AK" : true, "NG-AN" : true, "NG-BA" : true, "NG-BE" : true, "NG-BO" : true, - "NG-BY" : true, "NG-CR" : true, "NG-DE" : true, "NG-EB" : true, "NG-ED" : true, - "NG-EK" : true, "NG-EN" : true, "NG-FC" : true, "NG-GO" : true, "NG-IM" : true, - "NG-JI" : true, "NG-KD" : true, "NG-KE" : true, "NG-KN" : true, "NG-KO" : true, - "NG-KT" : true, "NG-KW" : true, "NG-LA" : true, "NG-NA" : true, "NG-NI" : true, - "NG-OG" : true, "NG-ON" : true, "NG-OS" : true, "NG-OY" : true, "NG-PL" : true, - "NG-RI" : true, "NG-SO" : true, "NG-TA" : true, "NG-YO" : true, "NG-ZA" : true, - "NI-AN" : true, "NI-AS" : true, "NI-BO" : true, "NI-CA" : true, "NI-CI" : true, - "NI-CO" : true, "NI-ES" : true, "NI-GR" : true, "NI-JI" : true, "NI-LE" : true, - "NI-MD" : true, "NI-MN" : true, "NI-MS" : true, "NI-MT" : true, "NI-NS" : true, - "NI-RI" : true, "NI-SJ" : true, "NL-AW" : true, "NL-BQ1" : true, "NL-BQ2" : true, - "NL-BQ3" : true, "NL-CW" : true, "NL-DR" : true, "NL-FL" : true, "NL-FR" : true, - "NL-GE" : true, "NL-GR" : true, "NL-LI" : true, "NL-NB" : true, "NL-NH" : true, - "NL-OV" : true, "NL-SX" : true, "NL-UT" : true, "NL-ZE" : true, "NL-ZH" : true, - "NO-01" : true, "NO-02" : true, "NO-03" : true, "NO-04" : true, "NO-05" : true, - "NO-06" : true, "NO-07" : true, "NO-08" : true, "NO-09" : true, "NO-10" : true, - "NO-11" : true, "NO-12" : true, "NO-14" : true, "NO-15" : true, "NO-16" : true, - "NO-17" : true, "NO-18" : true, "NO-19" : true, "NO-20" : true, "NO-21" : true, - "NO-22" : true, "NP-1" : true, "NP-2" : true, "NP-3" : true, "NP-4" : true, - "NP-5" : true, "NP-BA" : true, "NP-BH" : true, "NP-DH" : true, "NP-GA" : true, - "NP-JA" : true, "NP-KA" : true, "NP-KO" : true, "NP-LU" : true, "NP-MA" : true, - "NP-ME" : true, "NP-NA" : true, "NP-RA" : true, "NP-SA" : true, "NP-SE" : true, - "NR-01" : true, "NR-02" : true, "NR-03" : true, "NR-04" : true, "NR-05" : true, - "NR-06" : true, "NR-07" : true, "NR-08" : true, "NR-09" : true, "NR-10" : true, - "NR-11" : true, "NR-12" : true, "NR-13" : true, "NR-14" : true, "NZ-AUK" : true, - "NZ-BOP" : true, "NZ-CAN" : true, "NZ-CIT" : true, "NZ-GIS" : true, "NZ-HKB" : true, - "NZ-MBH" : true, "NZ-MWT" : true, "NZ-N" : true, "NZ-NSN" : true, "NZ-NTL" : true, - "NZ-OTA" : true, "NZ-S" : true, "NZ-STL" : true, "NZ-TAS" : true, "NZ-TKI" : true, - "NZ-WGN" : true, "NZ-WKO" : true, "NZ-WTC" : true, "OM-BA" : true, "OM-BU" : true, - "OM-DA" : true, "OM-MA" : true, "OM-MU" : true, "OM-SH" : true, "OM-WU" : true, - "OM-ZA" : true, "OM-ZU" : true, "PA-1" : true, "PA-2" : true, "PA-3" : true, - "PA-4" : true, "PA-5" : true, "PA-6" : true, "PA-7" : true, "PA-8" : true, - "PA-9" : true, "PA-EM" : true, "PA-KY" : true, "PA-NB" : true, "PE-AMA" : true, - "PE-ANC" : true, "PE-APU" : true, "PE-ARE" : true, "PE-AYA" : true, "PE-CAJ" : true, - "PE-CAL" : true, "PE-CUS" : true, "PE-HUC" : true, "PE-HUV" : true, "PE-ICA" : true, - "PE-JUN" : true, "PE-LAL" : true, "PE-LAM" : true, "PE-LIM" : true, "PE-LMA" : true, - "PE-LOR" : true, "PE-MDD" : true, "PE-MOQ" : true, "PE-PAS" : true, "PE-PIU" : true, - "PE-PUN" : true, "PE-SAM" : true, "PE-TAC" : true, "PE-TUM" : true, "PE-UCA" : true, - "PG-CPK" : true, "PG-CPM" : true, "PG-EBR" : true, "PG-EHG" : true, "PG-EPW" : true, - "PG-ESW" : true, "PG-GPK" : true, "PG-MBA" : true, "PG-MPL" : true, "PG-MPM" : true, - "PG-MRL" : true, "PG-NCD" : true, "PG-NIK" : true, "PG-NPP" : true, "PG-NSB" : true, - "PG-SAN" : true, "PG-SHM" : true, "PG-WBK" : true, "PG-WHM" : true, "PG-WPD" : true, - "PH-00" : true, "PH-01" : true, "PH-02" : true, "PH-03" : true, "PH-05" : true, - "PH-06" : true, "PH-07" : true, "PH-08" : true, "PH-09" : true, "PH-10" : true, - "PH-11" : true, "PH-12" : true, "PH-13" : true, "PH-14" : true, "PH-15" : true, - "PH-40" : true, "PH-41" : true, "PH-ABR" : true, "PH-AGN" : true, "PH-AGS" : true, - "PH-AKL" : true, "PH-ALB" : true, "PH-ANT" : true, "PH-APA" : true, "PH-AUR" : true, - "PH-BAN" : true, "PH-BAS" : true, "PH-BEN" : true, "PH-BIL" : true, "PH-BOH" : true, - "PH-BTG" : true, "PH-BTN" : true, "PH-BUK" : true, "PH-BUL" : true, "PH-CAG" : true, - "PH-CAM" : true, "PH-CAN" : true, "PH-CAP" : true, "PH-CAS" : true, "PH-CAT" : true, - "PH-CAV" : true, "PH-CEB" : true, "PH-COM" : true, "PH-DAO" : true, "PH-DAS" : true, - "PH-DAV" : true, "PH-DIN" : true, "PH-EAS" : true, "PH-GUI" : true, "PH-IFU" : true, - "PH-ILI" : true, "PH-ILN" : true, "PH-ILS" : true, "PH-ISA" : true, "PH-KAL" : true, - "PH-LAG" : true, "PH-LAN" : true, "PH-LAS" : true, "PH-LEY" : true, "PH-LUN" : true, - "PH-MAD" : true, "PH-MAG" : true, "PH-MAS" : true, "PH-MDC" : true, "PH-MDR" : true, - "PH-MOU" : true, "PH-MSC" : true, "PH-MSR" : true, "PH-NCO" : true, "PH-NEC" : true, - "PH-NER" : true, "PH-NSA" : true, "PH-NUE" : true, "PH-NUV" : true, "PH-PAM" : true, - "PH-PAN" : true, "PH-PLW" : true, "PH-QUE" : true, "PH-QUI" : true, "PH-RIZ" : true, - "PH-ROM" : true, "PH-SAR" : true, "PH-SCO" : true, "PH-SIG" : true, "PH-SLE" : true, - "PH-SLU" : true, "PH-SOR" : true, "PH-SUK" : true, "PH-SUN" : true, "PH-SUR" : true, - "PH-TAR" : true, "PH-TAW" : true, "PH-WSA" : true, "PH-ZAN" : true, "PH-ZAS" : true, - "PH-ZMB" : true, "PH-ZSI" : true, "PK-BA" : true, "PK-GB" : true, "PK-IS" : true, - "PK-JK" : true, "PK-KP" : true, "PK-PB" : true, "PK-SD" : true, "PK-TA" : true, - "PL-DS" : true, "PL-KP" : true, "PL-LB" : true, "PL-LD" : true, "PL-LU" : true, - "PL-MA" : true, "PL-MZ" : true, "PL-OP" : true, "PL-PD" : true, "PL-PK" : true, - "PL-PM" : true, "PL-SK" : true, "PL-SL" : true, "PL-WN" : true, "PL-WP" : true, - "PL-ZP" : true, "PS-BTH" : true, "PS-DEB" : true, "PS-GZA" : true, "PS-HBN" : true, - "PS-JEM" : true, "PS-JEN" : true, "PS-JRH" : true, "PS-KYS" : true, "PS-NBS" : true, - "PS-NGZ" : true, "PS-QQA" : true, "PS-RBH" : true, "PS-RFH" : true, "PS-SLT" : true, - "PS-TBS" : true, "PS-TKM" : true, "PT-01" : true, "PT-02" : true, "PT-03" : true, - "PT-04" : true, "PT-05" : true, "PT-06" : true, "PT-07" : true, "PT-08" : true, - "PT-09" : true, "PT-10" : true, "PT-11" : true, "PT-12" : true, "PT-13" : true, - "PT-14" : true, "PT-15" : true, "PT-16" : true, "PT-17" : true, "PT-18" : true, - "PT-20" : true, "PT-30" : true, "PW-002" : true, "PW-004" : true, "PW-010" : true, - "PW-050" : true, "PW-100" : true, "PW-150" : true, "PW-212" : true, "PW-214" : true, - "PW-218" : true, "PW-222" : true, "PW-224" : true, "PW-226" : true, "PW-227" : true, - "PW-228" : true, "PW-350" : true, "PW-370" : true, "PY-1" : true, "PY-10" : true, - "PY-11" : true, "PY-12" : true, "PY-13" : true, "PY-14" : true, "PY-15" : true, - "PY-16" : true, "PY-19" : true, "PY-2" : true, "PY-3" : true, "PY-4" : true, - "PY-5" : true, "PY-6" : true, "PY-7" : true, "PY-8" : true, "PY-9" : true, - "PY-ASU" : true, "QA-DA" : true, "QA-KH" : true, "QA-MS" : true, "QA-RA" : true, - "QA-US" : true, "QA-WA" : true, "QA-ZA" : true, "RO-AB" : true, "RO-AG" : true, - "RO-AR" : true, "RO-B" : true, "RO-BC" : true, "RO-BH" : true, "RO-BN" : true, - "RO-BR" : true, "RO-BT" : true, "RO-BV" : true, "RO-BZ" : true, "RO-CJ" : true, - "RO-CL" : true, "RO-CS" : true, "RO-CT" : true, "RO-CV" : true, "RO-DB" : true, - "RO-DJ" : true, "RO-GJ" : true, "RO-GL" : true, "RO-GR" : true, "RO-HD" : true, - "RO-HR" : true, "RO-IF" : true, "RO-IL" : true, "RO-IS" : true, "RO-MH" : true, - "RO-MM" : true, "RO-MS" : true, "RO-NT" : true, "RO-OT" : true, "RO-PH" : true, - "RO-SB" : true, "RO-SJ" : true, "RO-SM" : true, "RO-SV" : true, "RO-TL" : true, - "RO-TM" : true, "RO-TR" : true, "RO-VL" : true, "RO-VN" : true, "RO-VS" : true, - "RS-00" : true, "RS-01" : true, "RS-02" : true, "RS-03" : true, "RS-04" : true, - "RS-05" : true, "RS-06" : true, "RS-07" : true, "RS-08" : true, "RS-09" : true, - "RS-10" : true, "RS-11" : true, "RS-12" : true, "RS-13" : true, "RS-14" : true, - "RS-15" : true, "RS-16" : true, "RS-17" : true, "RS-18" : true, "RS-19" : true, - "RS-20" : true, "RS-21" : true, "RS-22" : true, "RS-23" : true, "RS-24" : true, - "RS-25" : true, "RS-26" : true, "RS-27" : true, "RS-28" : true, "RS-29" : true, - "RS-KM" : true, "RS-VO" : true, "RU-AD" : true, "RU-AL" : true, "RU-ALT" : true, - "RU-AMU" : true, "RU-ARK" : true, "RU-AST" : true, "RU-BA" : true, "RU-BEL" : true, - "RU-BRY" : true, "RU-BU" : true, "RU-CE" : true, "RU-CHE" : true, "RU-CHU" : true, - "RU-CU" : true, "RU-DA" : true, "RU-IN" : true, "RU-IRK" : true, "RU-IVA" : true, - "RU-KAM" : true, "RU-KB" : true, "RU-KC" : true, "RU-KDA" : true, "RU-KEM" : true, - "RU-KGD" : true, "RU-KGN" : true, "RU-KHA" : true, "RU-KHM" : true, "RU-KIR" : true, - "RU-KK" : true, "RU-KL" : true, "RU-KLU" : true, "RU-KO" : true, "RU-KOS" : true, - "RU-KR" : true, "RU-KRS" : true, "RU-KYA" : true, "RU-LEN" : true, "RU-LIP" : true, - "RU-MAG" : true, "RU-ME" : true, "RU-MO" : true, "RU-MOS" : true, "RU-MOW" : true, - "RU-MUR" : true, "RU-NEN" : true, "RU-NGR" : true, "RU-NIZ" : true, "RU-NVS" : true, - "RU-OMS" : true, "RU-ORE" : true, "RU-ORL" : true, "RU-PER" : true, "RU-PNZ" : true, - "RU-PRI" : true, "RU-PSK" : true, "RU-ROS" : true, "RU-RYA" : true, "RU-SA" : true, - "RU-SAK" : true, "RU-SAM" : true, "RU-SAR" : true, "RU-SE" : true, "RU-SMO" : true, - "RU-SPE" : true, "RU-STA" : true, "RU-SVE" : true, "RU-TA" : true, "RU-TAM" : true, - "RU-TOM" : true, "RU-TUL" : true, "RU-TVE" : true, "RU-TY" : true, "RU-TYU" : true, - "RU-UD" : true, "RU-ULY" : true, "RU-VGG" : true, "RU-VLA" : true, "RU-VLG" : true, - "RU-VOR" : true, "RU-YAN" : true, "RU-YAR" : true, "RU-YEV" : true, "RU-ZAB" : true, - "RW-01" : true, "RW-02" : true, "RW-03" : true, "RW-04" : true, "RW-05" : true, - "SA-01" : true, "SA-02" : true, "SA-03" : true, "SA-04" : true, "SA-05" : true, - "SA-06" : true, "SA-07" : true, "SA-08" : true, "SA-09" : true, "SA-10" : true, - "SA-11" : true, "SA-12" : true, "SA-14" : true, "SB-CE" : true, "SB-CH" : true, - "SB-CT" : true, "SB-GU" : true, "SB-IS" : true, "SB-MK" : true, "SB-ML" : true, - "SB-RB" : true, "SB-TE" : true, "SB-WE" : true, "SC-01" : true, "SC-02" : true, - "SC-03" : true, "SC-04" : true, "SC-05" : true, "SC-06" : true, "SC-07" : true, - "SC-08" : true, "SC-09" : true, "SC-10" : true, "SC-11" : true, "SC-12" : true, - "SC-13" : true, "SC-14" : true, "SC-15" : true, "SC-16" : true, "SC-17" : true, - "SC-18" : true, "SC-19" : true, "SC-20" : true, "SC-21" : true, "SC-22" : true, - "SC-23" : true, "SC-24" : true, "SC-25" : true, "SD-DC" : true, "SD-DE" : true, - "SD-DN" : true, "SD-DS" : true, "SD-DW" : true, "SD-GD" : true, "SD-GZ" : true, - "SD-KA" : true, "SD-KH" : true, "SD-KN" : true, "SD-KS" : true, "SD-NB" : true, - "SD-NO" : true, "SD-NR" : true, "SD-NW" : true, "SD-RS" : true, "SD-SI" : true, - "SE-AB" : true, "SE-AC" : true, "SE-BD" : true, "SE-C" : true, "SE-D" : true, - "SE-E" : true, "SE-F" : true, "SE-G" : true, "SE-H" : true, "SE-I" : true, - "SE-K" : true, "SE-M" : true, "SE-N" : true, "SE-O" : true, "SE-S" : true, - "SE-T" : true, "SE-U" : true, "SE-W" : true, "SE-X" : true, "SE-Y" : true, - "SE-Z" : true, "SG-01" : true, "SG-02" : true, "SG-03" : true, "SG-04" : true, - "SG-05" : true, "SH-AC" : true, "SH-HL" : true, "SH-TA" : true, "SI-001" : true, - "SI-002" : true, "SI-003" : true, "SI-004" : true, "SI-005" : true, "SI-006" : true, - "SI-007" : true, "SI-008" : true, "SI-009" : true, "SI-010" : true, "SI-011" : true, - "SI-012" : true, "SI-013" : true, "SI-014" : true, "SI-015" : true, "SI-016" : true, - "SI-017" : true, "SI-018" : true, "SI-019" : true, "SI-020" : true, "SI-021" : true, - "SI-022" : true, "SI-023" : true, "SI-024" : true, "SI-025" : true, "SI-026" : true, - "SI-027" : true, "SI-028" : true, "SI-029" : true, "SI-030" : true, "SI-031" : true, - "SI-032" : true, "SI-033" : true, "SI-034" : true, "SI-035" : true, "SI-036" : true, - "SI-037" : true, "SI-038" : true, "SI-039" : true, "SI-040" : true, "SI-041" : true, - "SI-042" : true, "SI-043" : true, "SI-044" : true, "SI-045" : true, "SI-046" : true, - "SI-047" : true, "SI-048" : true, "SI-049" : true, "SI-050" : true, "SI-051" : true, - "SI-052" : true, "SI-053" : true, "SI-054" : true, "SI-055" : true, "SI-056" : true, - "SI-057" : true, "SI-058" : true, "SI-059" : true, "SI-060" : true, "SI-061" : true, - "SI-062" : true, "SI-063" : true, "SI-064" : true, "SI-065" : true, "SI-066" : true, - "SI-067" : true, "SI-068" : true, "SI-069" : true, "SI-070" : true, "SI-071" : true, - "SI-072" : true, "SI-073" : true, "SI-074" : true, "SI-075" : true, "SI-076" : true, - "SI-077" : true, "SI-078" : true, "SI-079" : true, "SI-080" : true, "SI-081" : true, - "SI-082" : true, "SI-083" : true, "SI-084" : true, "SI-085" : true, "SI-086" : true, - "SI-087" : true, "SI-088" : true, "SI-089" : true, "SI-090" : true, "SI-091" : true, - "SI-092" : true, "SI-093" : true, "SI-094" : true, "SI-095" : true, "SI-096" : true, - "SI-097" : true, "SI-098" : true, "SI-099" : true, "SI-100" : true, "SI-101" : true, - "SI-102" : true, "SI-103" : true, "SI-104" : true, "SI-105" : true, "SI-106" : true, - "SI-107" : true, "SI-108" : true, "SI-109" : true, "SI-110" : true, "SI-111" : true, - "SI-112" : true, "SI-113" : true, "SI-114" : true, "SI-115" : true, "SI-116" : true, - "SI-117" : true, "SI-118" : true, "SI-119" : true, "SI-120" : true, "SI-121" : true, - "SI-122" : true, "SI-123" : true, "SI-124" : true, "SI-125" : true, "SI-126" : true, - "SI-127" : true, "SI-128" : true, "SI-129" : true, "SI-130" : true, "SI-131" : true, - "SI-132" : true, "SI-133" : true, "SI-134" : true, "SI-135" : true, "SI-136" : true, - "SI-137" : true, "SI-138" : true, "SI-139" : true, "SI-140" : true, "SI-141" : true, - "SI-142" : true, "SI-143" : true, "SI-144" : true, "SI-146" : true, "SI-147" : true, - "SI-148" : true, "SI-149" : true, "SI-150" : true, "SI-151" : true, "SI-152" : true, - "SI-153" : true, "SI-154" : true, "SI-155" : true, "SI-156" : true, "SI-157" : true, - "SI-158" : true, "SI-159" : true, "SI-160" : true, "SI-161" : true, "SI-162" : true, - "SI-163" : true, "SI-164" : true, "SI-165" : true, "SI-166" : true, "SI-167" : true, - "SI-168" : true, "SI-169" : true, "SI-170" : true, "SI-171" : true, "SI-172" : true, - "SI-173" : true, "SI-174" : true, "SI-175" : true, "SI-176" : true, "SI-177" : true, - "SI-178" : true, "SI-179" : true, "SI-180" : true, "SI-181" : true, "SI-182" : true, - "SI-183" : true, "SI-184" : true, "SI-185" : true, "SI-186" : true, "SI-187" : true, - "SI-188" : true, "SI-189" : true, "SI-190" : true, "SI-191" : true, "SI-192" : true, - "SI-193" : true, "SI-194" : true, "SI-195" : true, "SI-196" : true, "SI-197" : true, - "SI-198" : true, "SI-199" : true, "SI-200" : true, "SI-201" : true, "SI-202" : true, - "SI-203" : true, "SI-204" : true, "SI-205" : true, "SI-206" : true, "SI-207" : true, - "SI-208" : true, "SI-209" : true, "SI-210" : true, "SI-211" : true, "SK-BC" : true, - "SK-BL" : true, "SK-KI" : true, "SK-NI" : true, "SK-PV" : true, "SK-TA" : true, - "SK-TC" : true, "SK-ZI" : true, "SL-E" : true, "SL-N" : true, "SL-S" : true, - "SL-W" : true, "SM-01" : true, "SM-02" : true, "SM-03" : true, "SM-04" : true, - "SM-05" : true, "SM-06" : true, "SM-07" : true, "SM-08" : true, "SM-09" : true, - "SN-DB" : true, "SN-DK" : true, "SN-FK" : true, "SN-KA" : true, "SN-KD" : true, - "SN-KE" : true, "SN-KL" : true, "SN-LG" : true, "SN-MT" : true, "SN-SE" : true, - "SN-SL" : true, "SN-TC" : true, "SN-TH" : true, "SN-ZG" : true, "SO-AW" : true, - "SO-BK" : true, "SO-BN" : true, "SO-BR" : true, "SO-BY" : true, "SO-GA" : true, - "SO-GE" : true, "SO-HI" : true, "SO-JD" : true, "SO-JH" : true, "SO-MU" : true, - "SO-NU" : true, "SO-SA" : true, "SO-SD" : true, "SO-SH" : true, "SO-SO" : true, - "SO-TO" : true, "SO-WO" : true, "SR-BR" : true, "SR-CM" : true, "SR-CR" : true, - "SR-MA" : true, "SR-NI" : true, "SR-PM" : true, "SR-PR" : true, "SR-SA" : true, - "SR-SI" : true, "SR-WA" : true, "SS-BN" : true, "SS-BW" : true, "SS-EC" : true, - "SS-EE8" : true, "SS-EW" : true, "SS-JG" : true, "SS-LK" : true, "SS-NU" : true, - "SS-UY" : true, "SS-WR" : true, "ST-P" : true, "ST-S" : true, "SV-AH" : true, - "SV-CA" : true, "SV-CH" : true, "SV-CU" : true, "SV-LI" : true, "SV-MO" : true, - "SV-PA" : true, "SV-SA" : true, "SV-SM" : true, "SV-SO" : true, "SV-SS" : true, - "SV-SV" : true, "SV-UN" : true, "SV-US" : true, "SY-DI" : true, "SY-DR" : true, - "SY-DY" : true, "SY-HA" : true, "SY-HI" : true, "SY-HL" : true, "SY-HM" : true, - "SY-ID" : true, "SY-LA" : true, "SY-QU" : true, "SY-RA" : true, "SY-RD" : true, - "SY-SU" : true, "SY-TA" : true, "SZ-HH" : true, "SZ-LU" : true, "SZ-MA" : true, - "SZ-SH" : true, "TD-BA" : true, "TD-BG" : true, "TD-BO" : true, "TD-CB" : true, - "TD-EN" : true, "TD-GR" : true, "TD-HL" : true, "TD-KA" : true, "TD-LC" : true, - "TD-LO" : true, "TD-LR" : true, "TD-MA" : true, "TD-MC" : true, "TD-ME" : true, - "TD-MO" : true, "TD-ND" : true, "TD-OD" : true, "TD-SA" : true, "TD-SI" : true, - "TD-TA" : true, "TD-TI" : true, "TD-WF" : true, "TG-C" : true, "TG-K" : true, - "TG-M" : true, "TG-P" : true, "TG-S" : true, "TH-10" : true, "TH-11" : true, - "TH-12" : true, "TH-13" : true, "TH-14" : true, "TH-15" : true, "TH-16" : true, - "TH-17" : true, "TH-18" : true, "TH-19" : true, "TH-20" : true, "TH-21" : true, - "TH-22" : true, "TH-23" : true, "TH-24" : true, "TH-25" : true, "TH-26" : true, - "TH-27" : true, "TH-30" : true, "TH-31" : true, "TH-32" : true, "TH-33" : true, - "TH-34" : true, "TH-35" : true, "TH-36" : true, "TH-37" : true, "TH-39" : true, - "TH-40" : true, "TH-41" : true, "TH-42" : true, "TH-43" : true, "TH-44" : true, - "TH-45" : true, "TH-46" : true, "TH-47" : true, "TH-48" : true, "TH-49" : true, - "TH-50" : true, "TH-51" : true, "TH-52" : true, "TH-53" : true, "TH-54" : true, - "TH-55" : true, "TH-56" : true, "TH-57" : true, "TH-58" : true, "TH-60" : true, - "TH-61" : true, "TH-62" : true, "TH-63" : true, "TH-64" : true, "TH-65" : true, - "TH-66" : true, "TH-67" : true, "TH-70" : true, "TH-71" : true, "TH-72" : true, - "TH-73" : true, "TH-74" : true, "TH-75" : true, "TH-76" : true, "TH-77" : true, - "TH-80" : true, "TH-81" : true, "TH-82" : true, "TH-83" : true, "TH-84" : true, - "TH-85" : true, "TH-86" : true, "TH-90" : true, "TH-91" : true, "TH-92" : true, - "TH-93" : true, "TH-94" : true, "TH-95" : true, "TH-96" : true, "TH-S" : true, - "TJ-GB" : true, "TJ-KT" : true, "TJ-SU" : true, "TL-AL" : true, "TL-AN" : true, - "TL-BA" : true, "TL-BO" : true, "TL-CO" : true, "TL-DI" : true, "TL-ER" : true, - "TL-LA" : true, "TL-LI" : true, "TL-MF" : true, "TL-MT" : true, "TL-OE" : true, - "TL-VI" : true, "TM-A" : true, "TM-B" : true, "TM-D" : true, "TM-L" : true, - "TM-M" : true, "TM-S" : true, "TN-11" : true, "TN-12" : true, "TN-13" : true, - "TN-14" : true, "TN-21" : true, "TN-22" : true, "TN-23" : true, "TN-31" : true, - "TN-32" : true, "TN-33" : true, "TN-34" : true, "TN-41" : true, "TN-42" : true, - "TN-43" : true, "TN-51" : true, "TN-52" : true, "TN-53" : true, "TN-61" : true, - "TN-71" : true, "TN-72" : true, "TN-73" : true, "TN-81" : true, "TN-82" : true, - "TN-83" : true, "TO-01" : true, "TO-02" : true, "TO-03" : true, "TO-04" : true, - "TO-05" : true, "TR-01" : true, "TR-02" : true, "TR-03" : true, "TR-04" : true, - "TR-05" : true, "TR-06" : true, "TR-07" : true, "TR-08" : true, "TR-09" : true, - "TR-10" : true, "TR-11" : true, "TR-12" : true, "TR-13" : true, "TR-14" : true, - "TR-15" : true, "TR-16" : true, "TR-17" : true, "TR-18" : true, "TR-19" : true, - "TR-20" : true, "TR-21" : true, "TR-22" : true, "TR-23" : true, "TR-24" : true, - "TR-25" : true, "TR-26" : true, "TR-27" : true, "TR-28" : true, "TR-29" : true, - "TR-30" : true, "TR-31" : true, "TR-32" : true, "TR-33" : true, "TR-34" : true, - "TR-35" : true, "TR-36" : true, "TR-37" : true, "TR-38" : true, "TR-39" : true, - "TR-40" : true, "TR-41" : true, "TR-42" : true, "TR-43" : true, "TR-44" : true, - "TR-45" : true, "TR-46" : true, "TR-47" : true, "TR-48" : true, "TR-49" : true, - "TR-50" : true, "TR-51" : true, "TR-52" : true, "TR-53" : true, "TR-54" : true, - "TR-55" : true, "TR-56" : true, "TR-57" : true, "TR-58" : true, "TR-59" : true, - "TR-60" : true, "TR-61" : true, "TR-62" : true, "TR-63" : true, "TR-64" : true, - "TR-65" : true, "TR-66" : true, "TR-67" : true, "TR-68" : true, "TR-69" : true, - "TR-70" : true, "TR-71" : true, "TR-72" : true, "TR-73" : true, "TR-74" : true, - "TR-75" : true, "TR-76" : true, "TR-77" : true, "TR-78" : true, "TR-79" : true, - "TR-80" : true, "TR-81" : true, "TT-ARI" : true, "TT-CHA" : true, "TT-CTT" : true, - "TT-DMN" : true, "TT-ETO" : true, "TT-PED" : true, "TT-POS" : true, "TT-PRT" : true, - "TT-PTF" : true, "TT-RCM" : true, "TT-SFO" : true, "TT-SGE" : true, "TT-SIP" : true, - "TT-SJL" : true, "TT-TUP" : true, "TT-WTO" : true, "TV-FUN" : true, "TV-NIT" : true, - "TV-NKF" : true, "TV-NKL" : true, "TV-NMA" : true, "TV-NMG" : true, "TV-NUI" : true, - "TV-VAI" : true, "TW-CHA" : true, "TW-CYI" : true, "TW-CYQ" : true, "TW-HSQ" : true, - "TW-HSZ" : true, "TW-HUA" : true, "TW-ILA" : true, "TW-KEE" : true, "TW-KHH" : true, - "TW-KHQ" : true, "TW-MIA" : true, "TW-NAN" : true, "TW-PEN" : true, "TW-PIF" : true, - "TW-TAO" : true, "TW-TNN" : true, "TW-TNQ" : true, "TW-TPE" : true, "TW-TPQ" : true, - "TW-TTT" : true, "TW-TXG" : true, "TW-TXQ" : true, "TW-YUN" : true, "TZ-01" : true, - "TZ-02" : true, "TZ-03" : true, "TZ-04" : true, "TZ-05" : true, "TZ-06" : true, - "TZ-07" : true, "TZ-08" : true, "TZ-09" : true, "TZ-10" : true, "TZ-11" : true, - "TZ-12" : true, "TZ-13" : true, "TZ-14" : true, "TZ-15" : true, "TZ-16" : true, - "TZ-17" : true, "TZ-18" : true, "TZ-19" : true, "TZ-20" : true, "TZ-21" : true, - "TZ-22" : true, "TZ-23" : true, "TZ-24" : true, "TZ-25" : true, "TZ-26" : true, - "UA-05" : true, "UA-07" : true, "UA-09" : true, "UA-12" : true, "UA-14" : true, - "UA-18" : true, "UA-21" : true, "UA-23" : true, "UA-26" : true, "UA-30" : true, - "UA-32" : true, "UA-35" : true, "UA-40" : true, "UA-43" : true, "UA-46" : true, - "UA-48" : true, "UA-51" : true, "UA-53" : true, "UA-56" : true, "UA-59" : true, - "UA-61" : true, "UA-63" : true, "UA-65" : true, "UA-68" : true, "UA-71" : true, - "UA-74" : true, "UA-77" : true, "UG-101" : true, "UG-102" : true, "UG-103" : true, - "UG-104" : true, "UG-105" : true, "UG-106" : true, "UG-107" : true, "UG-108" : true, - "UG-109" : true, "UG-110" : true, "UG-111" : true, "UG-112" : true, "UG-113" : true, - "UG-114" : true, "UG-115" : true, "UG-116" : true, "UG-201" : true, "UG-202" : true, - "UG-203" : true, "UG-204" : true, "UG-205" : true, "UG-206" : true, "UG-207" : true, - "UG-208" : true, "UG-209" : true, "UG-210" : true, "UG-211" : true, "UG-212" : true, - "UG-213" : true, "UG-214" : true, "UG-215" : true, "UG-216" : true, "UG-217" : true, - "UG-218" : true, "UG-219" : true, "UG-220" : true, "UG-221" : true, "UG-222" : true, - "UG-223" : true, "UG-224" : true, "UG-301" : true, "UG-302" : true, "UG-303" : true, - "UG-304" : true, "UG-305" : true, "UG-306" : true, "UG-307" : true, "UG-308" : true, - "UG-309" : true, "UG-310" : true, "UG-311" : true, "UG-312" : true, "UG-313" : true, - "UG-314" : true, "UG-315" : true, "UG-316" : true, "UG-317" : true, "UG-318" : true, - "UG-319" : true, "UG-320" : true, "UG-321" : true, "UG-401" : true, "UG-402" : true, - "UG-403" : true, "UG-404" : true, "UG-405" : true, "UG-406" : true, "UG-407" : true, - "UG-408" : true, "UG-409" : true, "UG-410" : true, "UG-411" : true, "UG-412" : true, - "UG-413" : true, "UG-414" : true, "UG-415" : true, "UG-416" : true, "UG-417" : true, - "UG-418" : true, "UG-419" : true, "UG-C" : true, "UG-E" : true, "UG-N" : true, - "UG-W" : true, "UM-67" : true, "UM-71" : true, "UM-76" : true, "UM-79" : true, - "UM-81" : true, "UM-84" : true, "UM-86" : true, "UM-89" : true, "UM-95" : true, - "US-AK" : true, "US-AL" : true, "US-AR" : true, "US-AS" : true, "US-AZ" : true, - "US-CA" : true, "US-CO" : true, "US-CT" : true, "US-DC" : true, "US-DE" : true, - "US-FL" : true, "US-GA" : true, "US-GU" : true, "US-HI" : true, "US-IA" : true, - "US-ID" : true, "US-IL" : true, "US-IN" : true, "US-KS" : true, "US-KY" : true, - "US-LA" : true, "US-MA" : true, "US-MD" : true, "US-ME" : true, "US-MI" : true, - "US-MN" : true, "US-MO" : true, "US-MP" : true, "US-MS" : true, "US-MT" : true, - "US-NC" : true, "US-ND" : true, "US-NE" : true, "US-NH" : true, "US-NJ" : true, - "US-NM" : true, "US-NV" : true, "US-NY" : true, "US-OH" : true, "US-OK" : true, - "US-OR" : true, "US-PA" : true, "US-PR" : true, "US-RI" : true, "US-SC" : true, - "US-SD" : true, "US-TN" : true, "US-TX" : true, "US-UM" : true, "US-UT" : true, - "US-VA" : true, "US-VI" : true, "US-VT" : true, "US-WA" : true, "US-WI" : true, - "US-WV" : true, "US-WY" : true, "UY-AR" : true, "UY-CA" : true, "UY-CL" : true, - "UY-CO" : true, "UY-DU" : true, "UY-FD" : true, "UY-FS" : true, "UY-LA" : true, - "UY-MA" : true, "UY-MO" : true, "UY-PA" : true, "UY-RN" : true, "UY-RO" : true, - "UY-RV" : true, "UY-SA" : true, "UY-SJ" : true, "UY-SO" : true, "UY-TA" : true, - "UY-TT" : true, "UZ-AN" : true, "UZ-BU" : true, "UZ-FA" : true, "UZ-JI" : true, - "UZ-NG" : true, "UZ-NW" : true, "UZ-QA" : true, "UZ-QR" : true, "UZ-SA" : true, - "UZ-SI" : true, "UZ-SU" : true, "UZ-TK" : true, "UZ-TO" : true, "UZ-XO" : true, - "VC-01" : true, "VC-02" : true, "VC-03" : true, "VC-04" : true, "VC-05" : true, - "VC-06" : true, "VE-A" : true, "VE-B" : true, "VE-C" : true, "VE-D" : true, - "VE-E" : true, "VE-F" : true, "VE-G" : true, "VE-H" : true, "VE-I" : true, - "VE-J" : true, "VE-K" : true, "VE-L" : true, "VE-M" : true, "VE-N" : true, - "VE-O" : true, "VE-P" : true, "VE-R" : true, "VE-S" : true, "VE-T" : true, - "VE-U" : true, "VE-V" : true, "VE-W" : true, "VE-X" : true, "VE-Y" : true, - "VE-Z" : true, "VN-01" : true, "VN-02" : true, "VN-03" : true, "VN-04" : true, - "VN-05" : true, "VN-06" : true, "VN-07" : true, "VN-09" : true, "VN-13" : true, - "VN-14" : true, "VN-15" : true, "VN-18" : true, "VN-20" : true, "VN-21" : true, - "VN-22" : true, "VN-23" : true, "VN-24" : true, "VN-25" : true, "VN-26" : true, - "VN-27" : true, "VN-28" : true, "VN-29" : true, "VN-30" : true, "VN-31" : true, - "VN-32" : true, "VN-33" : true, "VN-34" : true, "VN-35" : true, "VN-36" : true, - "VN-37" : true, "VN-39" : true, "VN-40" : true, "VN-41" : true, "VN-43" : true, - "VN-44" : true, "VN-45" : true, "VN-46" : true, "VN-47" : true, "VN-49" : true, - "VN-50" : true, "VN-51" : true, "VN-52" : true, "VN-53" : true, "VN-54" : true, - "VN-55" : true, "VN-56" : true, "VN-57" : true, "VN-58" : true, "VN-59" : true, - "VN-61" : true, "VN-63" : true, "VN-66" : true, "VN-67" : true, "VN-68" : true, - "VN-69" : true, "VN-70" : true, "VN-71" : true, "VN-72" : true, "VN-73" : true, - "VN-CT" : true, "VN-DN" : true, "VN-HN" : true, "VN-HP" : true, "VN-SG" : true, - "VU-MAP" : true, "VU-PAM" : true, "VU-SAM" : true, "VU-SEE" : true, "VU-TAE" : true, - "VU-TOB" : true, "WS-AA" : true, "WS-AL" : true, "WS-AT" : true, "WS-FA" : true, - "WS-GE" : true, "WS-GI" : true, "WS-PA" : true, "WS-SA" : true, "WS-TU" : true, - "WS-VF" : true, "WS-VS" : true, "YE-AB" : true, "YE-AD" : true, "YE-AM" : true, - "YE-BA" : true, "YE-DA" : true, "YE-DH" : true, "YE-HD" : true, "YE-HJ" : true, - "YE-IB" : true, "YE-JA" : true, "YE-LA" : true, "YE-MA" : true, "YE-MR" : true, - "YE-MU" : true, "YE-MW" : true, "YE-RA" : true, "YE-SD" : true, "YE-SH" : true, - "YE-SN" : true, "YE-TA" : true, "ZA-EC" : true, "ZA-FS" : true, "ZA-GP" : true, - "ZA-LP" : true, "ZA-MP" : true, "ZA-NC" : true, "ZA-NW" : true, "ZA-WC" : true, - "ZA-ZN" : true, "ZM-01" : true, "ZM-02" : true, "ZM-03" : true, "ZM-04" : true, - "ZM-05" : true, "ZM-06" : true, "ZM-07" : true, "ZM-08" : true, "ZM-09" : true, - "ZW-BU" : true, "ZW-HA" : true, "ZW-MA" : true, "ZW-MC" : true, "ZW-ME" : true, - "ZW-MI" : true, "ZW-MN" : true, "ZW-MS" : true, "ZW-MV" : true, "ZW-MW" : true, + "AD-02": true, "AD-03": true, "AD-04": true, "AD-05": true, "AD-06": true, + "AD-07": true, "AD-08": true, "AE-AJ": true, "AE-AZ": true, "AE-DU": true, + "AE-FU": true, "AE-RK": true, "AE-SH": true, "AE-UQ": true, "AF-BAL": true, + "AF-BAM": true, "AF-BDG": true, "AF-BDS": true, "AF-BGL": true, "AF-DAY": true, + "AF-FRA": true, "AF-FYB": true, "AF-GHA": true, "AF-GHO": true, "AF-HEL": true, + "AF-HER": true, "AF-JOW": true, "AF-KAB": true, "AF-KAN": true, "AF-KAP": true, + "AF-KDZ": true, "AF-KHO": true, "AF-KNR": true, "AF-LAG": true, "AF-LOG": true, + "AF-NAN": true, "AF-NIM": true, "AF-NUR": true, "AF-PAN": true, "AF-PAR": true, + "AF-PIA": true, "AF-PKA": true, "AF-SAM": true, "AF-SAR": true, "AF-TAK": true, + "AF-URU": true, "AF-WAR": true, "AF-ZAB": true, "AG-03": true, "AG-04": true, + "AG-05": true, "AG-06": true, "AG-07": true, "AG-08": true, "AG-10": true, + "AG-11": true, "AL-01": true, "AL-02": true, "AL-03": true, "AL-04": true, + "AL-05": true, "AL-06": true, "AL-07": true, "AL-08": true, "AL-09": true, + "AL-10": true, "AL-11": true, "AL-12": true, "AL-BR": true, "AL-BU": true, + "AL-DI": true, "AL-DL": true, "AL-DR": true, "AL-DV": true, "AL-EL": true, + "AL-ER": true, "AL-FR": true, "AL-GJ": true, "AL-GR": true, "AL-HA": true, + "AL-KA": true, "AL-KB": true, "AL-KC": true, "AL-KO": true, "AL-KR": true, + "AL-KU": true, "AL-LB": true, "AL-LE": true, "AL-LU": true, "AL-MK": true, + "AL-MM": true, "AL-MR": true, "AL-MT": true, "AL-PG": true, "AL-PQ": true, + "AL-PR": true, "AL-PU": true, "AL-SH": true, "AL-SK": true, "AL-SR": true, + "AL-TE": true, "AL-TP": true, "AL-TR": true, "AL-VL": true, "AM-AG": true, + "AM-AR": true, "AM-AV": true, "AM-ER": true, "AM-GR": true, "AM-KT": true, + "AM-LO": true, "AM-SH": true, "AM-SU": true, "AM-TV": true, "AM-VD": true, + "AO-BGO": true, "AO-BGU": true, "AO-BIE": true, "AO-CAB": true, "AO-CCU": true, + "AO-CNN": true, "AO-CNO": true, "AO-CUS": true, "AO-HUA": true, "AO-HUI": true, + "AO-LNO": true, "AO-LSU": true, "AO-LUA": true, "AO-MAL": true, "AO-MOX": true, + "AO-NAM": true, "AO-UIG": true, "AO-ZAI": true, "AR-A": true, "AR-B": true, + "AR-C": true, "AR-D": true, "AR-E": true, "AR-F": true, "AR-G": true, "AR-H": true, + "AR-J": true, "AR-K": true, "AR-L": true, "AR-M": true, "AR-N": true, + "AR-P": true, "AR-Q": true, "AR-R": true, "AR-S": true, "AR-T": true, + "AR-U": true, "AR-V": true, "AR-W": true, "AR-X": true, "AR-Y": true, + "AR-Z": true, "AT-1": true, "AT-2": true, "AT-3": true, "AT-4": true, + "AT-5": true, "AT-6": true, "AT-7": true, "AT-8": true, "AT-9": true, + "AU-ACT": true, "AU-NSW": true, "AU-NT": true, "AU-QLD": true, "AU-SA": true, + "AU-TAS": true, "AU-VIC": true, "AU-WA": true, "AZ-ABS": true, "AZ-AGA": true, + "AZ-AGC": true, "AZ-AGM": true, "AZ-AGS": true, "AZ-AGU": true, "AZ-AST": true, + "AZ-BA": true, "AZ-BAB": true, "AZ-BAL": true, "AZ-BAR": true, "AZ-BEY": true, + "AZ-BIL": true, "AZ-CAB": true, "AZ-CAL": true, "AZ-CUL": true, "AZ-DAS": true, + "AZ-FUZ": true, "AZ-GA": true, "AZ-GAD": true, "AZ-GOR": true, "AZ-GOY": true, + "AZ-GYG": true, "AZ-HAC": true, "AZ-IMI": true, "AZ-ISM": true, "AZ-KAL": true, + "AZ-KAN": true, "AZ-KUR": true, "AZ-LA": true, "AZ-LAC": true, "AZ-LAN": true, + "AZ-LER": true, "AZ-MAS": true, "AZ-MI": true, "AZ-NA": true, "AZ-NEF": true, + "AZ-NV": true, "AZ-NX": true, "AZ-OGU": true, "AZ-ORD": true, "AZ-QAB": true, + "AZ-QAX": true, "AZ-QAZ": true, "AZ-QBA": true, "AZ-QBI": true, "AZ-QOB": true, + "AZ-QUS": true, "AZ-SA": true, "AZ-SAB": true, "AZ-SAD": true, "AZ-SAH": true, + "AZ-SAK": true, "AZ-SAL": true, "AZ-SAR": true, "AZ-SAT": true, "AZ-SBN": true, + "AZ-SIY": true, "AZ-SKR": true, "AZ-SM": true, "AZ-SMI": true, "AZ-SMX": true, + "AZ-SR": true, "AZ-SUS": true, "AZ-TAR": true, "AZ-TOV": true, "AZ-UCA": true, + "AZ-XA": true, "AZ-XAC": true, "AZ-XCI": true, "AZ-XIZ": true, "AZ-XVD": true, + "AZ-YAR": true, "AZ-YE": true, "AZ-YEV": true, "AZ-ZAN": true, "AZ-ZAQ": true, + "AZ-ZAR": true, "BA-01": true, "BA-02": true, "BA-03": true, "BA-04": true, + "BA-05": true, "BA-06": true, "BA-07": true, "BA-08": true, "BA-09": true, + "BA-10": true, "BA-BIH": true, "BA-BRC": true, "BA-SRP": true, "BB-01": true, + "BB-02": true, "BB-03": true, "BB-04": true, "BB-05": true, "BB-06": true, + "BB-07": true, "BB-08": true, "BB-09": true, "BB-10": true, "BB-11": true, + "BD-01": true, "BD-02": true, "BD-03": true, "BD-04": true, "BD-05": true, + "BD-06": true, "BD-07": true, "BD-08": true, "BD-09": true, "BD-10": true, + "BD-11": true, "BD-12": true, "BD-13": true, "BD-14": true, "BD-15": true, + "BD-16": true, "BD-17": true, "BD-18": true, "BD-19": true, "BD-20": true, + "BD-21": true, "BD-22": true, "BD-23": true, "BD-24": true, "BD-25": true, + "BD-26": true, "BD-27": true, "BD-28": true, "BD-29": true, "BD-30": true, + "BD-31": true, "BD-32": true, "BD-33": true, "BD-34": true, "BD-35": true, + "BD-36": true, "BD-37": true, "BD-38": true, "BD-39": true, "BD-40": true, + "BD-41": true, "BD-42": true, "BD-43": true, "BD-44": true, "BD-45": true, + "BD-46": true, "BD-47": true, "BD-48": true, "BD-49": true, "BD-50": true, + "BD-51": true, "BD-52": true, "BD-53": true, "BD-54": true, "BD-55": true, + "BD-56": true, "BD-57": true, "BD-58": true, "BD-59": true, "BD-60": true, + "BD-61": true, "BD-62": true, "BD-63": true, "BD-64": true, "BD-A": true, + "BD-B": true, "BD-C": true, "BD-D": true, "BD-E": true, "BD-F": true, + "BD-G": true, "BE-BRU": true, "BE-VAN": true, "BE-VBR": true, "BE-VLG": true, + "BE-VLI": true, "BE-VOV": true, "BE-VWV": true, "BE-WAL": true, "BE-WBR": true, + "BE-WHT": true, "BE-WLG": true, "BE-WLX": true, "BE-WNA": true, "BF-01": true, + "BF-02": true, "BF-03": true, "BF-04": true, "BF-05": true, "BF-06": true, + "BF-07": true, "BF-08": true, "BF-09": true, "BF-10": true, "BF-11": true, + "BF-12": true, "BF-13": true, "BF-BAL": true, "BF-BAM": true, "BF-BAN": true, + "BF-BAZ": true, "BF-BGR": true, "BF-BLG": true, "BF-BLK": true, "BF-COM": true, + "BF-GAN": true, "BF-GNA": true, "BF-GOU": true, "BF-HOU": true, "BF-IOB": true, + "BF-KAD": true, "BF-KEN": true, "BF-KMD": true, "BF-KMP": true, "BF-KOP": true, + "BF-KOS": true, "BF-KOT": true, "BF-KOW": true, "BF-LER": true, "BF-LOR": true, + "BF-MOU": true, "BF-NAM": true, "BF-NAO": true, "BF-NAY": true, "BF-NOU": true, + "BF-OUB": true, "BF-OUD": true, "BF-PAS": true, "BF-PON": true, "BF-SEN": true, + "BF-SIS": true, "BF-SMT": true, "BF-SNG": true, "BF-SOM": true, "BF-SOR": true, + "BF-TAP": true, "BF-TUI": true, "BF-YAG": true, "BF-YAT": true, "BF-ZIR": true, + "BF-ZON": true, "BF-ZOU": true, "BG-01": true, "BG-02": true, "BG-03": true, + "BG-04": true, "BG-05": true, "BG-06": true, "BG-07": true, "BG-08": true, + "BG-09": true, "BG-10": true, "BG-11": true, "BG-12": true, "BG-13": true, + "BG-14": true, "BG-15": true, "BG-16": true, "BG-17": true, "BG-18": true, + "BG-19": true, "BG-20": true, "BG-21": true, "BG-22": true, "BG-23": true, + "BG-24": true, "BG-25": true, "BG-26": true, "BG-27": true, "BG-28": true, + "BH-13": true, "BH-14": true, "BH-15": true, "BH-16": true, "BH-17": true, + "BI-BB": true, "BI-BL": true, "BI-BM": true, "BI-BR": true, "BI-CA": true, + "BI-CI": true, "BI-GI": true, "BI-KI": true, "BI-KR": true, "BI-KY": true, + "BI-MA": true, "BI-MU": true, "BI-MW": true, "BI-NG": true, "BI-RM": true, "BI-RT": true, + "BI-RY": true, "BJ-AK": true, "BJ-AL": true, "BJ-AQ": true, "BJ-BO": true, + "BJ-CO": true, "BJ-DO": true, "BJ-KO": true, "BJ-LI": true, "BJ-MO": true, + "BJ-OU": true, "BJ-PL": true, "BJ-ZO": true, "BN-BE": true, "BN-BM": true, + "BN-TE": true, "BN-TU": true, "BO-B": true, "BO-C": true, "BO-H": true, + "BO-L": true, "BO-N": true, "BO-O": true, "BO-P": true, "BO-S": true, + "BO-T": true, "BQ-BO": true, "BQ-SA": true, "BQ-SE": true, "BR-AC": true, + "BR-AL": true, "BR-AM": true, "BR-AP": true, "BR-BA": true, "BR-CE": true, + "BR-DF": true, "BR-ES": true, "BR-FN": true, "BR-GO": true, "BR-MA": true, + "BR-MG": true, "BR-MS": true, "BR-MT": true, "BR-PA": true, "BR-PB": true, + "BR-PE": true, "BR-PI": true, "BR-PR": true, "BR-RJ": true, "BR-RN": true, + "BR-RO": true, "BR-RR": true, "BR-RS": true, "BR-SC": true, "BR-SE": true, + "BR-SP": true, "BR-TO": true, "BS-AK": true, "BS-BI": true, "BS-BP": true, + "BS-BY": true, "BS-CE": true, "BS-CI": true, "BS-CK": true, "BS-CO": true, + "BS-CS": true, "BS-EG": true, "BS-EX": true, "BS-FP": true, "BS-GC": true, + "BS-HI": true, "BS-HT": true, "BS-IN": true, "BS-LI": true, "BS-MC": true, + "BS-MG": true, "BS-MI": true, "BS-NE": true, "BS-NO": true, "BS-NP": true, "BS-NS": true, + "BS-RC": true, "BS-RI": true, "BS-SA": true, "BS-SE": true, "BS-SO": true, + "BS-SS": true, "BS-SW": true, "BS-WG": true, "BT-11": true, "BT-12": true, + "BT-13": true, "BT-14": true, "BT-15": true, "BT-21": true, "BT-22": true, + "BT-23": true, "BT-24": true, "BT-31": true, "BT-32": true, "BT-33": true, + "BT-34": true, "BT-41": true, "BT-42": true, "BT-43": true, "BT-44": true, + "BT-45": true, "BT-GA": true, "BT-TY": true, "BW-CE": true, "BW-CH": true, "BW-GH": true, + "BW-KG": true, "BW-KL": true, "BW-KW": true, "BW-NE": true, "BW-NW": true, + "BW-SE": true, "BW-SO": true, "BY-BR": true, "BY-HM": true, "BY-HO": true, + "BY-HR": true, "BY-MA": true, "BY-MI": true, "BY-VI": true, "BZ-BZ": true, + "BZ-CY": true, "BZ-CZL": true, "BZ-OW": true, "BZ-SC": true, "BZ-TOL": true, + "CA-AB": true, "CA-BC": true, "CA-MB": true, "CA-NB": true, "CA-NL": true, + "CA-NS": true, "CA-NT": true, "CA-NU": true, "CA-ON": true, "CA-PE": true, + "CA-QC": true, "CA-SK": true, "CA-YT": true, "CD-BC": true, "CD-BN": true, + "CD-EQ": true, "CD-HK": true, "CD-IT": true, "CD-KA": true, "CD-KC": true, "CD-KE": true, "CD-KG": true, "CD-KN": true, + "CD-KW": true, "CD-KS": true, "CD-LU": true, "CD-MA": true, "CD-NK": true, "CD-OR": true, "CD-SA": true, "CD-SK": true, + "CD-TA": true, "CD-TO": true, "CF-AC": true, "CF-BB": true, "CF-BGF": true, "CF-BK": true, "CF-HK": true, "CF-HM": true, + "CF-HS": true, "CF-KB": true, "CF-KG": true, "CF-LB": true, "CF-MB": true, + "CF-MP": true, "CF-NM": true, "CF-OP": true, "CF-SE": true, "CF-UK": true, + "CF-VK": true, "CG-11": true, "CG-12": true, "CG-13": true, "CG-14": true, + "CG-15": true, "CG-16": true, "CG-2": true, "CG-5": true, "CG-7": true, "CG-8": true, + "CG-9": true, "CG-BZV": true, "CH-AG": true, "CH-AI": true, "CH-AR": true, + "CH-BE": true, "CH-BL": true, "CH-BS": true, "CH-FR": true, "CH-GE": true, + "CH-GL": true, "CH-GR": true, "CH-JU": true, "CH-LU": true, "CH-NE": true, + "CH-NW": true, "CH-OW": true, "CH-SG": true, "CH-SH": true, "CH-SO": true, + "CH-SZ": true, "CH-TG": true, "CH-TI": true, "CH-UR": true, "CH-VD": true, + "CH-VS": true, "CH-ZG": true, "CH-ZH": true, "CI-AB": true, "CI-BS": true, + "CI-CM": true, "CI-DN": true, "CI-GD": true, "CI-LC": true, "CI-LG": true, + "CI-MG": true, "CI-SM": true, "CI-SV": true, "CI-VB": true, "CI-WR": true, + "CI-YM": true, "CI-ZZ": true, "CL-AI": true, "CL-AN": true, "CL-AP": true, + "CL-AR": true, "CL-AT": true, "CL-BI": true, "CL-CO": true, "CL-LI": true, + "CL-LL": true, "CL-LR": true, "CL-MA": true, "CL-ML": true, "CL-NB": true, "CL-RM": true, + "CL-TA": true, "CL-VS": true, "CM-AD": true, "CM-CE": true, "CM-EN": true, + "CM-ES": true, "CM-LT": true, "CM-NO": true, "CM-NW": true, "CM-OU": true, + "CM-SU": true, "CM-SW": true, "CN-AH": true, "CN-BJ": true, "CN-CQ": true, + "CN-FJ": true, "CN-GS": true, "CN-GD": true, "CN-GX": true, "CN-GZ": true, + "CN-HI": true, "CN-HE": true, "CN-HL": true, "CN-HA": true, "CN-HB": true, + "CN-HN": true, "CN-JS": true, "CN-JX": true, "CN-JL": true, "CN-LN": true, + "CN-NM": true, "CN-NX": true, "CN-QH": true, "CN-SN": true, "CN-SD": true, "CN-SH": true, + "CN-SX": true, "CN-SC": true, "CN-TJ": true, "CN-XJ": true, "CN-XZ": true, "CN-YN": true, + "CN-ZJ": true, "CO-AMA": true, "CO-ANT": true, "CO-ARA": true, "CO-ATL": true, + "CO-BOL": true, "CO-BOY": true, "CO-CAL": true, "CO-CAQ": true, "CO-CAS": true, + "CO-CAU": true, "CO-CES": true, "CO-CHO": true, "CO-COR": true, "CO-CUN": true, + "CO-DC": true, "CO-GUA": true, "CO-GUV": true, "CO-HUI": true, "CO-LAG": true, + "CO-MAG": true, "CO-MET": true, "CO-NAR": true, "CO-NSA": true, "CO-PUT": true, + "CO-QUI": true, "CO-RIS": true, "CO-SAN": true, "CO-SAP": true, "CO-SUC": true, + "CO-TOL": true, "CO-VAC": true, "CO-VAU": true, "CO-VID": true, "CR-A": true, + "CR-C": true, "CR-G": true, "CR-H": true, "CR-L": true, "CR-P": true, + "CR-SJ": true, "CU-01": true, "CU-02": true, "CU-03": true, "CU-04": true, + "CU-05": true, "CU-06": true, "CU-07": true, "CU-08": true, "CU-09": true, + "CU-10": true, "CU-11": true, "CU-12": true, "CU-13": true, "CU-14": true, "CU-15": true, + "CU-16": true, "CU-99": true, "CV-B": true, "CV-BR": true, "CV-BV": true, "CV-CA": true, + "CV-CF": true, "CV-CR": true, "CV-MA": true, "CV-MO": true, "CV-PA": true, + "CV-PN": true, "CV-PR": true, "CV-RB": true, "CV-RG": true, "CV-RS": true, + "CV-S": true, "CV-SD": true, "CV-SF": true, "CV-SL": true, "CV-SM": true, + "CV-SO": true, "CV-SS": true, "CV-SV": true, "CV-TA": true, "CV-TS": true, + "CY-01": true, "CY-02": true, "CY-03": true, "CY-04": true, "CY-05": true, + "CY-06": true, "CZ-10": true, "CZ-101": true, "CZ-102": true, "CZ-103": true, + "CZ-104": true, "CZ-105": true, "CZ-106": true, "CZ-107": true, "CZ-108": true, + "CZ-109": true, "CZ-110": true, "CZ-111": true, "CZ-112": true, "CZ-113": true, + "CZ-114": true, "CZ-115": true, "CZ-116": true, "CZ-117": true, "CZ-118": true, + "CZ-119": true, "CZ-120": true, "CZ-121": true, "CZ-122": true, "CZ-20": true, + "CZ-201": true, "CZ-202": true, "CZ-203": true, "CZ-204": true, "CZ-205": true, + "CZ-206": true, "CZ-207": true, "CZ-208": true, "CZ-209": true, "CZ-20A": true, + "CZ-20B": true, "CZ-20C": true, "CZ-31": true, "CZ-311": true, "CZ-312": true, + "CZ-313": true, "CZ-314": true, "CZ-315": true, "CZ-316": true, "CZ-317": true, + "CZ-32": true, "CZ-321": true, "CZ-322": true, "CZ-323": true, "CZ-324": true, + "CZ-325": true, "CZ-326": true, "CZ-327": true, "CZ-41": true, "CZ-411": true, + "CZ-412": true, "CZ-413": true, "CZ-42": true, "CZ-421": true, "CZ-422": true, + "CZ-423": true, "CZ-424": true, "CZ-425": true, "CZ-426": true, "CZ-427": true, + "CZ-51": true, "CZ-511": true, "CZ-512": true, "CZ-513": true, "CZ-514": true, + "CZ-52": true, "CZ-521": true, "CZ-522": true, "CZ-523": true, "CZ-524": true, + "CZ-525": true, "CZ-53": true, "CZ-531": true, "CZ-532": true, "CZ-533": true, + "CZ-534": true, "CZ-63": true, "CZ-631": true, "CZ-632": true, "CZ-633": true, + "CZ-634": true, "CZ-635": true, "CZ-64": true, "CZ-641": true, "CZ-642": true, + "CZ-643": true, "CZ-644": true, "CZ-645": true, "CZ-646": true, "CZ-647": true, + "CZ-71": true, "CZ-711": true, "CZ-712": true, "CZ-713": true, "CZ-714": true, + "CZ-715": true, "CZ-72": true, "CZ-721": true, "CZ-722": true, "CZ-723": true, + "CZ-724": true, "CZ-80": true, "CZ-801": true, "CZ-802": true, "CZ-803": true, + "CZ-804": true, "CZ-805": true, "CZ-806": true, "DE-BB": true, "DE-BE": true, + "DE-BW": true, "DE-BY": true, "DE-HB": true, "DE-HE": true, "DE-HH": true, + "DE-MV": true, "DE-NI": true, "DE-NW": true, "DE-RP": true, "DE-SH": true, + "DE-SL": true, "DE-SN": true, "DE-ST": true, "DE-TH": true, "DJ-AR": true, + "DJ-AS": true, "DJ-DI": true, "DJ-DJ": true, "DJ-OB": true, "DJ-TA": true, + "DK-81": true, "DK-82": true, "DK-83": true, "DK-84": true, "DK-85": true, + "DM-01": true, "DM-02": true, "DM-03": true, "DM-04": true, "DM-05": true, + "DM-06": true, "DM-07": true, "DM-08": true, "DM-09": true, "DM-10": true, + "DO-01": true, "DO-02": true, "DO-03": true, "DO-04": true, "DO-05": true, + "DO-06": true, "DO-07": true, "DO-08": true, "DO-09": true, "DO-10": true, + "DO-11": true, "DO-12": true, "DO-13": true, "DO-14": true, "DO-15": true, + "DO-16": true, "DO-17": true, "DO-18": true, "DO-19": true, "DO-20": true, + "DO-21": true, "DO-22": true, "DO-23": true, "DO-24": true, "DO-25": true, + "DO-26": true, "DO-27": true, "DO-28": true, "DO-29": true, "DO-30": true, "DO-31": true, + "DZ-01": true, "DZ-02": true, "DZ-03": true, "DZ-04": true, "DZ-05": true, + "DZ-06": true, "DZ-07": true, "DZ-08": true, "DZ-09": true, "DZ-10": true, + "DZ-11": true, "DZ-12": true, "DZ-13": true, "DZ-14": true, "DZ-15": true, + "DZ-16": true, "DZ-17": true, "DZ-18": true, "DZ-19": true, "DZ-20": true, + "DZ-21": true, "DZ-22": true, "DZ-23": true, "DZ-24": true, "DZ-25": true, + "DZ-26": true, "DZ-27": true, "DZ-28": true, "DZ-29": true, "DZ-30": true, + "DZ-31": true, "DZ-32": true, "DZ-33": true, "DZ-34": true, "DZ-35": true, + "DZ-36": true, "DZ-37": true, "DZ-38": true, "DZ-39": true, "DZ-40": true, + "DZ-41": true, "DZ-42": true, "DZ-43": true, "DZ-44": true, "DZ-45": true, + "DZ-46": true, "DZ-47": true, "DZ-48": true, "DZ-49": true, "DZ-51": true, + "DZ-53": true, "DZ-55": true, "DZ-56": true, "DZ-57": true, "EC-A": true, "EC-B": true, + "EC-C": true, "EC-D": true, "EC-E": true, "EC-F": true, "EC-G": true, + "EC-H": true, "EC-I": true, "EC-L": true, "EC-M": true, "EC-N": true, + "EC-O": true, "EC-P": true, "EC-R": true, "EC-S": true, "EC-SD": true, + "EC-SE": true, "EC-T": true, "EC-U": true, "EC-W": true, "EC-X": true, + "EC-Y": true, "EC-Z": true, "EE-37": true, "EE-39": true, "EE-44": true, "EE-45": true, + "EE-49": true, "EE-50": true, "EE-51": true, "EE-52": true, "EE-56": true, "EE-57": true, + "EE-59": true, "EE-60": true, "EE-64": true, "EE-65": true, "EE-67": true, "EE-68": true, + "EE-70": true, "EE-71": true, "EE-74": true, "EE-78": true, "EE-79": true, "EE-81": true, "EE-82": true, + "EE-84": true, "EE-86": true, "EE-87": true, "EG-ALX": true, "EG-ASN": true, "EG-AST": true, + "EG-BA": true, "EG-BH": true, "EG-BNS": true, "EG-C": true, "EG-DK": true, + "EG-DT": true, "EG-FYM": true, "EG-GH": true, "EG-GZ": true, "EG-HU": true, + "EG-IS": true, "EG-JS": true, "EG-KB": true, "EG-KFS": true, "EG-KN": true, + "EG-LX": true, "EG-MN": true, "EG-MNF": true, "EG-MT": true, "EG-PTS": true, "EG-SHG": true, + "EG-SHR": true, "EG-SIN": true, "EG-SU": true, "EG-SUZ": true, "EG-WAD": true, + "ER-AN": true, "ER-DK": true, "ER-DU": true, "ER-GB": true, "ER-MA": true, + "ER-SK": true, "ES-A": true, "ES-AB": true, "ES-AL": true, "ES-AN": true, + "ES-AR": true, "ES-AS": true, "ES-AV": true, "ES-B": true, "ES-BA": true, + "ES-BI": true, "ES-BU": true, "ES-C": true, "ES-CA": true, "ES-CB": true, + "ES-CC": true, "ES-CE": true, "ES-CL": true, "ES-CM": true, "ES-CN": true, + "ES-CO": true, "ES-CR": true, "ES-CS": true, "ES-CT": true, "ES-CU": true, + "ES-EX": true, "ES-GA": true, "ES-GC": true, "ES-GI": true, "ES-GR": true, + "ES-GU": true, "ES-H": true, "ES-HU": true, "ES-IB": true, "ES-J": true, + "ES-L": true, "ES-LE": true, "ES-LO": true, "ES-LU": true, "ES-M": true, + "ES-MA": true, "ES-MC": true, "ES-MD": true, "ES-ML": true, "ES-MU": true, + "ES-NA": true, "ES-NC": true, "ES-O": true, "ES-OR": true, "ES-P": true, + "ES-PM": true, "ES-PO": true, "ES-PV": true, "ES-RI": true, "ES-S": true, + "ES-SA": true, "ES-SE": true, "ES-SG": true, "ES-SO": true, "ES-SS": true, + "ES-T": true, "ES-TE": true, "ES-TF": true, "ES-TO": true, "ES-V": true, + "ES-VA": true, "ES-VC": true, "ES-VI": true, "ES-Z": true, "ES-ZA": true, + "ET-AA": true, "ET-AF": true, "ET-AM": true, "ET-BE": true, "ET-DD": true, + "ET-GA": true, "ET-HA": true, "ET-OR": true, "ET-SN": true, "ET-SO": true, + "ET-TI": true, "FI-01": true, "FI-02": true, "FI-03": true, "FI-04": true, + "FI-05": true, "FI-06": true, "FI-07": true, "FI-08": true, "FI-09": true, + "FI-10": true, "FI-11": true, "FI-12": true, "FI-13": true, "FI-14": true, + "FI-15": true, "FI-16": true, "FI-17": true, "FI-18": true, "FI-19": true, + "FJ-C": true, "FJ-E": true, "FJ-N": true, "FJ-R": true, "FJ-W": true, + "FM-KSA": true, "FM-PNI": true, "FM-TRK": true, "FM-YAP": true, "FR-01": true, + "FR-02": true, "FR-03": true, "FR-04": true, "FR-05": true, "FR-06": true, + "FR-07": true, "FR-08": true, "FR-09": true, "FR-10": true, "FR-11": true, + "FR-12": true, "FR-13": true, "FR-14": true, "FR-15": true, "FR-16": true, + "FR-17": true, "FR-18": true, "FR-19": true, "FR-20R": true, "FR-21": true, "FR-22": true, + "FR-23": true, "FR-24": true, "FR-25": true, "FR-26": true, "FR-27": true, + "FR-28": true, "FR-29": true, "FR-2A": true, "FR-2B": true, "FR-30": true, + "FR-31": true, "FR-32": true, "FR-33": true, "FR-34": true, "FR-35": true, + "FR-36": true, "FR-37": true, "FR-38": true, "FR-39": true, "FR-40": true, + "FR-41": true, "FR-42": true, "FR-43": true, "FR-44": true, "FR-45": true, + "FR-46": true, "FR-47": true, "FR-48": true, "FR-49": true, "FR-50": true, + "FR-51": true, "FR-52": true, "FR-53": true, "FR-54": true, "FR-55": true, + "FR-56": true, "FR-57": true, "FR-58": true, "FR-59": true, "FR-60": true, + "FR-61": true, "FR-62": true, "FR-63": true, "FR-64": true, "FR-65": true, + "FR-66": true, "FR-67": true, "FR-68": true, "FR-69": true, "FR-70": true, + "FR-71": true, "FR-72": true, "FR-73": true, "FR-74": true, "FR-75": true, + "FR-76": true, "FR-77": true, "FR-78": true, "FR-79": true, "FR-80": true, + "FR-81": true, "FR-82": true, "FR-83": true, "FR-84": true, "FR-85": true, + "FR-86": true, "FR-87": true, "FR-88": true, "FR-89": true, "FR-90": true, + "FR-91": true, "FR-92": true, "FR-93": true, "FR-94": true, "FR-95": true, + "FR-ARA": true, "FR-BFC": true, "FR-BL": true, "FR-BRE": true, "FR-COR": true, + "FR-CP": true, "FR-CVL": true, "FR-GES": true, "FR-GF": true, "FR-GP": true, + "FR-GUA": true, "FR-HDF": true, "FR-IDF": true, "FR-LRE": true, "FR-MAY": true, + "FR-MF": true, "FR-MQ": true, "FR-NAQ": true, "FR-NC": true, "FR-NOR": true, + "FR-OCC": true, "FR-PAC": true, "FR-PDL": true, "FR-PF": true, "FR-PM": true, + "FR-RE": true, "FR-TF": true, "FR-WF": true, "FR-YT": true, "GA-1": true, + "GA-2": true, "GA-3": true, "GA-4": true, "GA-5": true, "GA-6": true, + "GA-7": true, "GA-8": true, "GA-9": true, "GB-ABC": true, "GB-ABD": true, + "GB-ABE": true, "GB-AGB": true, "GB-AGY": true, "GB-AND": true, "GB-ANN": true, + "GB-ANS": true, "GB-BAS": true, "GB-BBD": true, "GB-BDF": true, "GB-BDG": true, + "GB-BEN": true, "GB-BEX": true, "GB-BFS": true, "GB-BGE": true, "GB-BGW": true, + "GB-BIR": true, "GB-BKM": true, "GB-BMH": true, "GB-BNE": true, "GB-BNH": true, + "GB-BNS": true, "GB-BOL": true, "GB-BPL": true, "GB-BRC": true, "GB-BRD": true, + "GB-BRY": true, "GB-BST": true, "GB-BUR": true, "GB-CAM": true, "GB-CAY": true, + "GB-CBF": true, "GB-CCG": true, "GB-CGN": true, "GB-CHE": true, "GB-CHW": true, + "GB-CLD": true, "GB-CLK": true, "GB-CMA": true, "GB-CMD": true, "GB-CMN": true, + "GB-CON": true, "GB-COV": true, "GB-CRF": true, "GB-CRY": true, "GB-CWY": true, + "GB-DAL": true, "GB-DBY": true, "GB-DEN": true, "GB-DER": true, "GB-DEV": true, + "GB-DGY": true, "GB-DNC": true, "GB-DND": true, "GB-DOR": true, "GB-DRS": true, + "GB-DUD": true, "GB-DUR": true, "GB-EAL": true, "GB-EAW": true, "GB-EAY": true, + "GB-EDH": true, "GB-EDU": true, "GB-ELN": true, "GB-ELS": true, "GB-ENF": true, + "GB-ENG": true, "GB-ERW": true, "GB-ERY": true, "GB-ESS": true, "GB-ESX": true, + "GB-FAL": true, "GB-FIF": true, "GB-FLN": true, "GB-FMO": true, "GB-GAT": true, + "GB-GBN": true, "GB-GLG": true, "GB-GLS": true, "GB-GRE": true, "GB-GWN": true, + "GB-HAL": true, "GB-HAM": true, "GB-HAV": true, "GB-HCK": true, "GB-HEF": true, + "GB-HIL": true, "GB-HLD": true, "GB-HMF": true, "GB-HNS": true, "GB-HPL": true, + "GB-HRT": true, "GB-HRW": true, "GB-HRY": true, "GB-IOS": true, "GB-IOW": true, + "GB-ISL": true, "GB-IVC": true, "GB-KEC": true, "GB-KEN": true, "GB-KHL": true, + "GB-KIR": true, "GB-KTT": true, "GB-KWL": true, "GB-LAN": true, "GB-LBC": true, + "GB-LBH": true, "GB-LCE": true, "GB-LDS": true, "GB-LEC": true, "GB-LEW": true, + "GB-LIN": true, "GB-LIV": true, "GB-LND": true, "GB-LUT": true, "GB-MAN": true, + "GB-MDB": true, "GB-MDW": true, "GB-MEA": true, "GB-MIK": true, "GD-01": true, + "GB-MLN": true, "GB-MON": true, "GB-MRT": true, "GB-MRY": true, "GB-MTY": true, + "GB-MUL": true, "GB-NAY": true, "GB-NBL": true, "GB-NEL": true, "GB-NET": true, + "GB-NFK": true, "GB-NGM": true, "GB-NIR": true, "GB-NLK": true, "GB-NLN": true, + "GB-NMD": true, "GB-NSM": true, "GB-NTH": true, "GB-NTL": true, "GB-NTT": true, + "GB-NTY": true, "GB-NWM": true, "GB-NWP": true, "GB-NYK": true, "GB-OLD": true, + "GB-ORK": true, "GB-OXF": true, "GB-PEM": true, "GB-PKN": true, "GB-PLY": true, + "GB-POL": true, "GB-POR": true, "GB-POW": true, "GB-PTE": true, "GB-RCC": true, + "GB-RCH": true, "GB-RCT": true, "GB-RDB": true, "GB-RDG": true, "GB-RFW": true, + "GB-RIC": true, "GB-ROT": true, "GB-RUT": true, "GB-SAW": true, "GB-SAY": true, + "GB-SCB": true, "GB-SCT": true, "GB-SFK": true, "GB-SFT": true, "GB-SGC": true, + "GB-SHF": true, "GB-SHN": true, "GB-SHR": true, "GB-SKP": true, "GB-SLF": true, + "GB-SLG": true, "GB-SLK": true, "GB-SND": true, "GB-SOL": true, "GB-SOM": true, + "GB-SOS": true, "GB-SRY": true, "GB-STE": true, "GB-STG": true, "GB-STH": true, + "GB-STN": true, "GB-STS": true, "GB-STT": true, "GB-STY": true, "GB-SWA": true, + "GB-SWD": true, "GB-SWK": true, "GB-TAM": true, "GB-TFW": true, "GB-THR": true, + "GB-TOB": true, "GB-TOF": true, "GB-TRF": true, "GB-TWH": true, "GB-UKM": true, + "GB-VGL": true, "GB-WAR": true, "GB-WBK": true, "GB-WDU": true, "GB-WFT": true, + "GB-WGN": true, "GB-WIL": true, "GB-WKF": true, "GB-WLL": true, "GB-WLN": true, + "GB-WLS": true, "GB-WLV": true, "GB-WND": true, "GB-WNM": true, "GB-WOK": true, + "GB-WOR": true, "GB-WRL": true, "GB-WRT": true, "GB-WRX": true, "GB-WSM": true, + "GB-WSX": true, "GB-YOR": true, "GB-ZET": true, "GD-02": true, "GD-03": true, + "GD-04": true, "GD-05": true, "GD-06": true, "GD-10": true, "GE-AB": true, + "GE-AJ": true, "GE-GU": true, "GE-IM": true, "GE-KA": true, "GE-KK": true, + "GE-MM": true, "GE-RL": true, "GE-SJ": true, "GE-SK": true, "GE-SZ": true, + "GE-TB": true, "GH-AA": true, "GH-AH": true, "GH-AF": true, "GH-BA": true, "GH-BO": true, "GH-BE": true, "GH-CP": true, + "GH-EP": true, "GH-NP": true, "GH-TV": true, "GH-UE": true, "GH-UW": true, + "GH-WP": true, "GL-AV": true, "GL-KU": true, "GL-QA": true, "GL-QT": true, "GL-QE": true, "GL-SM": true, + "GM-B": true, "GM-L": true, "GM-M": true, "GM-N": true, "GM-U": true, + "GM-W": true, "GN-B": true, "GN-BE": true, "GN-BF": true, "GN-BK": true, + "GN-C": true, "GN-CO": true, "GN-D": true, "GN-DB": true, "GN-DI": true, + "GN-DL": true, "GN-DU": true, "GN-F": true, "GN-FA": true, "GN-FO": true, + "GN-FR": true, "GN-GA": true, "GN-GU": true, "GN-K": true, "GN-KA": true, + "GN-KB": true, "GN-KD": true, "GN-KE": true, "GN-KN": true, "GN-KO": true, + "GN-KS": true, "GN-L": true, "GN-LA": true, "GN-LE": true, "GN-LO": true, + "GN-M": true, "GN-MC": true, "GN-MD": true, "GN-ML": true, "GN-MM": true, + "GN-N": true, "GN-NZ": true, "GN-PI": true, "GN-SI": true, "GN-TE": true, + "GN-TO": true, "GN-YO": true, "GQ-AN": true, "GQ-BN": true, "GQ-BS": true, + "GQ-C": true, "GQ-CS": true, "GQ-I": true, "GQ-KN": true, "GQ-LI": true, + "GQ-WN": true, "GR-01": true, "GR-03": true, "GR-04": true, "GR-05": true, + "GR-06": true, "GR-07": true, "GR-11": true, "GR-12": true, "GR-13": true, + "GR-14": true, "GR-15": true, "GR-16": true, "GR-17": true, "GR-21": true, + "GR-22": true, "GR-23": true, "GR-24": true, "GR-31": true, "GR-32": true, + "GR-33": true, "GR-34": true, "GR-41": true, "GR-42": true, "GR-43": true, + "GR-44": true, "GR-51": true, "GR-52": true, "GR-53": true, "GR-54": true, + "GR-55": true, "GR-56": true, "GR-57": true, "GR-58": true, "GR-59": true, + "GR-61": true, "GR-62": true, "GR-63": true, "GR-64": true, "GR-69": true, + "GR-71": true, "GR-72": true, "GR-73": true, "GR-81": true, "GR-82": true, + "GR-83": true, "GR-84": true, "GR-85": true, "GR-91": true, "GR-92": true, + "GR-93": true, "GR-94": true, "GR-A": true, "GR-A1": true, "GR-B": true, + "GR-C": true, "GR-D": true, "GR-E": true, "GR-F": true, "GR-G": true, + "GR-H": true, "GR-I": true, "GR-J": true, "GR-K": true, "GR-L": true, + "GR-M": true, "GT-01": true, "GT-02": true, "GT-03": true, "GT-04": true, + "GT-05": true, "GT-06": true, "GT-07": true, "GT-08": true, "GT-09": true, + "GT-10": true, "GT-11": true, "GT-12": true, "GT-13": true, "GT-14": true, + "GT-15": true, "GT-16": true, "GT-17": true, "GT-18": true, "GT-19": true, + "GT-20": true, "GT-21": true, "GT-22": true, "GW-BA": true, "GW-BL": true, + "GW-BM": true, "GW-BS": true, "GW-CA": true, "GW-GA": true, "GW-L": true, + "GW-N": true, "GW-OI": true, "GW-QU": true, "GW-S": true, "GW-TO": true, + "GY-BA": true, "GY-CU": true, "GY-DE": true, "GY-EB": true, "GY-ES": true, + "GY-MA": true, "GY-PM": true, "GY-PT": true, "GY-UD": true, "GY-UT": true, + "HN-AT": true, "HN-CH": true, "HN-CL": true, "HN-CM": true, "HN-CP": true, + "HN-CR": true, "HN-EP": true, "HN-FM": true, "HN-GD": true, "HN-IB": true, + "HN-IN": true, "HN-LE": true, "HN-LP": true, "HN-OC": true, "HN-OL": true, + "HN-SB": true, "HN-VA": true, "HN-YO": true, "HR-01": true, "HR-02": true, + "HR-03": true, "HR-04": true, "HR-05": true, "HR-06": true, "HR-07": true, + "HR-08": true, "HR-09": true, "HR-10": true, "HR-11": true, "HR-12": true, + "HR-13": true, "HR-14": true, "HR-15": true, "HR-16": true, "HR-17": true, + "HR-18": true, "HR-19": true, "HR-20": true, "HR-21": true, "HT-AR": true, + "HT-CE": true, "HT-GA": true, "HT-ND": true, "HT-NE": true, "HT-NO": true, "HT-NI": true, + "HT-OU": true, "HT-SD": true, "HT-SE": true, "HU-BA": true, "HU-BC": true, + "HU-BE": true, "HU-BK": true, "HU-BU": true, "HU-BZ": true, "HU-CS": true, + "HU-DE": true, "HU-DU": true, "HU-EG": true, "HU-ER": true, "HU-FE": true, + "HU-GS": true, "HU-GY": true, "HU-HB": true, "HU-HE": true, "HU-HV": true, + "HU-JN": true, "HU-KE": true, "HU-KM": true, "HU-KV": true, "HU-MI": true, + "HU-NK": true, "HU-NO": true, "HU-NY": true, "HU-PE": true, "HU-PS": true, + "HU-SD": true, "HU-SF": true, "HU-SH": true, "HU-SK": true, "HU-SN": true, + "HU-SO": true, "HU-SS": true, "HU-ST": true, "HU-SZ": true, "HU-TB": true, + "HU-TO": true, "HU-VA": true, "HU-VE": true, "HU-VM": true, "HU-ZA": true, + "HU-ZE": true, "ID-AC": true, "ID-BA": true, "ID-BB": true, "ID-BE": true, + "ID-BT": true, "ID-GO": true, "ID-IJ": true, "ID-JA": true, "ID-JB": true, + "ID-JI": true, "ID-JK": true, "ID-JT": true, "ID-JW": true, "ID-KA": true, + "ID-KB": true, "ID-KI": true, "ID-KU": true, "ID-KR": true, "ID-KS": true, + "ID-KT": true, "ID-LA": true, "ID-MA": true, "ID-ML": true, "ID-MU": true, + "ID-NB": true, "ID-NT": true, "ID-NU": true, "ID-PA": true, "ID-PB": true, + "ID-PE": true, "ID-PP": true, "ID-PS": true, "ID-PT": true, "ID-RI": true, + "ID-SA": true, "ID-SB": true, "ID-SG": true, "ID-SL": true, "ID-SM": true, + "ID-SN": true, "ID-SR": true, "ID-SS": true, "ID-ST": true, "ID-SU": true, + "ID-YO": true, "IE-C": true, "IE-CE": true, "IE-CN": true, "IE-CO": true, + "IE-CW": true, "IE-D": true, "IE-DL": true, "IE-G": true, "IE-KE": true, + "IE-KK": true, "IE-KY": true, "IE-L": true, "IE-LD": true, "IE-LH": true, + "IE-LK": true, "IE-LM": true, "IE-LS": true, "IE-M": true, "IE-MH": true, + "IE-MN": true, "IE-MO": true, "IE-OY": true, "IE-RN": true, "IE-SO": true, + "IE-TA": true, "IE-U": true, "IE-WD": true, "IE-WH": true, "IE-WW": true, + "IE-WX": true, "IL-D": true, "IL-HA": true, "IL-JM": true, "IL-M": true, + "IL-TA": true, "IL-Z": true, "IN-AN": true, "IN-AP": true, "IN-AR": true, + "IN-AS": true, "IN-BR": true, "IN-CH": true, "IN-CT": true, "IN-DH": true, + "IN-DL": true, "IN-DN": true, "IN-GA": true, "IN-GJ": true, "IN-HP": true, + "IN-HR": true, "IN-JH": true, "IN-JK": true, "IN-KA": true, "IN-KL": true, + "IN-LD": true, "IN-MH": true, "IN-ML": true, "IN-MN": true, "IN-MP": true, + "IN-MZ": true, "IN-NL": true, "IN-TG": true, "IN-OR": true, "IN-PB": true, "IN-PY": true, + "IN-RJ": true, "IN-SK": true, "IN-TN": true, "IN-TR": true, "IN-UP": true, + "IN-UT": true, "IN-WB": true, "IQ-AN": true, "IQ-AR": true, "IQ-BA": true, + "IQ-BB": true, "IQ-BG": true, "IQ-DA": true, "IQ-DI": true, "IQ-DQ": true, + "IQ-KA": true, "IQ-KI": true, "IQ-MA": true, "IQ-MU": true, "IQ-NA": true, "IQ-NI": true, + "IQ-QA": true, "IQ-SD": true, "IQ-SW": true, "IQ-SU": true, "IQ-TS": true, "IQ-WA": true, + "IR-00": true, "IR-01": true, "IR-02": true, "IR-03": true, "IR-04": true, "IR-05": true, + "IR-06": true, "IR-07": true, "IR-08": true, "IR-09": true, "IR-10": true, "IR-11": true, + "IR-12": true, "IR-13": true, "IR-14": true, "IR-15": true, "IR-16": true, + "IR-17": true, "IR-18": true, "IR-19": true, "IR-20": true, "IR-21": true, + "IR-22": true, "IR-23": true, "IR-24": true, "IR-25": true, "IR-26": true, + "IR-27": true, "IR-28": true, "IR-29": true, "IR-30": true, "IR-31": true, + "IS-0": true, "IS-1": true, "IS-2": true, "IS-3": true, "IS-4": true, + "IS-5": true, "IS-6": true, "IS-7": true, "IS-8": true, "IT-21": true, + "IT-23": true, "IT-25": true, "IT-32": true, "IT-34": true, "IT-36": true, + "IT-42": true, "IT-45": true, "IT-52": true, "IT-55": true, "IT-57": true, + "IT-62": true, "IT-65": true, "IT-67": true, "IT-72": true, "IT-75": true, + "IT-77": true, "IT-78": true, "IT-82": true, "IT-88": true, "IT-AG": true, + "IT-AL": true, "IT-AN": true, "IT-AO": true, "IT-AP": true, "IT-AQ": true, + "IT-AR": true, "IT-AT": true, "IT-AV": true, "IT-BA": true, "IT-BG": true, + "IT-BI": true, "IT-BL": true, "IT-BN": true, "IT-BO": true, "IT-BR": true, + "IT-BS": true, "IT-BT": true, "IT-BZ": true, "IT-CA": true, "IT-CB": true, + "IT-CE": true, "IT-CH": true, "IT-CI": true, "IT-CL": true, "IT-CN": true, + "IT-CO": true, "IT-CR": true, "IT-CS": true, "IT-CT": true, "IT-CZ": true, + "IT-EN": true, "IT-FC": true, "IT-FE": true, "IT-FG": true, "IT-FI": true, + "IT-FM": true, "IT-FR": true, "IT-GE": true, "IT-GO": true, "IT-GR": true, + "IT-IM": true, "IT-IS": true, "IT-KR": true, "IT-LC": true, "IT-LE": true, + "IT-LI": true, "IT-LO": true, "IT-LT": true, "IT-LU": true, "IT-MB": true, + "IT-MC": true, "IT-ME": true, "IT-MI": true, "IT-MN": true, "IT-MO": true, + "IT-MS": true, "IT-MT": true, "IT-NA": true, "IT-NO": true, "IT-NU": true, + "IT-OG": true, "IT-OR": true, "IT-OT": true, "IT-PA": true, "IT-PC": true, + "IT-PD": true, "IT-PE": true, "IT-PG": true, "IT-PI": true, "IT-PN": true, + "IT-PO": true, "IT-PR": true, "IT-PT": true, "IT-PU": true, "IT-PV": true, + "IT-PZ": true, "IT-RA": true, "IT-RC": true, "IT-RE": true, "IT-RG": true, + "IT-RI": true, "IT-RM": true, "IT-RN": true, "IT-RO": true, "IT-SA": true, + "IT-SI": true, "IT-SO": true, "IT-SP": true, "IT-SR": true, "IT-SS": true, + "IT-SV": true, "IT-TA": true, "IT-TE": true, "IT-TN": true, "IT-TO": true, + "IT-TP": true, "IT-TR": true, "IT-TS": true, "IT-TV": true, "IT-UD": true, + "IT-VA": true, "IT-VB": true, "IT-VC": true, "IT-VE": true, "IT-VI": true, + "IT-VR": true, "IT-VS": true, "IT-VT": true, "IT-VV": true, "JM-01": true, + "JM-02": true, "JM-03": true, "JM-04": true, "JM-05": true, "JM-06": true, + "JM-07": true, "JM-08": true, "JM-09": true, "JM-10": true, "JM-11": true, + "JM-12": true, "JM-13": true, "JM-14": true, "JO-AJ": true, "JO-AM": true, + "JO-AQ": true, "JO-AT": true, "JO-AZ": true, "JO-BA": true, "JO-IR": true, + "JO-JA": true, "JO-KA": true, "JO-MA": true, "JO-MD": true, "JO-MN": true, + "JP-01": true, "JP-02": true, "JP-03": true, "JP-04": true, "JP-05": true, + "JP-06": true, "JP-07": true, "JP-08": true, "JP-09": true, "JP-10": true, + "JP-11": true, "JP-12": true, "JP-13": true, "JP-14": true, "JP-15": true, + "JP-16": true, "JP-17": true, "JP-18": true, "JP-19": true, "JP-20": true, + "JP-21": true, "JP-22": true, "JP-23": true, "JP-24": true, "JP-25": true, + "JP-26": true, "JP-27": true, "JP-28": true, "JP-29": true, "JP-30": true, + "JP-31": true, "JP-32": true, "JP-33": true, "JP-34": true, "JP-35": true, + "JP-36": true, "JP-37": true, "JP-38": true, "JP-39": true, "JP-40": true, + "JP-41": true, "JP-42": true, "JP-43": true, "JP-44": true, "JP-45": true, + "JP-46": true, "JP-47": true, "KE-01": true, "KE-02": true, "KE-03": true, + "KE-04": true, "KE-05": true, "KE-06": true, "KE-07": true, "KE-08": true, + "KE-09": true, "KE-10": true, "KE-11": true, "KE-12": true, "KE-13": true, + "KE-14": true, "KE-15": true, "KE-16": true, "KE-17": true, "KE-18": true, + "KE-19": true, "KE-20": true, "KE-21": true, "KE-22": true, "KE-23": true, + "KE-24": true, "KE-25": true, "KE-26": true, "KE-27": true, "KE-28": true, + "KE-29": true, "KE-30": true, "KE-31": true, "KE-32": true, "KE-33": true, + "KE-34": true, "KE-35": true, "KE-36": true, "KE-37": true, "KE-38": true, + "KE-39": true, "KE-40": true, "KE-41": true, "KE-42": true, "KE-43": true, + "KE-44": true, "KE-45": true, "KE-46": true, "KE-47": true, "KG-B": true, + "KG-C": true, "KG-GB": true, "KG-GO": true, "KG-J": true, "KG-N": true, "KG-O": true, + "KG-T": true, "KG-Y": true, "KH-1": true, "KH-10": true, "KH-11": true, + "KH-12": true, "KH-13": true, "KH-14": true, "KH-15": true, "KH-16": true, + "KH-17": true, "KH-18": true, "KH-19": true, "KH-2": true, "KH-20": true, + "KH-21": true, "KH-22": true, "KH-23": true, "KH-24": true, "KH-3": true, + "KH-4": true, "KH-5": true, "KH-6": true, "KH-7": true, "KH-8": true, + "KH-9": true, "KI-G": true, "KI-L": true, "KI-P": true, "KM-A": true, + "KM-G": true, "KM-M": true, "KN-01": true, "KN-02": true, "KN-03": true, + "KN-04": true, "KN-05": true, "KN-06": true, "KN-07": true, "KN-08": true, + "KN-09": true, "KN-10": true, "KN-11": true, "KN-12": true, "KN-13": true, + "KN-15": true, "KN-K": true, "KN-N": true, "KP-01": true, "KP-02": true, + "KP-03": true, "KP-04": true, "KP-05": true, "KP-06": true, "KP-07": true, + "KP-08": true, "KP-09": true, "KP-10": true, "KP-13": true, "KR-11": true, + "KR-26": true, "KR-27": true, "KR-28": true, "KR-29": true, "KR-30": true, + "KR-31": true, "KR-41": true, "KR-42": true, "KR-43": true, "KR-44": true, + "KR-45": true, "KR-46": true, "KR-47": true, "KR-48": true, "KR-49": true, + "KW-AH": true, "KW-FA": true, "KW-HA": true, "KW-JA": true, "KW-KU": true, + "KW-MU": true, "KZ-10": true, "KZ-75": true, "KZ-19": true, "KZ-11": true, + "KZ-15": true, "KZ-71": true, "KZ-23": true, "KZ-27": true, "KZ-47": true, + "KZ-55": true, "KZ-35": true, "KZ-39": true, "KZ-43": true, "KZ-63": true, + "KZ-79": true, "KZ-59": true, "KZ-61": true, "KZ-62": true, "KZ-31": true, + "KZ-33": true, "LA-AT": true, "LA-BK": true, "LA-BL": true, + "LA-CH": true, "LA-HO": true, "LA-KH": true, "LA-LM": true, "LA-LP": true, + "LA-OU": true, "LA-PH": true, "LA-SL": true, "LA-SV": true, "LA-VI": true, + "LA-VT": true, "LA-XA": true, "LA-XE": true, "LA-XI": true, "LA-XS": true, + "LB-AK": true, "LB-AS": true, "LB-BA": true, "LB-BH": true, "LB-BI": true, + "LB-JA": true, "LB-JL": true, "LB-NA": true, "LC-01": true, "LC-02": true, + "LC-03": true, "LC-05": true, "LC-06": true, "LC-07": true, "LC-08": true, + "LC-10": true, "LC-11": true, "LI-01": true, "LI-02": true, + "LI-03": true, "LI-04": true, "LI-05": true, "LI-06": true, "LI-07": true, + "LI-08": true, "LI-09": true, "LI-10": true, "LI-11": true, "LK-1": true, + "LK-11": true, "LK-12": true, "LK-13": true, "LK-2": true, "LK-21": true, + "LK-22": true, "LK-23": true, "LK-3": true, "LK-31": true, "LK-32": true, + "LK-33": true, "LK-4": true, "LK-41": true, "LK-42": true, "LK-43": true, + "LK-44": true, "LK-45": true, "LK-5": true, "LK-51": true, "LK-52": true, + "LK-53": true, "LK-6": true, "LK-61": true, "LK-62": true, "LK-7": true, + "LK-71": true, "LK-72": true, "LK-8": true, "LK-81": true, "LK-82": true, + "LK-9": true, "LK-91": true, "LK-92": true, "LR-BG": true, "LR-BM": true, + "LR-CM": true, "LR-GB": true, "LR-GG": true, "LR-GK": true, "LR-LO": true, + "LR-MG": true, "LR-MO": true, "LR-MY": true, "LR-NI": true, "LR-RI": true, + "LR-SI": true, "LS-A": true, "LS-B": true, "LS-C": true, "LS-D": true, + "LS-E": true, "LS-F": true, "LS-G": true, "LS-H": true, "LS-J": true, + "LS-K": true, "LT-AL": true, "LT-KL": true, "LT-KU": true, "LT-MR": true, + "LT-PN": true, "LT-SA": true, "LT-TA": true, "LT-TE": true, "LT-UT": true, + "LT-VL": true, "LU-CA": true, "LU-CL": true, "LU-DI": true, "LU-EC": true, + "LU-ES": true, "LU-GR": true, "LU-LU": true, "LU-ME": true, "LU-RD": true, + "LU-RM": true, "LU-VD": true, "LU-WI": true, "LU-D": true, "LU-G": true, "LU-L": true, + "LV-001": true, "LV-111": true, "LV-112": true, "LV-113": true, + "LV-002": true, "LV-003": true, "LV-004": true, "LV-005": true, "LV-006": true, + "LV-007": true, "LV-008": true, "LV-009": true, "LV-010": true, "LV-011": true, + "LV-012": true, "LV-013": true, "LV-014": true, "LV-015": true, "LV-016": true, + "LV-017": true, "LV-018": true, "LV-019": true, "LV-020": true, "LV-021": true, + "LV-022": true, "LV-023": true, "LV-024": true, "LV-025": true, "LV-026": true, + "LV-027": true, "LV-028": true, "LV-029": true, "LV-030": true, "LV-031": true, + "LV-032": true, "LV-033": true, "LV-034": true, "LV-035": true, "LV-036": true, + "LV-037": true, "LV-038": true, "LV-039": true, "LV-040": true, "LV-041": true, + "LV-042": true, "LV-043": true, "LV-044": true, "LV-045": true, "LV-046": true, + "LV-047": true, "LV-048": true, "LV-049": true, "LV-050": true, "LV-051": true, + "LV-052": true, "LV-053": true, "LV-054": true, "LV-055": true, "LV-056": true, + "LV-057": true, "LV-058": true, "LV-059": true, "LV-060": true, "LV-061": true, + "LV-062": true, "LV-063": true, "LV-064": true, "LV-065": true, "LV-066": true, + "LV-067": true, "LV-068": true, "LV-069": true, "LV-070": true, "LV-071": true, + "LV-072": true, "LV-073": true, "LV-074": true, "LV-075": true, "LV-076": true, + "LV-077": true, "LV-078": true, "LV-079": true, "LV-080": true, "LV-081": true, + "LV-082": true, "LV-083": true, "LV-084": true, "LV-085": true, "LV-086": true, + "LV-087": true, "LV-088": true, "LV-089": true, "LV-090": true, "LV-091": true, + "LV-092": true, "LV-093": true, "LV-094": true, "LV-095": true, "LV-096": true, + "LV-097": true, "LV-098": true, "LV-099": true, "LV-100": true, "LV-101": true, + "LV-102": true, "LV-103": true, "LV-104": true, "LV-105": true, "LV-106": true, + "LV-107": true, "LV-108": true, "LV-109": true, "LV-110": true, "LV-DGV": true, + "LV-JEL": true, "LV-JKB": true, "LV-JUR": true, "LV-LPX": true, "LV-REZ": true, + "LV-RIX": true, "LV-VEN": true, "LV-VMR": true, "LY-BA": true, "LY-BU": true, + "LY-DR": true, "LY-GT": true, "LY-JA": true, "LY-JB": true, "LY-JG": true, + "LY-JI": true, "LY-JU": true, "LY-KF": true, "LY-MB": true, "LY-MI": true, + "LY-MJ": true, "LY-MQ": true, "LY-NL": true, "LY-NQ": true, "LY-SB": true, + "LY-SR": true, "LY-TB": true, "LY-WA": true, "LY-WD": true, "LY-WS": true, + "LY-ZA": true, "MA-01": true, "MA-02": true, "MA-03": true, "MA-04": true, + "MA-05": true, "MA-06": true, "MA-07": true, "MA-08": true, "MA-09": true, + "MA-10": true, "MA-11": true, "MA-12": true, "MA-13": true, "MA-14": true, + "MA-15": true, "MA-16": true, "MA-AGD": true, "MA-AOU": true, "MA-ASZ": true, + "MA-AZI": true, "MA-BEM": true, "MA-BER": true, "MA-BES": true, "MA-BOD": true, + "MA-BOM": true, "MA-CAS": true, "MA-CHE": true, "MA-CHI": true, "MA-CHT": true, + "MA-ERR": true, "MA-ESI": true, "MA-ESM": true, "MA-FAH": true, "MA-FES": true, + "MA-FIG": true, "MA-GUE": true, "MA-HAJ": true, "MA-HAO": true, "MA-HOC": true, + "MA-IFR": true, "MA-INE": true, "MA-JDI": true, "MA-JRA": true, "MA-KEN": true, + "MA-KES": true, "MA-KHE": true, "MA-KHN": true, "MA-KHO": true, "MA-LAA": true, + "MA-LAR": true, "MA-MED": true, "MA-MEK": true, "MA-MMD": true, "MA-MMN": true, + "MA-MOH": true, "MA-MOU": true, "MA-NAD": true, "MA-NOU": true, "MA-OUA": true, + "MA-OUD": true, "MA-OUJ": true, "MA-RAB": true, "MA-SAF": true, "MA-SAL": true, + "MA-SEF": true, "MA-SET": true, "MA-SIK": true, "MA-SKH": true, "MA-SYB": true, + "MA-TAI": true, "MA-TAO": true, "MA-TAR": true, "MA-TAT": true, "MA-TAZ": true, + "MA-TET": true, "MA-TIZ": true, "MA-TNG": true, "MA-TNT": true, "MA-ZAG": true, + "MC-CL": true, "MC-CO": true, "MC-FO": true, "MC-GA": true, "MC-JE": true, + "MC-LA": true, "MC-MA": true, "MC-MC": true, "MC-MG": true, "MC-MO": true, + "MC-MU": true, "MC-PH": true, "MC-SD": true, "MC-SO": true, "MC-SP": true, + "MC-SR": true, "MC-VR": true, "MD-AN": true, "MD-BA": true, "MD-BD": true, + "MD-BR": true, "MD-BS": true, "MD-CA": true, "MD-CL": true, "MD-CM": true, + "MD-CR": true, "MD-CS": true, "MD-CT": true, "MD-CU": true, "MD-DO": true, + "MD-DR": true, "MD-DU": true, "MD-ED": true, "MD-FA": true, "MD-FL": true, + "MD-GA": true, "MD-GL": true, "MD-HI": true, "MD-IA": true, "MD-LE": true, + "MD-NI": true, "MD-OC": true, "MD-OR": true, "MD-RE": true, "MD-RI": true, + "MD-SD": true, "MD-SI": true, "MD-SN": true, "MD-SO": true, "MD-ST": true, + "MD-SV": true, "MD-TA": true, "MD-TE": true, "MD-UN": true, "ME-01": true, + "ME-02": true, "ME-03": true, "ME-04": true, "ME-05": true, "ME-06": true, + "ME-07": true, "ME-08": true, "ME-09": true, "ME-10": true, "ME-11": true, + "ME-12": true, "ME-13": true, "ME-14": true, "ME-15": true, "ME-16": true, + "ME-17": true, "ME-18": true, "ME-19": true, "ME-20": true, "ME-21": true, "ME-24": true, + "MG-A": true, "MG-D": true, "MG-F": true, "MG-M": true, "MG-T": true, + "MG-U": true, "MH-ALK": true, "MH-ALL": true, "MH-ARN": true, "MH-AUR": true, + "MH-EBO": true, "MH-ENI": true, "MH-JAB": true, "MH-JAL": true, "MH-KIL": true, + "MH-KWA": true, "MH-L": true, "MH-LAE": true, "MH-LIB": true, "MH-LIK": true, + "MH-MAJ": true, "MH-MAL": true, "MH-MEJ": true, "MH-MIL": true, "MH-NMK": true, + "MH-NMU": true, "MH-RON": true, "MH-T": true, "MH-UJA": true, "MH-UTI": true, + "MH-WTJ": true, "MH-WTN": true, "MK-101": true, "MK-102": true, "MK-103": true, + "MK-104": true, "MK-105": true, + "MK-106": true, "MK-107": true, "MK-108": true, "MK-109": true, "MK-201": true, + "MK-202": true, "MK-205": true, "MK-206": true, "MK-207": true, "MK-208": true, + "MK-209": true, "MK-210": true, "MK-211": true, "MK-301": true, "MK-303": true, + "MK-307": true, "MK-308": true, "MK-310": true, "MK-311": true, "MK-312": true, + "MK-401": true, "MK-402": true, "MK-403": true, "MK-404": true, "MK-405": true, + "MK-406": true, "MK-408": true, "MK-409": true, "MK-410": true, "MK-501": true, + "MK-502": true, "MK-503": true, "MK-505": true, "MK-506": true, "MK-507": true, + "MK-508": true, "MK-509": true, "MK-601": true, "MK-602": true, "MK-604": true, + "MK-605": true, "MK-606": true, "MK-607": true, "MK-608": true, "MK-609": true, + "MK-701": true, "MK-702": true, "MK-703": true, "MK-704": true, "MK-705": true, + "MK-803": true, "MK-804": true, "MK-806": true, "MK-807": true, "MK-809": true, + "MK-810": true, "MK-811": true, "MK-812": true, "MK-813": true, "MK-814": true, + "MK-816": true, "ML-1": true, "ML-2": true, "ML-3": true, "ML-4": true, + "ML-5": true, "ML-6": true, "ML-7": true, "ML-8": true, "ML-BKO": true, + "MM-01": true, "MM-02": true, "MM-03": true, "MM-04": true, "MM-05": true, + "MM-06": true, "MM-07": true, "MM-11": true, "MM-12": true, "MM-13": true, + "MM-14": true, "MM-15": true, "MM-16": true, "MM-17": true, "MM-18": true, "MN-035": true, + "MN-037": true, "MN-039": true, "MN-041": true, "MN-043": true, "MN-046": true, + "MN-047": true, "MN-049": true, "MN-051": true, "MN-053": true, "MN-055": true, + "MN-057": true, "MN-059": true, "MN-061": true, "MN-063": true, "MN-064": true, + "MN-065": true, "MN-067": true, "MN-069": true, "MN-071": true, "MN-073": true, + "MN-1": true, "MR-01": true, "MR-02": true, "MR-03": true, "MR-04": true, + "MR-05": true, "MR-06": true, "MR-07": true, "MR-08": true, "MR-09": true, + "MR-10": true, "MR-11": true, "MR-12": true, "MR-13": true, "MR-NKC": true, "MT-01": true, + "MT-02": true, "MT-03": true, "MT-04": true, "MT-05": true, "MT-06": true, + "MT-07": true, "MT-08": true, "MT-09": true, "MT-10": true, "MT-11": true, + "MT-12": true, "MT-13": true, "MT-14": true, "MT-15": true, "MT-16": true, + "MT-17": true, "MT-18": true, "MT-19": true, "MT-20": true, "MT-21": true, + "MT-22": true, "MT-23": true, "MT-24": true, "MT-25": true, "MT-26": true, + "MT-27": true, "MT-28": true, "MT-29": true, "MT-30": true, "MT-31": true, + "MT-32": true, "MT-33": true, "MT-34": true, "MT-35": true, "MT-36": true, + "MT-37": true, "MT-38": true, "MT-39": true, "MT-40": true, "MT-41": true, + "MT-42": true, "MT-43": true, "MT-44": true, "MT-45": true, "MT-46": true, + "MT-47": true, "MT-48": true, "MT-49": true, "MT-50": true, "MT-51": true, + "MT-52": true, "MT-53": true, "MT-54": true, "MT-55": true, "MT-56": true, + "MT-57": true, "MT-58": true, "MT-59": true, "MT-60": true, "MT-61": true, + "MT-62": true, "MT-63": true, "MT-64": true, "MT-65": true, "MT-66": true, + "MT-67": true, "MT-68": true, "MU-AG": true, "MU-BL": true, "MU-BR": true, + "MU-CC": true, "MU-CU": true, "MU-FL": true, "MU-GP": true, "MU-MO": true, + "MU-PA": true, "MU-PL": true, "MU-PU": true, "MU-PW": true, "MU-QB": true, + "MU-RO": true, "MU-RP": true, "MU-RR": true, "MU-SA": true, "MU-VP": true, "MV-00": true, + "MV-01": true, "MV-02": true, "MV-03": true, "MV-04": true, "MV-05": true, + "MV-07": true, "MV-08": true, "MV-12": true, "MV-13": true, "MV-14": true, + "MV-17": true, "MV-20": true, "MV-23": true, "MV-24": true, "MV-25": true, + "MV-26": true, "MV-27": true, "MV-28": true, "MV-29": true, "MV-CE": true, + "MV-MLE": true, "MV-NC": true, "MV-NO": true, "MV-SC": true, "MV-SU": true, + "MV-UN": true, "MV-US": true, "MW-BA": true, "MW-BL": true, "MW-C": true, + "MW-CK": true, "MW-CR": true, "MW-CT": true, "MW-DE": true, "MW-DO": true, + "MW-KR": true, "MW-KS": true, "MW-LI": true, "MW-LK": true, "MW-MC": true, + "MW-MG": true, "MW-MH": true, "MW-MU": true, "MW-MW": true, "MW-MZ": true, + "MW-N": true, "MW-NB": true, "MW-NE": true, "MW-NI": true, "MW-NK": true, + "MW-NS": true, "MW-NU": true, "MW-PH": true, "MW-RU": true, "MW-S": true, + "MW-SA": true, "MW-TH": true, "MW-ZO": true, "MX-AGU": true, "MX-BCN": true, + "MX-BCS": true, "MX-CAM": true, "MX-CHH": true, "MX-CHP": true, "MX-COA": true, + "MX-COL": true, "MX-CMX": true, "MX-DIF": true, "MX-DUR": true, "MX-GRO": true, "MX-GUA": true, + "MX-HID": true, "MX-JAL": true, "MX-MEX": true, "MX-MIC": true, "MX-MOR": true, + "MX-NAY": true, "MX-NLE": true, "MX-OAX": true, "MX-PUE": true, "MX-QUE": true, + "MX-ROO": true, "MX-SIN": true, "MX-SLP": true, "MX-SON": true, "MX-TAB": true, + "MX-TAM": true, "MX-TLA": true, "MX-VER": true, "MX-YUC": true, "MX-ZAC": true, + "MY-01": true, "MY-02": true, "MY-03": true, "MY-04": true, "MY-05": true, + "MY-06": true, "MY-07": true, "MY-08": true, "MY-09": true, "MY-10": true, + "MY-11": true, "MY-12": true, "MY-13": true, "MY-14": true, "MY-15": true, + "MY-16": true, "MZ-A": true, "MZ-B": true, "MZ-G": true, "MZ-I": true, + "MZ-L": true, "MZ-MPM": true, "MZ-N": true, "MZ-P": true, "MZ-Q": true, + "MZ-S": true, "MZ-T": true, "NA-CA": true, "NA-ER": true, "NA-HA": true, + "NA-KA": true, "NA-KE": true, "NA-KH": true, "NA-KU": true, "NA-KW": true, "NA-OD": true, "NA-OH": true, + "NA-OK": true, "NA-ON": true, "NA-OS": true, "NA-OT": true, "NA-OW": true, + "NE-1": true, "NE-2": true, "NE-3": true, "NE-4": true, "NE-5": true, + "NE-6": true, "NE-7": true, "NE-8": true, "NG-AB": true, "NG-AD": true, + "NG-AK": true, "NG-AN": true, "NG-BA": true, "NG-BE": true, "NG-BO": true, + "NG-BY": true, "NG-CR": true, "NG-DE": true, "NG-EB": true, "NG-ED": true, + "NG-EK": true, "NG-EN": true, "NG-FC": true, "NG-GO": true, "NG-IM": true, + "NG-JI": true, "NG-KD": true, "NG-KE": true, "NG-KN": true, "NG-KO": true, + "NG-KT": true, "NG-KW": true, "NG-LA": true, "NG-NA": true, "NG-NI": true, + "NG-OG": true, "NG-ON": true, "NG-OS": true, "NG-OY": true, "NG-PL": true, + "NG-RI": true, "NG-SO": true, "NG-TA": true, "NG-YO": true, "NG-ZA": true, + "NI-AN": true, "NI-AS": true, "NI-BO": true, "NI-CA": true, "NI-CI": true, + "NI-CO": true, "NI-ES": true, "NI-GR": true, "NI-JI": true, "NI-LE": true, + "NI-MD": true, "NI-MN": true, "NI-MS": true, "NI-MT": true, "NI-NS": true, + "NI-RI": true, "NI-SJ": true, "NL-AW": true, "NL-BQ1": true, "NL-BQ2": true, + "NL-BQ3": true, "NL-CW": true, "NL-DR": true, "NL-FL": true, "NL-FR": true, + "NL-GE": true, "NL-GR": true, "NL-LI": true, "NL-NB": true, "NL-NH": true, + "NL-OV": true, "NL-SX": true, "NL-UT": true, "NL-ZE": true, "NL-ZH": true, + "NO-03": true, "NO-11": true, "NO-15": true, "NO-16": true, "NO-17": true, + "NO-18": true, "NO-21": true, "NO-30": true, "NO-34": true, "NO-38": true, + "NO-42": true, "NO-46": true, "NO-50": true, "NO-54": true, + "NO-22": true, "NP-1": true, "NP-2": true, "NP-3": true, "NP-4": true, + "NP-5": true, "NP-BA": true, "NP-BH": true, "NP-DH": true, "NP-GA": true, + "NP-JA": true, "NP-KA": true, "NP-KO": true, "NP-LU": true, "NP-MA": true, + "NP-ME": true, "NP-NA": true, "NP-RA": true, "NP-SA": true, "NP-SE": true, + "NR-01": true, "NR-02": true, "NR-03": true, "NR-04": true, "NR-05": true, + "NR-06": true, "NR-07": true, "NR-08": true, "NR-09": true, "NR-10": true, + "NR-11": true, "NR-12": true, "NR-13": true, "NR-14": true, "NZ-AUK": true, + "NZ-BOP": true, "NZ-CAN": true, "NZ-CIT": true, "NZ-GIS": true, "NZ-HKB": true, + "NZ-MBH": true, "NZ-MWT": true, "NZ-N": true, "NZ-NSN": true, "NZ-NTL": true, + "NZ-OTA": true, "NZ-S": true, "NZ-STL": true, "NZ-TAS": true, "NZ-TKI": true, + "NZ-WGN": true, "NZ-WKO": true, "NZ-WTC": true, "OM-BA": true, "OM-BS": true, "OM-BU": true, "OM-BJ": true, + "OM-DA": true, "OM-MA": true, "OM-MU": true, "OM-SH": true, "OM-SJ": true, "OM-SS": true, "OM-WU": true, + "OM-ZA": true, "OM-ZU": true, "PA-1": true, "PA-2": true, "PA-3": true, + "PA-4": true, "PA-5": true, "PA-6": true, "PA-7": true, "PA-8": true, + "PA-9": true, "PA-EM": true, "PA-KY": true, "PA-NB": true, "PE-AMA": true, + "PE-ANC": true, "PE-APU": true, "PE-ARE": true, "PE-AYA": true, "PE-CAJ": true, + "PE-CAL": true, "PE-CUS": true, "PE-HUC": true, "PE-HUV": true, "PE-ICA": true, + "PE-JUN": true, "PE-LAL": true, "PE-LAM": true, "PE-LIM": true, "PE-LMA": true, + "PE-LOR": true, "PE-MDD": true, "PE-MOQ": true, "PE-PAS": true, "PE-PIU": true, + "PE-PUN": true, "PE-SAM": true, "PE-TAC": true, "PE-TUM": true, "PE-UCA": true, + "PG-CPK": true, "PG-CPM": true, "PG-EBR": true, "PG-EHG": true, "PG-EPW": true, + "PG-ESW": true, "PG-GPK": true, "PG-MBA": true, "PG-MPL": true, "PG-MPM": true, + "PG-MRL": true, "PG-NCD": true, "PG-NIK": true, "PG-NPP": true, "PG-NSB": true, + "PG-SAN": true, "PG-SHM": true, "PG-WBK": true, "PG-WHM": true, "PG-WPD": true, + "PH-00": true, "PH-01": true, "PH-02": true, "PH-03": true, "PH-05": true, + "PH-06": true, "PH-07": true, "PH-08": true, "PH-09": true, "PH-10": true, + "PH-11": true, "PH-12": true, "PH-13": true, "PH-14": true, "PH-15": true, + "PH-40": true, "PH-41": true, "PH-ABR": true, "PH-AGN": true, "PH-AGS": true, + "PH-AKL": true, "PH-ALB": true, "PH-ANT": true, "PH-APA": true, "PH-AUR": true, + "PH-BAN": true, "PH-BAS": true, "PH-BEN": true, "PH-BIL": true, "PH-BOH": true, + "PH-BTG": true, "PH-BTN": true, "PH-BUK": true, "PH-BUL": true, "PH-CAG": true, + "PH-CAM": true, "PH-CAN": true, "PH-CAP": true, "PH-CAS": true, "PH-CAT": true, + "PH-CAV": true, "PH-CEB": true, "PH-COM": true, "PH-DAO": true, "PH-DAS": true, + "PH-DAV": true, "PH-DIN": true, "PH-EAS": true, "PH-GUI": true, "PH-IFU": true, + "PH-ILI": true, "PH-ILN": true, "PH-ILS": true, "PH-ISA": true, "PH-KAL": true, + "PH-LAG": true, "PH-LAN": true, "PH-LAS": true, "PH-LEY": true, "PH-LUN": true, + "PH-MAD": true, "PH-MAG": true, "PH-MAS": true, "PH-MDC": true, "PH-MDR": true, + "PH-MOU": true, "PH-MSC": true, "PH-MSR": true, "PH-NCO": true, "PH-NEC": true, + "PH-NER": true, "PH-NSA": true, "PH-NUE": true, "PH-NUV": true, "PH-PAM": true, + "PH-PAN": true, "PH-PLW": true, "PH-QUE": true, "PH-QUI": true, "PH-RIZ": true, + "PH-ROM": true, "PH-SAR": true, "PH-SCO": true, "PH-SIG": true, "PH-SLE": true, + "PH-SLU": true, "PH-SOR": true, "PH-SUK": true, "PH-SUN": true, "PH-SUR": true, + "PH-TAR": true, "PH-TAW": true, "PH-WSA": true, "PH-ZAN": true, "PH-ZAS": true, + "PH-ZMB": true, "PH-ZSI": true, "PK-BA": true, "PK-GB": true, "PK-IS": true, + "PK-JK": true, "PK-KP": true, "PK-PB": true, "PK-SD": true, "PK-TA": true, + "PL-02": true, "PL-04": true, "PL-06": true, "PL-08": true, "PL-10": true, + "PL-12": true, "PL-14": true, "PL-16": true, "PL-18": true, "PL-20": true, + "PL-22": true, "PL-24": true, "PL-26": true, "PL-28": true, "PL-30": true, "PL-32": true, + "PS-BTH": true, "PS-DEB": true, "PS-GZA": true, "PS-HBN": true, + "PS-JEM": true, "PS-JEN": true, "PS-JRH": true, "PS-KYS": true, "PS-NBS": true, + "PS-NGZ": true, "PS-QQA": true, "PS-RBH": true, "PS-RFH": true, "PS-SLT": true, + "PS-TBS": true, "PS-TKM": true, "PT-01": true, "PT-02": true, "PT-03": true, + "PT-04": true, "PT-05": true, "PT-06": true, "PT-07": true, "PT-08": true, + "PT-09": true, "PT-10": true, "PT-11": true, "PT-12": true, "PT-13": true, + "PT-14": true, "PT-15": true, "PT-16": true, "PT-17": true, "PT-18": true, + "PT-20": true, "PT-30": true, "PW-002": true, "PW-004": true, "PW-010": true, + "PW-050": true, "PW-100": true, "PW-150": true, "PW-212": true, "PW-214": true, + "PW-218": true, "PW-222": true, "PW-224": true, "PW-226": true, "PW-227": true, + "PW-228": true, "PW-350": true, "PW-370": true, "PY-1": true, "PY-10": true, + "PY-11": true, "PY-12": true, "PY-13": true, "PY-14": true, "PY-15": true, + "PY-16": true, "PY-19": true, "PY-2": true, "PY-3": true, "PY-4": true, + "PY-5": true, "PY-6": true, "PY-7": true, "PY-8": true, "PY-9": true, + "PY-ASU": true, "QA-DA": true, "QA-KH": true, "QA-MS": true, "QA-RA": true, + "QA-US": true, "QA-WA": true, "QA-ZA": true, "RO-AB": true, "RO-AG": true, + "RO-AR": true, "RO-B": true, "RO-BC": true, "RO-BH": true, "RO-BN": true, + "RO-BR": true, "RO-BT": true, "RO-BV": true, "RO-BZ": true, "RO-CJ": true, + "RO-CL": true, "RO-CS": true, "RO-CT": true, "RO-CV": true, "RO-DB": true, + "RO-DJ": true, "RO-GJ": true, "RO-GL": true, "RO-GR": true, "RO-HD": true, + "RO-HR": true, "RO-IF": true, "RO-IL": true, "RO-IS": true, "RO-MH": true, + "RO-MM": true, "RO-MS": true, "RO-NT": true, "RO-OT": true, "RO-PH": true, + "RO-SB": true, "RO-SJ": true, "RO-SM": true, "RO-SV": true, "RO-TL": true, + "RO-TM": true, "RO-TR": true, "RO-VL": true, "RO-VN": true, "RO-VS": true, + "RS-00": true, "RS-01": true, "RS-02": true, "RS-03": true, "RS-04": true, + "RS-05": true, "RS-06": true, "RS-07": true, "RS-08": true, "RS-09": true, + "RS-10": true, "RS-11": true, "RS-12": true, "RS-13": true, "RS-14": true, + "RS-15": true, "RS-16": true, "RS-17": true, "RS-18": true, "RS-19": true, + "RS-20": true, "RS-21": true, "RS-22": true, "RS-23": true, "RS-24": true, + "RS-25": true, "RS-26": true, "RS-27": true, "RS-28": true, "RS-29": true, + "RS-KM": true, "RS-VO": true, "RU-AD": true, "RU-AL": true, "RU-ALT": true, + "RU-AMU": true, "RU-ARK": true, "RU-AST": true, "RU-BA": true, "RU-BEL": true, + "RU-BRY": true, "RU-BU": true, "RU-CE": true, "RU-CHE": true, "RU-CHU": true, + "RU-CU": true, "RU-DA": true, "RU-IN": true, "RU-IRK": true, "RU-IVA": true, + "RU-KAM": true, "RU-KB": true, "RU-KC": true, "RU-KDA": true, "RU-KEM": true, + "RU-KGD": true, "RU-KGN": true, "RU-KHA": true, "RU-KHM": true, "RU-KIR": true, + "RU-KK": true, "RU-KL": true, "RU-KLU": true, "RU-KO": true, "RU-KOS": true, + "RU-KR": true, "RU-KRS": true, "RU-KYA": true, "RU-LEN": true, "RU-LIP": true, + "RU-MAG": true, "RU-ME": true, "RU-MO": true, "RU-MOS": true, "RU-MOW": true, + "RU-MUR": true, "RU-NEN": true, "RU-NGR": true, "RU-NIZ": true, "RU-NVS": true, + "RU-OMS": true, "RU-ORE": true, "RU-ORL": true, "RU-PER": true, "RU-PNZ": true, + "RU-PRI": true, "RU-PSK": true, "RU-ROS": true, "RU-RYA": true, "RU-SA": true, + "RU-SAK": true, "RU-SAM": true, "RU-SAR": true, "RU-SE": true, "RU-SMO": true, + "RU-SPE": true, "RU-STA": true, "RU-SVE": true, "RU-TA": true, "RU-TAM": true, + "RU-TOM": true, "RU-TUL": true, "RU-TVE": true, "RU-TY": true, "RU-TYU": true, + "RU-UD": true, "RU-ULY": true, "RU-VGG": true, "RU-VLA": true, "RU-VLG": true, + "RU-VOR": true, "RU-YAN": true, "RU-YAR": true, "RU-YEV": true, "RU-ZAB": true, + "RW-01": true, "RW-02": true, "RW-03": true, "RW-04": true, "RW-05": true, + "SA-01": true, "SA-02": true, "SA-03": true, "SA-04": true, "SA-05": true, + "SA-06": true, "SA-07": true, "SA-08": true, "SA-09": true, "SA-10": true, + "SA-11": true, "SA-12": true, "SA-14": true, "SB-CE": true, "SB-CH": true, + "SB-CT": true, "SB-GU": true, "SB-IS": true, "SB-MK": true, "SB-ML": true, + "SB-RB": true, "SB-TE": true, "SB-WE": true, "SC-01": true, "SC-02": true, + "SC-03": true, "SC-04": true, "SC-05": true, "SC-06": true, "SC-07": true, + "SC-08": true, "SC-09": true, "SC-10": true, "SC-11": true, "SC-12": true, + "SC-13": true, "SC-14": true, "SC-15": true, "SC-16": true, "SC-17": true, + "SC-18": true, "SC-19": true, "SC-20": true, "SC-21": true, "SC-22": true, + "SC-23": true, "SC-24": true, "SC-25": true, "SD-DC": true, "SD-DE": true, + "SD-DN": true, "SD-DS": true, "SD-DW": true, "SD-GD": true, "SD-GK": true, "SD-GZ": true, + "SD-KA": true, "SD-KH": true, "SD-KN": true, "SD-KS": true, "SD-NB": true, + "SD-NO": true, "SD-NR": true, "SD-NW": true, "SD-RS": true, "SD-SI": true, + "SE-AB": true, "SE-AC": true, "SE-BD": true, "SE-C": true, "SE-D": true, + "SE-E": true, "SE-F": true, "SE-G": true, "SE-H": true, "SE-I": true, + "SE-K": true, "SE-M": true, "SE-N": true, "SE-O": true, "SE-S": true, + "SE-T": true, "SE-U": true, "SE-W": true, "SE-X": true, "SE-Y": true, + "SE-Z": true, "SG-01": true, "SG-02": true, "SG-03": true, "SG-04": true, + "SG-05": true, "SH-AC": true, "SH-HL": true, "SH-TA": true, "SI-001": true, + "SI-002": true, "SI-003": true, "SI-004": true, "SI-005": true, "SI-006": true, + "SI-007": true, "SI-008": true, "SI-009": true, "SI-010": true, "SI-011": true, + "SI-012": true, "SI-013": true, "SI-014": true, "SI-015": true, "SI-016": true, + "SI-017": true, "SI-018": true, "SI-019": true, "SI-020": true, "SI-021": true, + "SI-022": true, "SI-023": true, "SI-024": true, "SI-025": true, "SI-026": true, + "SI-027": true, "SI-028": true, "SI-029": true, "SI-030": true, "SI-031": true, + "SI-032": true, "SI-033": true, "SI-034": true, "SI-035": true, "SI-036": true, + "SI-037": true, "SI-038": true, "SI-039": true, "SI-040": true, "SI-041": true, + "SI-042": true, "SI-043": true, "SI-044": true, "SI-045": true, "SI-046": true, + "SI-047": true, "SI-048": true, "SI-049": true, "SI-050": true, "SI-051": true, + "SI-052": true, "SI-053": true, "SI-054": true, "SI-055": true, "SI-056": true, + "SI-057": true, "SI-058": true, "SI-059": true, "SI-060": true, "SI-061": true, + "SI-062": true, "SI-063": true, "SI-064": true, "SI-065": true, "SI-066": true, + "SI-067": true, "SI-068": true, "SI-069": true, "SI-070": true, "SI-071": true, + "SI-072": true, "SI-073": true, "SI-074": true, "SI-075": true, "SI-076": true, + "SI-077": true, "SI-078": true, "SI-079": true, "SI-080": true, "SI-081": true, + "SI-082": true, "SI-083": true, "SI-084": true, "SI-085": true, "SI-086": true, + "SI-087": true, "SI-088": true, "SI-089": true, "SI-090": true, "SI-091": true, + "SI-092": true, "SI-093": true, "SI-094": true, "SI-095": true, "SI-096": true, + "SI-097": true, "SI-098": true, "SI-099": true, "SI-100": true, "SI-101": true, + "SI-102": true, "SI-103": true, "SI-104": true, "SI-105": true, "SI-106": true, + "SI-107": true, "SI-108": true, "SI-109": true, "SI-110": true, "SI-111": true, + "SI-112": true, "SI-113": true, "SI-114": true, "SI-115": true, "SI-116": true, + "SI-117": true, "SI-118": true, "SI-119": true, "SI-120": true, "SI-121": true, + "SI-122": true, "SI-123": true, "SI-124": true, "SI-125": true, "SI-126": true, + "SI-127": true, "SI-128": true, "SI-129": true, "SI-130": true, "SI-131": true, + "SI-132": true, "SI-133": true, "SI-134": true, "SI-135": true, "SI-136": true, + "SI-137": true, "SI-138": true, "SI-139": true, "SI-140": true, "SI-141": true, + "SI-142": true, "SI-143": true, "SI-144": true, "SI-146": true, "SI-147": true, + "SI-148": true, "SI-149": true, "SI-150": true, "SI-151": true, "SI-152": true, + "SI-153": true, "SI-154": true, "SI-155": true, "SI-156": true, "SI-157": true, + "SI-158": true, "SI-159": true, "SI-160": true, "SI-161": true, "SI-162": true, + "SI-163": true, "SI-164": true, "SI-165": true, "SI-166": true, "SI-167": true, + "SI-168": true, "SI-169": true, "SI-170": true, "SI-171": true, "SI-172": true, + "SI-173": true, "SI-174": true, "SI-175": true, "SI-176": true, "SI-177": true, + "SI-178": true, "SI-179": true, "SI-180": true, "SI-181": true, "SI-182": true, + "SI-183": true, "SI-184": true, "SI-185": true, "SI-186": true, "SI-187": true, + "SI-188": true, "SI-189": true, "SI-190": true, "SI-191": true, "SI-192": true, + "SI-193": true, "SI-194": true, "SI-195": true, "SI-196": true, "SI-197": true, + "SI-198": true, "SI-199": true, "SI-200": true, "SI-201": true, "SI-202": true, + "SI-203": true, "SI-204": true, "SI-205": true, "SI-206": true, "SI-207": true, + "SI-208": true, "SI-209": true, "SI-210": true, "SI-211": true, "SI-212": true, "SI-213": true, "SK-BC": true, + "SK-BL": true, "SK-KI": true, "SK-NI": true, "SK-PV": true, "SK-TA": true, + "SK-TC": true, "SK-ZI": true, "SL-E": true, "SL-N": true, "SL-S": true, + "SL-W": true, "SM-01": true, "SM-02": true, "SM-03": true, "SM-04": true, + "SM-05": true, "SM-06": true, "SM-07": true, "SM-08": true, "SM-09": true, + "SN-DB": true, "SN-DK": true, "SN-FK": true, "SN-KA": true, "SN-KD": true, + "SN-KE": true, "SN-KL": true, "SN-LG": true, "SN-MT": true, "SN-SE": true, + "SN-SL": true, "SN-TC": true, "SN-TH": true, "SN-ZG": true, "SO-AW": true, + "SO-BK": true, "SO-BN": true, "SO-BR": true, "SO-BY": true, "SO-GA": true, + "SO-GE": true, "SO-HI": true, "SO-JD": true, "SO-JH": true, "SO-MU": true, + "SO-NU": true, "SO-SA": true, "SO-SD": true, "SO-SH": true, "SO-SO": true, + "SO-TO": true, "SO-WO": true, "SR-BR": true, "SR-CM": true, "SR-CR": true, + "SR-MA": true, "SR-NI": true, "SR-PM": true, "SR-PR": true, "SR-SA": true, + "SR-SI": true, "SR-WA": true, "SS-BN": true, "SS-BW": true, "SS-EC": true, + "SS-EE8": true, "SS-EE": true, "SS-EW": true, "SS-JG": true, "SS-LK": true, "SS-NU": true, + "SS-UY": true, "SS-WR": true, "ST-01": true, "ST-P": true, "ST-S": true, "SV-AH": true, + "SV-CA": true, "SV-CH": true, "SV-CU": true, "SV-LI": true, "SV-MO": true, + "SV-PA": true, "SV-SA": true, "SV-SM": true, "SV-SO": true, "SV-SS": true, + "SV-SV": true, "SV-UN": true, "SV-US": true, "SY-DI": true, "SY-DR": true, + "SY-DY": true, "SY-HA": true, "SY-HI": true, "SY-HL": true, "SY-HM": true, + "SY-ID": true, "SY-LA": true, "SY-QU": true, "SY-RA": true, "SY-RD": true, + "SY-SU": true, "SY-TA": true, "SZ-HH": true, "SZ-LU": true, "SZ-MA": true, + "SZ-SH": true, "TD-BA": true, "TD-BG": true, "TD-BO": true, "TD-CB": true, + "TD-EN": true, "TD-GR": true, "TD-HL": true, "TD-KA": true, "TD-LC": true, + "TD-LO": true, "TD-LR": true, "TD-MA": true, "TD-MC": true, "TD-ME": true, + "TD-MO": true, "TD-ND": true, "TD-OD": true, "TD-SA": true, "TD-SI": true, + "TD-TA": true, "TD-TI": true, "TD-WF": true, "TG-C": true, "TG-K": true, + "TG-M": true, "TG-P": true, "TG-S": true, "TH-10": true, "TH-11": true, + "TH-12": true, "TH-13": true, "TH-14": true, "TH-15": true, "TH-16": true, + "TH-17": true, "TH-18": true, "TH-19": true, "TH-20": true, "TH-21": true, + "TH-22": true, "TH-23": true, "TH-24": true, "TH-25": true, "TH-26": true, + "TH-27": true, "TH-30": true, "TH-31": true, "TH-32": true, "TH-33": true, + "TH-34": true, "TH-35": true, "TH-36": true, "TH-37": true, "TH-38": true, "TH-39": true, + "TH-40": true, "TH-41": true, "TH-42": true, "TH-43": true, "TH-44": true, + "TH-45": true, "TH-46": true, "TH-47": true, "TH-48": true, "TH-49": true, + "TH-50": true, "TH-51": true, "TH-52": true, "TH-53": true, "TH-54": true, + "TH-55": true, "TH-56": true, "TH-57": true, "TH-58": true, "TH-60": true, + "TH-61": true, "TH-62": true, "TH-63": true, "TH-64": true, "TH-65": true, + "TH-66": true, "TH-67": true, "TH-70": true, "TH-71": true, "TH-72": true, + "TH-73": true, "TH-74": true, "TH-75": true, "TH-76": true, "TH-77": true, + "TH-80": true, "TH-81": true, "TH-82": true, "TH-83": true, "TH-84": true, + "TH-85": true, "TH-86": true, "TH-90": true, "TH-91": true, "TH-92": true, + "TH-93": true, "TH-94": true, "TH-95": true, "TH-96": true, "TH-S": true, + "TJ-GB": true, "TJ-KT": true, "TJ-SU": true, "TJ-DU": true, "TJ-RA": true, "TL-AL": true, "TL-AN": true, + "TL-BA": true, "TL-BO": true, "TL-CO": true, "TL-DI": true, "TL-ER": true, + "TL-LA": true, "TL-LI": true, "TL-MF": true, "TL-MT": true, "TL-OE": true, + "TL-VI": true, "TM-A": true, "TM-B": true, "TM-D": true, "TM-L": true, + "TM-M": true, "TM-S": true, "TN-11": true, "TN-12": true, "TN-13": true, + "TN-14": true, "TN-21": true, "TN-22": true, "TN-23": true, "TN-31": true, + "TN-32": true, "TN-33": true, "TN-34": true, "TN-41": true, "TN-42": true, + "TN-43": true, "TN-51": true, "TN-52": true, "TN-53": true, "TN-61": true, + "TN-71": true, "TN-72": true, "TN-73": true, "TN-81": true, "TN-82": true, + "TN-83": true, "TO-01": true, "TO-02": true, "TO-03": true, "TO-04": true, + "TO-05": true, "TR-01": true, "TR-02": true, "TR-03": true, "TR-04": true, + "TR-05": true, "TR-06": true, "TR-07": true, "TR-08": true, "TR-09": true, + "TR-10": true, "TR-11": true, "TR-12": true, "TR-13": true, "TR-14": true, + "TR-15": true, "TR-16": true, "TR-17": true, "TR-18": true, "TR-19": true, + "TR-20": true, "TR-21": true, "TR-22": true, "TR-23": true, "TR-24": true, + "TR-25": true, "TR-26": true, "TR-27": true, "TR-28": true, "TR-29": true, + "TR-30": true, "TR-31": true, "TR-32": true, "TR-33": true, "TR-34": true, + "TR-35": true, "TR-36": true, "TR-37": true, "TR-38": true, "TR-39": true, + "TR-40": true, "TR-41": true, "TR-42": true, "TR-43": true, "TR-44": true, + "TR-45": true, "TR-46": true, "TR-47": true, "TR-48": true, "TR-49": true, + "TR-50": true, "TR-51": true, "TR-52": true, "TR-53": true, "TR-54": true, + "TR-55": true, "TR-56": true, "TR-57": true, "TR-58": true, "TR-59": true, + "TR-60": true, "TR-61": true, "TR-62": true, "TR-63": true, "TR-64": true, + "TR-65": true, "TR-66": true, "TR-67": true, "TR-68": true, "TR-69": true, + "TR-70": true, "TR-71": true, "TR-72": true, "TR-73": true, "TR-74": true, + "TR-75": true, "TR-76": true, "TR-77": true, "TR-78": true, "TR-79": true, + "TR-80": true, "TR-81": true, "TT-ARI": true, "TT-CHA": true, "TT-CTT": true, + "TT-DMN": true, "TT-ETO": true, "TT-MRC": true, "TT-TOB": true, "TT-PED": true, "TT-POS": true, "TT-PRT": true, + "TT-PTF": true, "TT-RCM": true, "TT-SFO": true, "TT-SGE": true, "TT-SIP": true, + "TT-SJL": true, "TT-TUP": true, "TT-WTO": true, "TV-FUN": true, "TV-NIT": true, + "TV-NKF": true, "TV-NKL": true, "TV-NMA": true, "TV-NMG": true, "TV-NUI": true, + "TV-VAI": true, "TW-CHA": true, "TW-CYI": true, "TW-CYQ": true, "TW-KIN": true, "TW-HSQ": true, + "TW-HSZ": true, "TW-HUA": true, "TW-LIE": true, "TW-ILA": true, "TW-KEE": true, "TW-KHH": true, + "TW-KHQ": true, "TW-MIA": true, "TW-NAN": true, "TW-NWT": true, "TW-PEN": true, "TW-PIF": true, + "TW-TAO": true, "TW-TNN": true, "TW-TNQ": true, "TW-TPE": true, "TW-TPQ": true, + "TW-TTT": true, "TW-TXG": true, "TW-TXQ": true, "TW-YUN": true, "TZ-01": true, + "TZ-02": true, "TZ-03": true, "TZ-04": true, "TZ-05": true, "TZ-06": true, + "TZ-07": true, "TZ-08": true, "TZ-09": true, "TZ-10": true, "TZ-11": true, + "TZ-12": true, "TZ-13": true, "TZ-14": true, "TZ-15": true, "TZ-16": true, + "TZ-17": true, "TZ-18": true, "TZ-19": true, "TZ-20": true, "TZ-21": true, + "TZ-22": true, "TZ-23": true, "TZ-24": true, "TZ-25": true, "TZ-26": true, "TZ-27": true, "TZ-28": true, "TZ-29": true, "TZ-30": true, "TZ-31": true, + "UA-05": true, "UA-07": true, "UA-09": true, "UA-12": true, "UA-14": true, + "UA-18": true, "UA-21": true, "UA-23": true, "UA-26": true, "UA-30": true, + "UA-32": true, "UA-35": true, "UA-40": true, "UA-43": true, "UA-46": true, + "UA-48": true, "UA-51": true, "UA-53": true, "UA-56": true, "UA-59": true, + "UA-61": true, "UA-63": true, "UA-65": true, "UA-68": true, "UA-71": true, + "UA-74": true, "UA-77": true, "UG-101": true, "UG-102": true, "UG-103": true, + "UG-104": true, "UG-105": true, "UG-106": true, "UG-107": true, "UG-108": true, + "UG-109": true, "UG-110": true, "UG-111": true, "UG-112": true, "UG-113": true, + "UG-114": true, "UG-115": true, "UG-116": true, "UG-201": true, "UG-202": true, + "UG-203": true, "UG-204": true, "UG-205": true, "UG-206": true, "UG-207": true, + "UG-208": true, "UG-209": true, "UG-210": true, "UG-211": true, "UG-212": true, + "UG-213": true, "UG-214": true, "UG-215": true, "UG-216": true, "UG-217": true, + "UG-218": true, "UG-219": true, "UG-220": true, "UG-221": true, "UG-222": true, + "UG-223": true, "UG-224": true, "UG-301": true, "UG-302": true, "UG-303": true, + "UG-304": true, "UG-305": true, "UG-306": true, "UG-307": true, "UG-308": true, + "UG-309": true, "UG-310": true, "UG-311": true, "UG-312": true, "UG-313": true, + "UG-314": true, "UG-315": true, "UG-316": true, "UG-317": true, "UG-318": true, + "UG-319": true, "UG-320": true, "UG-321": true, "UG-401": true, "UG-402": true, + "UG-403": true, "UG-404": true, "UG-405": true, "UG-406": true, "UG-407": true, + "UG-408": true, "UG-409": true, "UG-410": true, "UG-411": true, "UG-412": true, + "UG-413": true, "UG-414": true, "UG-415": true, "UG-416": true, "UG-417": true, + "UG-418": true, "UG-419": true, "UG-C": true, "UG-E": true, "UG-N": true, + "UG-W": true, "UG-322": true, "UG-323": true, "UG-420": true, "UG-117": true, + "UG-118": true, "UG-225": true, "UG-120": true, "UG-226": true, + "UG-121": true, "UG-122": true, "UG-227": true, "UG-421": true, + "UG-325": true, "UG-228": true, "UG-123": true, "UG-422": true, + "UG-326": true, "UG-229": true, "UG-124": true, "UG-423": true, + "UG-230": true, "UG-327": true, "UG-424": true, "UG-328": true, + "UG-425": true, "UG-426": true, "UG-330": true, + "UM-67": true, "UM-71": true, "UM-76": true, "UM-79": true, + "UM-81": true, "UM-84": true, "UM-86": true, "UM-89": true, "UM-95": true, + "US-AK": true, "US-AL": true, "US-AR": true, "US-AS": true, "US-AZ": true, + "US-CA": true, "US-CO": true, "US-CT": true, "US-DC": true, "US-DE": true, + "US-FL": true, "US-GA": true, "US-GU": true, "US-HI": true, "US-IA": true, + "US-ID": true, "US-IL": true, "US-IN": true, "US-KS": true, "US-KY": true, + "US-LA": true, "US-MA": true, "US-MD": true, "US-ME": true, "US-MI": true, + "US-MN": true, "US-MO": true, "US-MP": true, "US-MS": true, "US-MT": true, + "US-NC": true, "US-ND": true, "US-NE": true, "US-NH": true, "US-NJ": true, + "US-NM": true, "US-NV": true, "US-NY": true, "US-OH": true, "US-OK": true, + "US-OR": true, "US-PA": true, "US-PR": true, "US-RI": true, "US-SC": true, + "US-SD": true, "US-TN": true, "US-TX": true, "US-UM": true, "US-UT": true, + "US-VA": true, "US-VI": true, "US-VT": true, "US-WA": true, "US-WI": true, + "US-WV": true, "US-WY": true, "UY-AR": true, "UY-CA": true, "UY-CL": true, + "UY-CO": true, "UY-DU": true, "UY-FD": true, "UY-FS": true, "UY-LA": true, + "UY-MA": true, "UY-MO": true, "UY-PA": true, "UY-RN": true, "UY-RO": true, + "UY-RV": true, "UY-SA": true, "UY-SJ": true, "UY-SO": true, "UY-TA": true, + "UY-TT": true, "UZ-AN": true, "UZ-BU": true, "UZ-FA": true, "UZ-JI": true, + "UZ-NG": true, "UZ-NW": true, "UZ-QA": true, "UZ-QR": true, "UZ-SA": true, + "UZ-SI": true, "UZ-SU": true, "UZ-TK": true, "UZ-TO": true, "UZ-XO": true, + "VC-01": true, "VC-02": true, "VC-03": true, "VC-04": true, "VC-05": true, + "VC-06": true, "VE-A": true, "VE-B": true, "VE-C": true, "VE-D": true, + "VE-E": true, "VE-F": true, "VE-G": true, "VE-H": true, "VE-I": true, + "VE-J": true, "VE-K": true, "VE-L": true, "VE-M": true, "VE-N": true, + "VE-O": true, "VE-P": true, "VE-R": true, "VE-S": true, "VE-T": true, + "VE-U": true, "VE-V": true, "VE-W": true, "VE-X": true, "VE-Y": true, + "VE-Z": true, "VN-01": true, "VN-02": true, "VN-03": true, "VN-04": true, + "VN-05": true, "VN-06": true, "VN-07": true, "VN-09": true, "VN-13": true, + "VN-14": true, "VN-15": true, "VN-18": true, "VN-20": true, "VN-21": true, + "VN-22": true, "VN-23": true, "VN-24": true, "VN-25": true, "VN-26": true, + "VN-27": true, "VN-28": true, "VN-29": true, "VN-30": true, "VN-31": true, + "VN-32": true, "VN-33": true, "VN-34": true, "VN-35": true, "VN-36": true, + "VN-37": true, "VN-39": true, "VN-40": true, "VN-41": true, "VN-43": true, + "VN-44": true, "VN-45": true, "VN-46": true, "VN-47": true, "VN-49": true, + "VN-50": true, "VN-51": true, "VN-52": true, "VN-53": true, "VN-54": true, + "VN-55": true, "VN-56": true, "VN-57": true, "VN-58": true, "VN-59": true, + "VN-61": true, "VN-63": true, "VN-66": true, "VN-67": true, "VN-68": true, + "VN-69": true, "VN-70": true, "VN-71": true, "VN-72": true, "VN-73": true, + "VN-CT": true, "VN-DN": true, "VN-HN": true, "VN-HP": true, "VN-SG": true, + "VU-MAP": true, "VU-PAM": true, "VU-SAM": true, "VU-SEE": true, "VU-TAE": true, + "VU-TOB": true, "WF-SG": true, "WF-UV": true, "WS-AA": true, "WS-AL": true, "WS-AT": true, "WS-FA": true, + "WS-GE": true, "WS-GI": true, "WS-PA": true, "WS-SA": true, "WS-TU": true, + "WS-VF": true, "WS-VS": true, "YE-AB": true, "YE-AD": true, "YE-AM": true, + "YE-BA": true, "YE-DA": true, "YE-DH": true, "YE-HD": true, "YE-HJ": true, "YE-HU": true, + "YE-IB": true, "YE-JA": true, "YE-LA": true, "YE-MA": true, "YE-MR": true, + "YE-MU": true, "YE-MW": true, "YE-RA": true, "YE-SA": true, "YE-SD": true, "YE-SH": true, + "YE-SN": true, "YE-TA": true, "ZA-EC": true, "ZA-FS": true, "ZA-GP": true, + "ZA-LP": true, "ZA-MP": true, "ZA-NC": true, "ZA-NW": true, "ZA-WC": true, + "ZA-ZN": true, "ZA-KZN": true, "ZM-01": true, "ZM-02": true, "ZM-03": true, "ZM-04": true, + "ZM-05": true, "ZM-06": true, "ZM-07": true, "ZM-08": true, "ZM-09": true, "ZM-10": true, + "ZW-BU": true, "ZW-HA": true, "ZW-MA": true, "ZW-MC": true, "ZW-ME": true, + "ZW-MI": true, "ZW-MN": true, "ZW-MS": true, "ZW-MV": true, "ZW-MW": true, } diff --git a/vendor/github.com/go-playground/validator/v10/doc.go b/vendor/github.com/go-playground/validator/v10/doc.go index 7341c67..f5aa9e5 100644 --- a/vendor/github.com/go-playground/validator/v10/doc.go +++ b/vendor/github.com/go-playground/validator/v10/doc.go @@ -7,7 +7,7 @@ and has the ability to dive into arrays and maps of any type. see more examples https://github.com/go-playground/validator/tree/master/_examples -Singleton +# Singleton Validator is designed to be thread-safe and used as a singleton instance. It caches information about your struct and validations, @@ -15,7 +15,7 @@ in essence only parsing your validation tags once per struct type. Using multiple instances neglects the benefit of caching. The not thread-safe functions are explicitly marked as such in the documentation. -Validation Functions Return Type error +# Validation Functions Return Type error Doing things this way is actually the way the standard library does, see the file.Open method here: @@ -34,7 +34,7 @@ if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so err.(validator.ValidationErrors). -Custom Validation Functions +# Custom Validation Functions Custom Validation functions can be added. Example: @@ -52,21 +52,21 @@ Custom Validation functions can be added. Example: // NOTES: using the same tag name as an existing function // will overwrite the existing one -Cross-Field Validation +# Cross-Field Validation Cross-Field Validation can be done via the following tags: - - eqfield - - nefield - - gtfield - - gtefield - - ltfield - - ltefield - - eqcsfield - - necsfield - - gtcsfield - - gtecsfield - - ltcsfield - - ltecsfield + - eqfield + - nefield + - gtfield + - gtefield + - ltfield + - ltefield + - eqcsfield + - necsfield + - gtcsfield + - gtecsfield + - ltcsfield + - ltecsfield If, however, some custom cross-field validation is required, it can be done using a custom validation. @@ -106,7 +106,7 @@ used "eqcsfield" it could be multiple levels down. Example: // whatever you pass, struct, field... // when calling validate.Field(field, tag) val will be nil -Multiple Validators +# Multiple Validators Multiple validators on a field will process in the order defined. Example: @@ -124,7 +124,7 @@ Bad Validator definitions are not handled by the library. Example: // this definition of min max will never succeed -Using Validator Tags +# Using Validator Tags Baked In Cross-Field validation only compares fields on the same struct. If Cross-Field + Cross-Struct validation is needed you should implement your @@ -146,24 +146,22 @@ use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, so the above will become excludesall=0x7C type Test struct { - Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! + Field `validate:"excludesall=|"` // BAD! Do not include a pipe! Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. } - -Baked In Validators and Tags +# Baked In Validators and Tags Here is a list of the current built in validators: - -Skip Field +# Skip Field Tells the validation to skip this struct field; this is particularly handy in ignoring embedded structs from being validated. (Usage: -) - Usage: - + Usage: - -Or Operator +# Or Operator This is the 'or' operator allowing multiple validators to be used and accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba @@ -172,7 +170,7 @@ colors to be accepted. This can also be combined with 'and' for example Usage: | -StructOnly +# StructOnly When a field that is a nested struct is encountered, and contains this flag any validation on the nested struct will be run, but none of the nested @@ -182,13 +180,13 @@ NOTE: only "required" and "omitempty" can be used on a struct itself. Usage: structonly -NoStructLevel +# NoStructLevel Same as structonly tag except that any struct level validations will not run. Usage: nostructlevel -Omit Empty +# Omit Empty Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation @@ -196,7 +194,7 @@ such as min or max won't run, but if a value is set validation will run. Usage: omitempty -Dive +# Dive This tells the validator to dive into a slice, array or map and validate that level of the slice, array or map with the validation tags that follow. @@ -232,19 +230,19 @@ require another 'keys' and 'endkeys' tag. These tags are only valid for maps. Example #1 - map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" + map[string]string with validation tag "gt=0,dive,keys,eq=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to the map keys + // eq=1|eq=2 will be applied to the map keys // required will be applied to map values Example #2 map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to each array element in the the map keys + // eq=1|eq=2 will be applied to each array element in the map keys // required will be applied to map values -Required +# Required This validates that the value is not the data types default zero value. For numbers ensures value is not zero. For strings ensures value is @@ -253,7 +251,7 @@ ensures the value is not nil. Usage: required -Required If +# Required If The field under validation must be present and not empty only if all the other specified fields are equal to the value following the specified @@ -270,7 +268,7 @@ Examples: // require the field if the Field1 and Field2 is equal to the value respectively: Usage: required_if=Field1 foo Field2 bar -Required Unless +# Required Unless The field under validation must be present and not empty unless all the other specified fields are equal to the value following the specified @@ -287,7 +285,7 @@ Examples: // require the field unless the Field1 and Field2 is equal to the value respectively: Usage: required_unless=Field1 foo Field2 bar -Required With +# Required With The field under validation must be present and not empty only if any of the other specified fields are present. For strings ensures value is @@ -304,7 +302,7 @@ Examples: // require the field if the Field1 or Field2 is present: Usage: required_with=Field1 Field2 -Required With All +# Required With All The field under validation must be present and not empty only if all of the other specified fields are present. For strings ensures value is @@ -318,7 +316,7 @@ Example: // require the field if the Field1 and Field2 is present: Usage: required_with_all=Field1 Field2 -Required Without +# Required Without The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is @@ -335,7 +333,7 @@ Examples: // require the field if the Field1 or Field2 is not present: Usage: required_without=Field1 Field2 -Required Without All +# Required Without All The field under validation must be present and not empty only when all of the other specified fields are not present. For strings ensures value is @@ -349,7 +347,7 @@ Example: // require the field if the Field1 and Field2 is not present: Usage: required_without_all=Field1 Field2 -Excluded If +# Excluded If The field under validation must not be present or not empty only if all the other specified fields are equal to the value following the specified @@ -366,7 +364,7 @@ Examples: // exclude the field if the Field1 and Field2 is equal to the value respectively: Usage: excluded_if=Field1 foo Field2 bar -Excluded Unless +# Excluded Unless The field under validation must not be present or empty unless all the other specified fields are equal to the value following the specified @@ -383,14 +381,14 @@ Examples: // exclude the field unless the Field1 and Field2 is equal to the value respectively: Usage: excluded_unless=Field1 foo Field2 bar -Is Default +# Is Default This validates that the value is the default value and is almost the opposite of required. Usage: isdefault -Length +# Length For numbers, length will ensure that the value is equal to the parameter given. For strings, it checks that @@ -408,7 +406,7 @@ in the parameter. Usage: len=1h30m -Maximum +# Maximum For numbers, max will ensure that the value is less than or equal to the parameter given. For strings, it checks @@ -426,7 +424,7 @@ duration given in the parameter. Usage: max=1h30m -Minimum +# Minimum For numbers, min will ensure that the value is greater or equal to the parameter given. For strings, it checks that @@ -444,7 +442,7 @@ the duration given in the parameter. Usage: min=1h30m -Equals +# Equals For strings & numbers, eq will ensure that the value is equal to the parameter given. For slices, arrays, and maps, @@ -461,7 +459,7 @@ in the parameter. Usage: eq=1h30m -Not Equal +# Not Equal For strings & numbers, ne will ensure that the value is not equal to the parameter given. For slices, arrays, and maps, @@ -478,7 +476,7 @@ given in the parameter. Usage: ne=1h30m -One Of +# One Of For strings, ints, and uints, oneof will ensure that the value is one of the values in the parameter. The parameter should be @@ -486,11 +484,11 @@ a list of values separated by whitespace. Values may be strings or numbers. To match strings with spaces in them, include the target string between single quotes. - Usage: oneof=red green - oneof='red green' 'blue yellow' - oneof=5 7 9 + Usage: oneof=red green + oneof='red green' 'blue yellow' + oneof=5 7 9 -Greater Than +# Greater Than For numbers, this will ensure that the value is greater than the parameter given. For strings, it checks that the string length @@ -514,7 +512,7 @@ given in the parameter. Usage: gt=1h30m -Greater Than or Equal +# Greater Than or Equal Same as 'min' above. Kept both to make terminology with 'len' easier. @@ -535,7 +533,7 @@ the duration given in the parameter. Usage: gte=1h30m -Less Than +# Less Than For numbers, this will ensure that the value is less than the parameter given. For strings, it checks that the string length is less than that number of @@ -558,7 +556,7 @@ in the parameter. Usage: lt=1h30m -Less Than or Equal +# Less Than or Equal Same as 'max' above. Kept both to make terminology with 'len' easier. @@ -579,7 +577,7 @@ duration given in the parameter. Usage: lte=1h30m -Field Equals Another Field +# Field Equals Another Field This will validate the field value against another fields value either within a struct or passed in field. @@ -601,7 +599,7 @@ to the top level struct. Usage: eqcsfield=InnerStructField.Field) -Field Does Not Equal Another Field +# Field Does Not Equal Another Field This will validate the field value against another fields value either within a struct or passed in field. @@ -623,7 +621,7 @@ relative to the top level struct. Usage: necsfield=InnerStructField.Field -Field Greater Than Another Field +# Field Greater Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -639,14 +637,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "gtfield") -Field Greater Than Another Relative Field +# Field Greater Than Another Relative Field This does the same as gtfield except that it validates the field provided relative to the top level struct. Usage: gtcsfield=InnerStructField.Field -Field Greater Than or Equal To Another Field +# Field Greater Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -662,14 +660,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "gtefield") -Field Greater Than or Equal To Another Relative Field +# Field Greater Than or Equal To Another Relative Field This does the same as gtefield except that it validates the field provided relative to the top level struct. Usage: gtecsfield=InnerStructField.Field -Less Than Another Field +# Less Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -685,14 +683,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "ltfield") -Less Than Another Relative Field +# Less Than Another Relative Field This does the same as ltfield except that it validates the field provided relative to the top level struct. Usage: ltcsfield=InnerStructField.Field -Less Than or Equal To Another Field +# Less Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -708,14 +706,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "ltefield") -Less Than or Equal To Another Relative Field +# Less Than or Equal To Another Relative Field This does the same as ltefield except that it validates the field provided relative to the top level struct. Usage: ltecsfield=InnerStructField.Field -Field Contains Another Field +# Field Contains Another Field This does the same as contains except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on @@ -723,7 +721,7 @@ other types. Usage: containsfield=InnerStructField.Field -Field Excludes Another Field +# Field Excludes Another Field This does the same as excludes except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on @@ -731,7 +729,7 @@ other types. Usage: excludesfield=InnerStructField.Field -Unique +# Unique For arrays & slices, unique will ensure that there are no duplicates. For maps, unique will ensure that there are no duplicate values. @@ -744,44 +742,44 @@ in a field of the struct specified via a parameter. // For slices of struct: Usage: unique=field -Alpha Only +# Alpha Only This validates that a string value contains ASCII alpha characters only Usage: alpha -Alphanumeric +# Alphanumeric This validates that a string value contains ASCII alphanumeric characters only Usage: alphanum -Alpha Unicode +# Alpha Unicode This validates that a string value contains unicode alpha characters only Usage: alphaunicode -Alphanumeric Unicode +# Alphanumeric Unicode This validates that a string value contains unicode alphanumeric characters only Usage: alphanumunicode -Boolean +# Boolean This validates that a string value can successfully be parsed into a boolean with strconv.ParseBool Usage: boolean -Number +# Number This validates that a string value contains number values only. For integers or float it returns true. Usage: number -Numeric +# Numeric This validates that a string value contains a basic numeric value. basic excludes exponents etc... @@ -789,63 +787,63 @@ for integers or float it returns true. Usage: numeric -Hexadecimal String +# Hexadecimal String This validates that a string value contains a valid hexadecimal. Usage: hexadecimal -Hexcolor String +# Hexcolor String This validates that a string value contains a valid hex color including hashtag (#) - Usage: hexcolor + Usage: hexcolor -Lowercase String +# Lowercase String This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. Usage: lowercase -Uppercase String +# Uppercase String This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. Usage: uppercase -RGB String +# RGB String This validates that a string value contains a valid rgb color Usage: rgb -RGBA String +# RGBA String This validates that a string value contains a valid rgba color Usage: rgba -HSL String +# HSL String This validates that a string value contains a valid hsl color Usage: hsl -HSLA String +# HSLA String This validates that a string value contains a valid hsla color Usage: hsla -E.164 Phone Number String +# E.164 Phone Number String This validates that a string value contains a valid E.164 Phone number https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) Usage: e164 -E-mail String +# E-mail String This validates that a string value contains a valid email This may not conform to all possibilities of any rfc standard, but neither @@ -853,19 +851,19 @@ does any email provider accept all possibilities. Usage: email -JSON String +# JSON String This validates that a string value is valid JSON Usage: json -JWT String +# JWT String This validates that a string value is a valid JWT Usage: jwt -File path +# File This validates that a string value contains a valid file path and that the file exists on the machine. @@ -873,7 +871,25 @@ This is done using os.Stat, which is a platform independent function. Usage: file -URL String +# Image path + +This validates that a string value contains a valid file path and that +the file exists on the machine and is an image. +This is done using os.Stat and github.com/gabriel-vasile/mimetype + + Usage: image + +# URL String + +# File Path + +This validates that a string value contains a valid file path but does not +validate the existence of that file. +This is done using os.Stat, which is a platform independent function. + + Usage: filepath + +# URL String This validates that a string value contains a valid url This will accept any url the golang request uri accepts but must contain @@ -881,21 +897,21 @@ a schema for example http:// or rtmp:// Usage: url -URI String +# URI String This validates that a string value contains a valid uri This will accept any uri the golang request uri accepts Usage: uri -Urn RFC 2141 String +# Urn RFC 2141 String This validataes that a string value contains a valid URN according to the RFC 2141 spec. Usage: urn_rfc2141 -Base64 String +# Base64 String This validates that a string value contains a valid base64 value. Although an empty string is valid base64 this will report an empty string @@ -904,17 +920,27 @@ this with the omitempty tag. Usage: base64 -Base64URL String +# Base64URL String This validates that a string value contains a valid base64 URL safe value -according the the RFC4648 spec. +according the RFC4648 spec. +Although an empty string is a valid base64 URL safe value, this will report +an empty string as an error, if you wish to accept an empty string as valid +you can use this with the omitempty tag. + + Usage: base64url + +# Base64RawURL String + +This validates that a string value contains a valid base64 URL safe value, +but without = padding, according the RFC4648 spec, section 3.2. Although an empty string is a valid base64 URL safe value, this will report an empty string as an error, if you wish to accept an empty string as valid you can use this with the omitempty tag. Usage: base64url -Bitcoin Address +# Bitcoin Address This validates that a string value contains a valid bitcoin address. The format of the string is checked to ensure it matches one of the three formats @@ -930,266 +956,266 @@ Special thanks to Pieter Wuille for providng reference implementations. Usage: btc_addr_bech32 -Ethereum Address +# Ethereum Address This validates that a string value contains a valid ethereum address. The format of the string is checked to ensure it matches the standard Ethereum address format. Usage: eth_addr -Contains +# Contains This validates that a string value contains the substring value. Usage: contains=@ -Contains Any +# Contains Any This validates that a string value contains any Unicode code points in the substring value. Usage: containsany=!@#? -Contains Rune +# Contains Rune This validates that a string value contains the supplied rune value. Usage: containsrune=@ -Excludes +# Excludes This validates that a string value does not contain the substring value. Usage: excludes=@ -Excludes All +# Excludes All This validates that a string value does not contain any Unicode code points in the substring value. Usage: excludesall=!@#? -Excludes Rune +# Excludes Rune This validates that a string value does not contain the supplied rune value. Usage: excludesrune=@ -Starts With +# Starts With This validates that a string value starts with the supplied string value Usage: startswith=hello -Ends With +# Ends With This validates that a string value ends with the supplied string value Usage: endswith=goodbye -Does Not Start With +# Does Not Start With This validates that a string value does not start with the supplied string value Usage: startsnotwith=hello -Does Not End With +# Does Not End With This validates that a string value does not end with the supplied string value Usage: endsnotwith=goodbye -International Standard Book Number +# International Standard Book Number This validates that a string value contains a valid isbn10 or isbn13 value. Usage: isbn -International Standard Book Number 10 +# International Standard Book Number 10 This validates that a string value contains a valid isbn10 value. Usage: isbn10 -International Standard Book Number 13 +# International Standard Book Number 13 This validates that a string value contains a valid isbn13 value. Usage: isbn13 -Universally Unique Identifier UUID +# Universally Unique Identifier UUID This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. Usage: uuid -Universally Unique Identifier UUID v3 +# Universally Unique Identifier UUID v3 This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. Usage: uuid3 -Universally Unique Identifier UUID v4 +# Universally Unique Identifier UUID v4 This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. Usage: uuid4 -Universally Unique Identifier UUID v5 +# Universally Unique Identifier UUID v5 This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. Usage: uuid5 -Universally Unique Lexicographically Sortable Identifier ULID +# Universally Unique Lexicographically Sortable Identifier ULID This validates that a string value contains a valid ULID value. Usage: ulid -ASCII +# ASCII This validates that a string value contains only ASCII characters. NOTE: if the string is blank, this validates as true. Usage: ascii -Printable ASCII +# Printable ASCII This validates that a string value contains only printable ASCII characters. NOTE: if the string is blank, this validates as true. Usage: printascii -Multi-Byte Characters +# Multi-Byte Characters This validates that a string value contains one or more multibyte characters. NOTE: if the string is blank, this validates as true. Usage: multibyte -Data URL +# Data URL This validates that a string value contains a valid DataURI. NOTE: this will also validate that the data portion is valid base64 Usage: datauri -Latitude +# Latitude This validates that a string value contains a valid latitude. Usage: latitude -Longitude +# Longitude This validates that a string value contains a valid longitude. Usage: longitude -Social Security Number SSN +# Social Security Number SSN This validates that a string value contains a valid U.S. Social Security Number. Usage: ssn -Internet Protocol Address IP +# Internet Protocol Address IP This validates that a string value contains a valid IP Address. Usage: ip -Internet Protocol Address IPv4 +# Internet Protocol Address IPv4 This validates that a string value contains a valid v4 IP Address. Usage: ipv4 -Internet Protocol Address IPv6 +# Internet Protocol Address IPv6 This validates that a string value contains a valid v6 IP Address. Usage: ipv6 -Classless Inter-Domain Routing CIDR +# Classless Inter-Domain Routing CIDR This validates that a string value contains a valid CIDR Address. Usage: cidr -Classless Inter-Domain Routing CIDRv4 +# Classless Inter-Domain Routing CIDRv4 This validates that a string value contains a valid v4 CIDR Address. Usage: cidrv4 -Classless Inter-Domain Routing CIDRv6 +# Classless Inter-Domain Routing CIDRv6 This validates that a string value contains a valid v6 CIDR Address. Usage: cidrv6 -Transmission Control Protocol Address TCP +# Transmission Control Protocol Address TCP This validates that a string value contains a valid resolvable TCP Address. Usage: tcp_addr -Transmission Control Protocol Address TCPv4 +# Transmission Control Protocol Address TCPv4 This validates that a string value contains a valid resolvable v4 TCP Address. Usage: tcp4_addr -Transmission Control Protocol Address TCPv6 +# Transmission Control Protocol Address TCPv6 This validates that a string value contains a valid resolvable v6 TCP Address. Usage: tcp6_addr -User Datagram Protocol Address UDP +# User Datagram Protocol Address UDP This validates that a string value contains a valid resolvable UDP Address. Usage: udp_addr -User Datagram Protocol Address UDPv4 +# User Datagram Protocol Address UDPv4 This validates that a string value contains a valid resolvable v4 UDP Address. Usage: udp4_addr -User Datagram Protocol Address UDPv6 +# User Datagram Protocol Address UDPv6 This validates that a string value contains a valid resolvable v6 UDP Address. Usage: udp6_addr -Internet Protocol Address IP +# Internet Protocol Address IP This validates that a string value contains a valid resolvable IP Address. Usage: ip_addr -Internet Protocol Address IPv4 +# Internet Protocol Address IPv4 This validates that a string value contains a valid resolvable v4 IP Address. Usage: ip4_addr -Internet Protocol Address IPv6 +# Internet Protocol Address IPv6 This validates that a string value contains a valid resolvable v6 IP Address. Usage: ip6_addr -Unix domain socket end point Address +# Unix domain socket end point Address This validates that a string value contains a valid Unix Address. Usage: unix_addr -Media Access Control Address MAC +# Media Access Control Address MAC This validates that a string value contains a valid MAC Address. @@ -1199,13 +1225,13 @@ Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 -Hostname RFC 952 +# Hostname RFC 952 This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 Usage: hostname -Hostname RFC 1123 +# Hostname RFC 1123 This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 @@ -1217,28 +1243,28 @@ This validates that a string value contains a valid FQDN. Usage: fqdn -HTML Tags +# HTML Tags This validates that a string value appears to be an HTML element tag including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element Usage: html -HTML Encoded +# HTML Encoded This validates that a string value is a proper character reference in decimal or hexadecimal format Usage: html_encoded -URL Encoded +# URL Encoded This validates that a string value is percent-encoded (URL encoded) according to https://tools.ietf.org/html/rfc3986#section-2.1 Usage: url_encoded -Directory +# Directory This validates that a string value contains a valid directory and that it exists on the machine. @@ -1246,42 +1272,52 @@ This is done using os.Stat, which is a platform independent function. Usage: dir -HostPort +# Directory Path + +This validates that a string value contains a valid directory but does +not validate the existence of that directory. +This is done using os.Stat, which is a platform independent function. +It is safest to suffix the string with os.PathSeparator if the directory +may not exist at the time of validation. + + Usage: dirpath + +# HostPort This validates that a string value contains a valid DNS hostname and port that can be used to valiate fields typically passed to sockets and connections. Usage: hostname_port -Datetime +# Datetime This validates that a string value is a valid datetime based on the supplied datetime format. Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ Usage: datetime=2006-01-02 -Iso3166-1 alpha-2 +# Iso3166-1 alpha-2 This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha2 -Iso3166-1 alpha-3 +# Iso3166-1 alpha-3 This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 -Iso3166-1 alpha-numeric +# Iso3166-1 alpha-numeric This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 -BCP 47 Language Tag +# BCP 47 Language Tag This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. More information on https://pkg.go.dev/golang.org/x/text/language @@ -1295,14 +1331,14 @@ More information on https://www.iso.org/standard/60390.html Usage: bic -RFC 1035 label +# RFC 1035 label This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035. More information on https://datatracker.ietf.org/doc/html/rfc1035 Usage: dns_rfc1035_label -TimeZone +# TimeZone This validates that a string value is a valid time zone based on the time zone database present on the system. Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. @@ -1310,21 +1346,47 @@ More information on https://golang.org/pkg/time/#LoadLocation Usage: timezone -Semantic Version +# Semantic Version This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0. More information on https://semver.org/ Usage: semver -Credit Card +# CVE Identifier -This validates that a string value contains a valid credit card number using Luhn algoritm. +This validates that a string value is a valid cve id, defined in cve mitre. +More information on https://cve.mitre.org/ + + Usage: cve + +# Credit Card + +This validates that a string value contains a valid credit card number using Luhn algorithm. Usage: credit_card -Alias Validators and Tags +# Luhn Checksum + + Usage: luhn_checksum +This validates that a string or (u)int value contains a valid checksum using the Luhn algorithm. + +# MongoDb ObjectID + +This validates that a string is a valid 24 character hexadecimal string. + + Usage: mongodb + +# Cron + +This validates that a string value contains a valid cron expression. + + Usage: cron + +# Alias Validators and Tags + +Alias Validators and Tags NOTE: When returning an error, the tag returned in "FieldError" will be the alias tag unless the dive tag is part of the alias. Everything after the dive tag is not reported as the alias tag. Also, the "ActualTag" in the before @@ -1354,7 +1416,7 @@ Validator notes: And the best reason, you can submit a pull request and we can keep on adding to the validation library of this package! -Non standard validators +# Non standard validators A collection of validation rules that are frequently needed but are more complex than the ones found in the baked in validators. @@ -1383,7 +1445,7 @@ Here is a list of the current non standard validators: Usage: notblank -Panics +# Panics This package panics when bad input is provided, this is by design, bad code like that should not make it to production. diff --git a/vendor/github.com/go-playground/validator/v10/errors.go b/vendor/github.com/go-playground/validator/v10/errors.go index 9a1b1ab..5856d57 100644 --- a/vendor/github.com/go-playground/validator/v10/errors.go +++ b/vendor/github.com/go-playground/validator/v10/errors.go @@ -44,12 +44,9 @@ func (ve ValidationErrors) Error() string { buff := bytes.NewBufferString("") - var fe *fieldError - for i := 0; i < len(ve); i++ { - fe = ve[i].(*fieldError) - buff.WriteString(fe.Error()) + buff.WriteString(ve[i].Error()) buff.WriteString("\n") } diff --git a/vendor/github.com/go-playground/validator/v10/regexes.go b/vendor/github.com/go-playground/validator/v10/regexes.go index 9c1c634..ba450b3 100644 --- a/vendor/github.com/go-playground/validator/v10/regexes.go +++ b/vendor/github.com/go-playground/validator/v10/regexes.go @@ -19,6 +19,7 @@ const ( e164RegexString = "^\\+[1-9]?[0-9]{7,14}$" base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$" + base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$" iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" @@ -64,6 +65,9 @@ const ( bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/ dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$" + cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html + mongodbRegexString = "^[a-f\\d]{24}$" + cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})` ) var ( @@ -83,6 +87,7 @@ var ( emailRegex = regexp.MustCompile(emailRegexString) base64Regex = regexp.MustCompile(base64RegexString) base64URLRegex = regexp.MustCompile(base64URLRegexString) + base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString) iSBN10Regex = regexp.MustCompile(iSBN10RegexString) iSBN13Regex = regexp.MustCompile(iSBN13RegexString) uUID3Regex = regexp.MustCompile(uUID3RegexString) @@ -118,8 +123,6 @@ var ( btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) ethAddressRegex = regexp.MustCompile(ethAddressRegexString) - ethAddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) - ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString) @@ -128,4 +131,7 @@ var ( bicRegex = regexp.MustCompile(bicRegexString) semverRegex = regexp.MustCompile(semverRegexString) dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label) + cveRegex = regexp.MustCompile(cveRegexString) + mongodbRegex = regexp.MustCompile(mongodbRegexString) + cronRegex = regexp.MustCompile(cronRegexString) ) diff --git a/vendor/github.com/go-playground/validator/v10/struct_level.go b/vendor/github.com/go-playground/validator/v10/struct_level.go index c0d89cf..271328f 100644 --- a/vendor/github.com/go-playground/validator/v10/struct_level.go +++ b/vendor/github.com/go-playground/validator/v10/struct_level.go @@ -62,7 +62,7 @@ type StructLevel interface { // existing namespace that validator is on. // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending // on the nesting. most of the time they will be blank, unless you validate - // at a level lower the the current field depth + // at a level lower the current field depth ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) } @@ -74,7 +74,7 @@ var _ StructLevel = new(validate) // if not is a nested struct. // // this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. +// should not be relied upon for an accurate value otherwise. func (v *validate) Top() reflect.Value { return v.top } @@ -85,7 +85,7 @@ func (v *validate) Top() reflect.Value { // if not is a nested struct. // // this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. +// should not be relied upon for an accurate value otherwise. func (v *validate) Parent() reflect.Value { return v.slflParent } diff --git a/vendor/github.com/go-playground/validator/v10/util.go b/vendor/github.com/go-playground/validator/v10/util.go index 36da855..3925cfe 100644 --- a/vendor/github.com/go-playground/validator/v10/util.go +++ b/vendor/github.com/go-playground/validator/v10/util.go @@ -234,7 +234,7 @@ func asInt(param string) int64 { func asIntFromTimeDuration(param string) int64 { d, err := time.ParseDuration(param) if err != nil { - // attempt parsing as an an integer assuming nanosecond precision + // attempt parsing as an integer assuming nanosecond precision return asInt(param) } return int64(d) diff --git a/vendor/github.com/go-playground/validator/v10/validator.go b/vendor/github.com/go-playground/validator/v10/validator.go index 80da095..6f6d53a 100644 --- a/vendor/github.com/go-playground/validator/v10/validator.go +++ b/vendor/github.com/go-playground/validator/v10/validator.go @@ -452,7 +452,6 @@ OUTER: v.ct = ct if !ct.fn(ctx, v) { - v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { diff --git a/vendor/github.com/go-playground/validator/v10/validator_instance.go b/vendor/github.com/go-playground/validator/v10/validator_instance.go index 9493da4..d2ee8fe 100644 --- a/vendor/github.com/go-playground/validator/v10/validator_instance.go +++ b/vendor/github.com/go-playground/validator/v10/validator_instance.go @@ -29,6 +29,7 @@ const ( requiredWithAllTag = "required_with_all" requiredIfTag = "required_if" requiredUnlessTag = "required_unless" + skipUnlessTag = "skip_unless" excludedWithoutAllTag = "excluded_without_all" excludedWithoutTag = "excluded_without" excludedWithTag = "excluded_with" @@ -57,7 +58,7 @@ var ( // FilterFunc is the type used to filter fields using // StructFiltered(...) function. -// returning true results in the field being filtered/skiped from +// returning true results in the field being filtered/skipped from // validation type FilterFunc func(ns []byte) bool @@ -123,7 +124,8 @@ func New() *Validate { switch k { // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, - excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: + excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag, + skipUnlessTag: _ = v.registerValidation(k, wrapFunc(val), true, true) default: // no need to error check here, baked in will always be valid @@ -151,7 +153,7 @@ func (v *Validate) SetTagName(name string) { } // ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual -// validation validation information via context.Context. +// validation information via context.Context. func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { errs := make(map[string]interface{}) for field, rule := range rules { @@ -190,14 +192,14 @@ func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]int // // eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: // -// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { -// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] -// // skip if tag key says it should be ignored -// if name == "-" { -// return "" -// } -// return name -// }) +// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { +// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] +// // skip if tag key says it should be ignored +// if name == "-" { +// return "" +// } +// return name +// }) func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { v.tagNameFunc = fn v.hasTagNameFunc = true @@ -451,7 +453,7 @@ func (v *Validate) StructPartial(s interface{}, fields ...string) error { } // StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual -// validation validation information via context.Context +// validation information via context.Context // Fields may be provided in a namespaced fashion relative to the struct provided // eg. NestedStruct.Field or NestedArrayField[0].Struct.Name // @@ -541,7 +543,7 @@ func (v *Validate) StructExcept(s interface{}, fields ...string) error { } // StructExceptCtx validates all fields except the ones passed in and allows passing of contextual -// validation validation information via context.Context +// validation information via context.Context // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name // @@ -613,7 +615,7 @@ func (v *Validate) Var(field interface{}, tag string) error { } // VarCtx validates a single variable using tag style validation and allows passing of contextual -// validation validation information via context.Context. +// validation information via context.Context. // eg. // var i int // validate.Var(i, "gt=1,lt=10") @@ -632,6 +634,7 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e } ctag := v.fetchCacheTag(tag) + val := reflect.ValueOf(field) vd := v.pool.Get().(*validate) vd.top = val diff --git a/vendor/github.com/goccy/go-json/CHANGELOG.md b/vendor/github.com/goccy/go-json/CHANGELOG.md index d63009f..d09bb89 100644 --- a/vendor/github.com/goccy/go-json/CHANGELOG.md +++ b/vendor/github.com/goccy/go-json/CHANGELOG.md @@ -1,3 +1,35 @@ +# v0.10.2 - 2023/03/20 + +### New features + +* Support DebugDOT option for debugging encoder ( #440 ) + +### Fix bugs + +* Fix combination of embedding structure and omitempty option ( #442 ) + +# v0.10.1 - 2023/03/13 + +### Fix bugs + +* Fix checkptr error for array decoder ( #415 ) +* Fix added buffer size check when decoding key ( #430 ) +* Fix handling of anonymous fields other than struct ( #431 ) +* Fix to not optimize when lower conversion can't handle byte-by-byte ( #432 ) +* Fix a problem that MarshalIndent does not work when UnorderedMap is specified ( #435 ) +* Fix mapDecoder.DecodeStream() for empty objects containing whitespace ( #425 ) +* Fix an issue that could not set the correct NextField for fields in the embedded structure ( #438 ) + +# v0.10.0 - 2022/11/29 + +### New features + +* Support JSON Path ( #250 ) + +### Fix bugs + +* Fix marshaler for map's key ( #409 ) + # v0.9.11 - 2022/08/18 ### Fix bugs diff --git a/vendor/github.com/goccy/go-json/Makefile b/vendor/github.com/goccy/go-json/Makefile index 363563a..5bbfc4c 100644 --- a/vendor/github.com/goccy/go-json/Makefile +++ b/vendor/github.com/goccy/go-json/Makefile @@ -22,7 +22,7 @@ cover-html: cover .PHONY: lint lint: golangci-lint - golangci-lint run + $(BIN_DIR)/golangci-lint run golangci-lint: | $(BIN_DIR) @{ \ @@ -30,7 +30,7 @@ golangci-lint: | $(BIN_DIR) GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \ cd $$GOLANGCI_LINT_TMP_DIR; \ go mod init tmp; \ - GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \ + GOBIN=$(BIN_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.48.0; \ rm -rf $$GOLANGCI_LINT_TMP_DIR; \ } diff --git a/vendor/github.com/goccy/go-json/README.md b/vendor/github.com/goccy/go-json/README.md index 5686237..7bacc54 100644 --- a/vendor/github.com/goccy/go-json/README.md +++ b/vendor/github.com/goccy/go-json/README.md @@ -184,7 +184,7 @@ func Marshal(v interface{}) ([]byte, error) { `json.Marshal` and `json.Unmarshal` receive `interface{}` value and they perform type determination dynamically to process. In normal case, you need to use the `reflect` library to determine the type dynamically, but since `reflect.Type` is defined as `interface`, when you call the method of `reflect.Type`, The reflect's argument is escaped. -Therefore, the arguments for `Marshal` and `Unmarshal` are always escape to the heap. +Therefore, the arguments for `Marshal` and `Unmarshal` are always escaped to the heap. However, `go-json` can use the feature of `reflect.Type` while avoiding escaping. `reflect.Type` is defined as `interface`, but in reality `reflect.Type` is implemented only by the structure `rtype` defined in the `reflect` package. diff --git a/vendor/github.com/goccy/go-json/decode.go b/vendor/github.com/goccy/go-json/decode.go index d99749d..74c6ac3 100644 --- a/vendor/github.com/goccy/go-json/decode.go +++ b/vendor/github.com/goccy/go-json/decode.go @@ -83,6 +83,37 @@ func unmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs return validateEndBuf(src, cursor) } +var ( + pathDecoder = decoder.NewPathDecoder() +) + +func extractFromPath(path *Path, data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) { + if path.path.RootSelectorOnly { + return [][]byte{data}, nil + } + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + ctx := decoder.TakeRuntimeContext() + ctx.Buf = src + ctx.Option.Flags = 0 + ctx.Option.Flags |= decoder.PathOption + ctx.Option.Path = path.path + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + paths, cursor, err := pathDecoder.DecodePath(ctx, 0, 0) + if err != nil { + decoder.ReleaseRuntimeContext(ctx) + return nil, err + } + decoder.ReleaseRuntimeContext(ctx) + if err := validateEndBuf(src, cursor); err != nil { + return nil, err + } + return paths, nil +} + func unmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { src := make([]byte, len(data)+1) // append nul byte to the end copy(src, data) diff --git a/vendor/github.com/goccy/go-json/error.go b/vendor/github.com/goccy/go-json/error.go index 94c1339..5b2dcee 100644 --- a/vendor/github.com/goccy/go-json/error.go +++ b/vendor/github.com/goccy/go-json/error.go @@ -37,3 +37,5 @@ type UnmarshalTypeError = errors.UnmarshalTypeError type UnsupportedTypeError = errors.UnsupportedTypeError type UnsupportedValueError = errors.UnsupportedValueError + +type PathError = errors.PathError diff --git a/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go b/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go index 030cb7a..b6876cf 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go @@ -35,3 +35,7 @@ func (d *anonymousFieldDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p = *(*unsafe.Pointer)(p) return d.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset)) } + +func (d *anonymousFieldDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return d.dec.DecodePath(ctx, cursor, depth) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/array.go b/vendor/github.com/goccy/go-json/internal/decoder/array.go index 21f1fd5..4b23ed4 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/array.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/array.go @@ -1,6 +1,7 @@ package decoder import ( + "fmt" "unsafe" "github.com/goccy/go-json/internal/errors" @@ -18,7 +19,9 @@ type arrayDecoder struct { } func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder { - zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType)) + // workaround to avoid checkptr errors. cannot use `*(*unsafe.Pointer)(unsafe_New(elemType))` directly. + zeroValuePtr := unsafe_New(elemType) + zeroValue := **(**unsafe.Pointer)(unsafe.Pointer(&zeroValuePtr)) return &arrayDecoder{ valueDecoder: dec, elemType: elemType, @@ -167,3 +170,7 @@ func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe } } } + +func (d *arrayDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: array decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/assign.go b/vendor/github.com/goccy/go-json/internal/decoder/assign.go new file mode 100644 index 0000000..c53e6ad --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/assign.go @@ -0,0 +1,438 @@ +package decoder + +import ( + "fmt" + "reflect" + "strconv" +) + +var ( + nilValue = reflect.ValueOf(nil) +) + +func AssignValue(src, dst reflect.Value) error { + if dst.Type().Kind() != reflect.Ptr { + return fmt.Errorf("invalid dst type. required pointer type: %T", dst.Type()) + } + casted, err := castValue(dst.Elem().Type(), src) + if err != nil { + return err + } + dst.Elem().Set(casted) + return nil +} + +func castValue(t reflect.Type, v reflect.Value) (reflect.Value, error) { + switch t.Kind() { + case reflect.Int: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int(vv.Int())), nil + case reflect.Int8: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int8(vv.Int())), nil + case reflect.Int16: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int16(vv.Int())), nil + case reflect.Int32: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int32(vv.Int())), nil + case reflect.Int64: + return castInt(v) + case reflect.Uint: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint(vv.Uint())), nil + case reflect.Uint8: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint8(vv.Uint())), nil + case reflect.Uint16: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint16(vv.Uint())), nil + case reflect.Uint32: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint32(vv.Uint())), nil + case reflect.Uint64: + return castUint(v) + case reflect.Uintptr: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uintptr(vv.Uint())), nil + case reflect.String: + return castString(v) + case reflect.Bool: + return castBool(v) + case reflect.Float32: + vv, err := castFloat(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(float32(vv.Float())), nil + case reflect.Float64: + return castFloat(v) + case reflect.Array: + return castArray(t, v) + case reflect.Slice: + return castSlice(t, v) + case reflect.Map: + return castMap(t, v) + case reflect.Struct: + return castStruct(t, v) + } + return v, nil +} + +func castInt(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(int64(v.Uint())), nil + case reflect.String: + i64, err := strconv.ParseInt(v.String(), 10, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(i64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(int64(1)), nil + } + return reflect.ValueOf(int64(0)), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(int64(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castInt(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to int64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castInt(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to int64 from empty slice") + case reflect.Interface: + return castInt(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to int64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to int64 from struct") + case reflect.Ptr: + return castInt(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to int64 from %s", v.Type().Kind()) +} + +func castUint(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(uint64(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v, nil + case reflect.String: + u64, err := strconv.ParseUint(v.String(), 10, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(u64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(uint64(1)), nil + } + return reflect.ValueOf(uint64(0)), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(uint64(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castUint(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castUint(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from empty slice") + case reflect.Interface: + return castUint(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to uint64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to uint64 from struct") + case reflect.Ptr: + return castUint(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from %s", v.Type().Kind()) +} + +func castString(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(fmt.Sprint(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(fmt.Sprint(v.Uint())), nil + case reflect.String: + return v, nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf("true"), nil + } + return reflect.ValueOf("false"), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(fmt.Sprint(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castString(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castString(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty slice") + case reflect.Interface: + return castString(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to string from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to string from struct") + case reflect.Ptr: + return castString(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to string from %s", v.Type().Kind()) +} + +func castBool(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch v.Int() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch v.Uint() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Uint()) + case reflect.String: + b, err := strconv.ParseBool(v.String()) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(b), nil + case reflect.Bool: + return v, nil + case reflect.Float32, reflect.Float64: + switch v.Float() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %f", v.Float()) + case reflect.Array: + if v.Len() > 0 { + return castBool(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castBool(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty slice") + case reflect.Interface: + return castBool(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to string from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to string from struct") + case reflect.Ptr: + return castBool(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to bool from %s", v.Type().Kind()) +} + +func castFloat(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(float64(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(float64(v.Uint())), nil + case reflect.String: + f64, err := strconv.ParseFloat(v.String(), 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(f64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(float64(1)), nil + } + return reflect.ValueOf(float64(0)), nil + case reflect.Float32, reflect.Float64: + return v, nil + case reflect.Array: + if v.Len() > 0 { + return castFloat(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to float64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castFloat(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to float64 from empty slice") + case reflect.Interface: + return castFloat(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to float64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to float64 from struct") + case reflect.Ptr: + return castFloat(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to float64 from %s", v.Type().Kind()) +} + +func castArray(t reflect.Type, v reflect.Value) (reflect.Value, error) { + kind := v.Type().Kind() + if kind == reflect.Interface { + return castArray(t, reflect.ValueOf(v.Interface())) + } + if kind != reflect.Slice && kind != reflect.Array { + return nilValue, fmt.Errorf("failed to cast to array from %s", kind) + } + if t.Elem() == v.Type().Elem() { + return v, nil + } + if t.Len() != v.Len() { + return nilValue, fmt.Errorf("failed to cast [%d]array from slice of %d length", t.Len(), v.Len()) + } + ret := reflect.New(t).Elem() + for i := 0; i < v.Len(); i++ { + vv, err := castValue(t.Elem(), v.Index(i)) + if err != nil { + return nilValue, err + } + ret.Index(i).Set(vv) + } + return ret, nil +} + +func castSlice(t reflect.Type, v reflect.Value) (reflect.Value, error) { + kind := v.Type().Kind() + if kind == reflect.Interface { + return castSlice(t, reflect.ValueOf(v.Interface())) + } + if kind != reflect.Slice && kind != reflect.Array { + return nilValue, fmt.Errorf("failed to cast to slice from %s", kind) + } + if t.Elem() == v.Type().Elem() { + return v, nil + } + ret := reflect.MakeSlice(t, v.Len(), v.Len()) + for i := 0; i < v.Len(); i++ { + vv, err := castValue(t.Elem(), v.Index(i)) + if err != nil { + return nilValue, err + } + ret.Index(i).Set(vv) + } + return ret, nil +} + +func castMap(t reflect.Type, v reflect.Value) (reflect.Value, error) { + ret := reflect.MakeMap(t) + switch v.Type().Kind() { + case reflect.Map: + iter := v.MapRange() + for iter.Next() { + key, err := castValue(t.Key(), iter.Key()) + if err != nil { + return nilValue, err + } + value, err := castValue(t.Elem(), iter.Value()) + if err != nil { + return nilValue, err + } + ret.SetMapIndex(key, value) + } + return ret, nil + case reflect.Interface: + return castMap(t, reflect.ValueOf(v.Interface())) + case reflect.Slice: + if v.Len() > 0 { + return castMap(t, v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to map from empty slice") + } + return nilValue, fmt.Errorf("failed to cast to map from %s", v.Type().Kind()) +} + +func castStruct(t reflect.Type, v reflect.Value) (reflect.Value, error) { + ret := reflect.New(t).Elem() + switch v.Type().Kind() { + case reflect.Map: + iter := v.MapRange() + for iter.Next() { + key := iter.Key() + k, err := castString(key) + if err != nil { + return nilValue, err + } + fieldName := k.String() + field, ok := t.FieldByName(fieldName) + if ok { + value, err := castValue(field.Type, iter.Value()) + if err != nil { + return nilValue, err + } + ret.FieldByName(fieldName).Set(value) + } + } + return ret, nil + case reflect.Struct: + for i := 0; i < v.Type().NumField(); i++ { + name := v.Type().Field(i).Name + ret.FieldByName(name).Set(v.FieldByName(name)) + } + return ret, nil + case reflect.Interface: + return castStruct(t, reflect.ValueOf(v.Interface())) + case reflect.Slice: + if v.Len() > 0 { + return castStruct(t, v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to struct from empty slice") + default: + return nilValue, fmt.Errorf("failed to cast to struct from %s", v.Type().Kind()) + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/bool.go b/vendor/github.com/goccy/go-json/internal/decoder/bool.go index 455042a..ba6cf5b 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/bool.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/bool.go @@ -1,6 +1,7 @@ package decoder import ( + "fmt" "unsafe" "github.com/goccy/go-json/internal/errors" @@ -76,3 +77,7 @@ func (d *boolDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe. } return 0, errors.ErrUnexpectedEndOfJSON("bool", cursor) } + +func (d *boolDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: bool decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/bytes.go b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go index 92c7dcf..939bf43 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/bytes.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go @@ -2,6 +2,7 @@ package decoder import ( "encoding/base64" + "fmt" "unsafe" "github.com/goccy/go-json/internal/errors" @@ -78,6 +79,10 @@ func (d *bytesDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe return cursor, nil } +func (d *bytesDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: []byte decoder does not support decode path") +} + func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) { c := s.skipWhiteSpace() if c == '[' { diff --git a/vendor/github.com/goccy/go-json/internal/decoder/float.go b/vendor/github.com/goccy/go-json/internal/decoder/float.go index dfb7168..9b2eb8b 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/float.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/float.go @@ -156,3 +156,15 @@ func (d *floatDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe d.op(p, f64) return cursor, nil } + +func (d *floatDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + bytes, c, err := d.decodeByte(buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/func.go b/vendor/github.com/goccy/go-json/internal/decoder/func.go index ee35637..4cc12ca 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/func.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/func.go @@ -2,6 +2,7 @@ package decoder import ( "bytes" + "fmt" "unsafe" "github.com/goccy/go-json/internal/errors" @@ -139,3 +140,7 @@ func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe. } return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) } + +func (d *funcDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: func decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/int.go b/vendor/github.com/goccy/go-json/internal/decoder/int.go index 509b753..1a7f081 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/int.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/int.go @@ -240,3 +240,7 @@ func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P d.op(p, i64) return cursor, nil } + +func (d *intDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: int decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/interface.go b/vendor/github.com/goccy/go-json/internal/decoder/interface.go index 4dbb4be..45c69ab 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/interface.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/interface.go @@ -94,6 +94,7 @@ func (d *interfaceDecoder) numDecoder(s *Stream) Decoder { var ( emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem()) + EmptyInterfaceType = emptyInterfaceType interfaceMapType = runtime.Type2RType( reflect.TypeOf((*map[string]interface{})(nil)).Elem(), ) @@ -456,3 +457,72 @@ func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, dep } return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) } + +func NewPathDecoder() Decoder { + ifaceDecoder := &interfaceDecoder{ + typ: emptyInterfaceType, + structName: "", + fieldName: "", + floatDecoder: newFloatDecoder("", "", func(p unsafe.Pointer, v float64) { + *(*interface{})(p) = v + }), + numberDecoder: newNumberDecoder("", "", func(p unsafe.Pointer, v json.Number) { + *(*interface{})(p) = v + }), + stringDecoder: newStringDecoder("", ""), + } + ifaceDecoder.sliceDecoder = newSliceDecoder( + ifaceDecoder, + emptyInterfaceType, + emptyInterfaceType.Size(), + "", "", + ) + ifaceDecoder.mapDecoder = newMapDecoder( + interfaceMapType, + stringType, + ifaceDecoder.stringDecoder, + interfaceMapType.Elem(), + ifaceDecoder, + "", "", + ) + return ifaceDecoder +} + +var ( + truebytes = []byte("true") + falsebytes = []byte("false") +) + +func (d *interfaceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case '{': + return d.mapDecoder.DecodePath(ctx, cursor, depth) + case '[': + return d.sliceDecoder.DecodePath(ctx, cursor, depth) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return d.floatDecoder.DecodePath(ctx, cursor, depth) + case '"': + return d.stringDecoder.DecodePath(ctx, cursor, depth) + case 't': + if err := validateTrue(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{truebytes}, cursor, nil + case 'f': + if err := validateFalse(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 5 + return [][]byte{falsebytes}, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + } + return nil, cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/invalid.go b/vendor/github.com/goccy/go-json/internal/decoder/invalid.go index 1ef50a7..4c9721b 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/invalid.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/invalid.go @@ -43,3 +43,13 @@ func (d *invalidDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsa Field: d.fieldName, } } + +func (d *invalidDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: cursor, + Struct: d.structName, + Field: d.fieldName, + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/map.go b/vendor/github.com/goccy/go-json/internal/decoder/map.go index cb55ef0..07a9cae 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/map.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/map.go @@ -88,7 +88,7 @@ func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro mapValue = makemap(d.mapType, 0) } s.cursor++ - if s.equalChar('}') { + if s.skipWhiteSpace() == '}' { *(*unsafe.Pointer)(p) = mapValue s.cursor++ return nil @@ -185,3 +185,96 @@ func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P cursor++ } } + +func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + cursor = skipWhiteSpace(buf, cursor) + buflen := int64(len(buf)) + if buflen < 2 { + return nil, 0, errors.ErrExpected("{} for map", cursor) + } + switch buf[cursor] { + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + case '{': + default: + return nil, 0, errors.ErrExpected("{ character for map value", cursor) + } + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return nil, cursor, nil + } + keyDecoder, ok := d.keyDecoder.(*stringDecoder) + if !ok { + return nil, 0, &errors.UnmarshalTypeError{ + Value: "string", + Type: reflect.TypeOf(""), + Offset: cursor, + Struct: d.structName, + Field: d.fieldName, + } + } + ret := [][]byte{} + for { + key, keyCursor, err := keyDecoder.decodeByte(buf, cursor) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(buf, keyCursor) + if buf[cursor] != ':' { + return nil, 0, errors.ErrExpected("colon after object key", cursor) + } + cursor++ + child, found, err := ctx.Option.Path.Field(string(key)) + if err != nil { + return nil, 0, err + } + if found { + if child != nil { + oldPath := ctx.Option.Path.node + ctx.Option.Path.node = child + paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) + if err != nil { + return nil, 0, err + } + ctx.Option.Path.node = oldPath + ret = append(ret, paths...) + cursor = c + } else { + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + ret = append(ret, buf[start:end]) + cursor = end + } + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + cursor = c + } + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return ret, cursor, nil + } + if buf[cursor] != ',' { + return nil, 0, errors.ErrExpected("comma after object value", cursor) + } + cursor++ + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/number.go b/vendor/github.com/goccy/go-json/internal/decoder/number.go index bf63773..10e5435 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/number.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/number.go @@ -51,6 +51,17 @@ func (d *numberDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsaf return cursor, nil } +func (d *numberDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, nil +} + func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { start := s.cursor for { diff --git a/vendor/github.com/goccy/go-json/internal/decoder/option.go b/vendor/github.com/goccy/go-json/internal/decoder/option.go index e41f876..502f772 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/option.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/option.go @@ -7,9 +7,11 @@ type OptionFlags uint8 const ( FirstWinOption OptionFlags = 1 << iota ContextOption + PathOption ) type Option struct { Flags OptionFlags Context context.Context + Path *Path } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/path.go b/vendor/github.com/goccy/go-json/internal/decoder/path.go new file mode 100644 index 0000000..a15ff69 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/path.go @@ -0,0 +1,670 @@ +package decoder + +import ( + "fmt" + "reflect" + "strconv" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type PathString string + +func (s PathString) Build() (*Path, error) { + builder := new(PathBuilder) + return builder.Build([]rune(s)) +} + +type PathBuilder struct { + root PathNode + node PathNode + singleQuotePathSelector bool + doubleQuotePathSelector bool +} + +func (b *PathBuilder) Build(buf []rune) (*Path, error) { + node, err := b.build(buf) + if err != nil { + return nil, err + } + return &Path{ + node: node, + RootSelectorOnly: node == nil, + SingleQuotePathSelector: b.singleQuotePathSelector, + DoubleQuotePathSelector: b.doubleQuotePathSelector, + }, nil +} + +func (b *PathBuilder) build(buf []rune) (PathNode, error) { + if len(buf) == 0 { + return nil, errors.ErrEmptyPath() + } + if buf[0] != '$' { + return nil, errors.ErrInvalidPath("JSON Path must start with a $ character") + } + if len(buf) == 1 { + return nil, nil + } + buf = buf[1:] + offset, err := b.buildNext(buf) + if err != nil { + return nil, err + } + if len(buf) > offset { + return nil, errors.ErrInvalidPath("remain invalid path %q", buf[offset:]) + } + return b.root, nil +} + +func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) { + if len(buf) > cursor { + offset, err := b.buildNext(buf[cursor:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + return cursor, nil +} + +func (b *PathBuilder) buildNext(buf []rune) (int, error) { + switch buf[0] { + case '.': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + offset, err := b.buildSelector(buf[1:]) + if err != nil { + return 0, err + } + return offset + 1, nil + case '[': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + offset, err := b.buildIndex(buf[1:]) + if err != nil { + return 0, err + } + return offset + 1, nil + default: + return 0, errors.ErrInvalidPath("expect dot or left bracket character. but found %c character", buf[0]) + } +} + +func (b *PathBuilder) buildSelector(buf []rune) (int, error) { + switch buf[0] { + case '.': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with double dot character") + } + offset, err := b.buildPathRecursive(buf[1:]) + if err != nil { + return 0, err + } + return 1 + offset, nil + case '[', ']', '$', '*': + return 0, errors.ErrInvalidPath("found invalid path character %c after dot", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '$', '*', ']': + return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor]) + case '.': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + offset, err := b.buildSelector(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '[': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + offset, err := b.buildIndex(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '"': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with double quote character") + } + offset, err := b.buildQuoteSelector(buf[cursor+1:], DoubleQuotePathSelector) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + } + b.addSelectorNode(string(buf)) + return len(buf), nil +} + +func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int, error) { + switch buf[0] { + case '[', ']', '$', '.', '*', '\'', '"': + return 0, errors.ErrInvalidPath("found invalid path character %c after quote", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '\'': + if sel != SingleQuotePathSelector { + return 0, errors.ErrInvalidPath("found double quote character in field selector with single quote context") + } + if len(buf) <= cursor+1 { + return 0, errors.ErrInvalidPath("JSON Path ends with single quote character in field selector context") + } + if buf[cursor+1] != ']' { + return 0, errors.ErrInvalidPath("expect right bracket for field selector with single quote but found %c", buf[cursor+1]) + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + b.singleQuotePathSelector = true + return b.buildNextCharIfExists(buf, cursor+2) + case '"': + if sel != DoubleQuotePathSelector { + return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + b.doubleQuotePathSelector = true + return b.buildNextCharIfExists(buf, cursor+1) + } + } + return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context") +} + +func (b *PathBuilder) buildPathRecursive(buf []rune) (int, error) { + switch buf[0] { + case '.', '[', ']', '$', '*': + return 0, errors.ErrInvalidPath("found invalid path character %c after double dot", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '$', '*', ']': + return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor]) + case '.': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + selector := buf[:cursor] + b.addRecursiveNode(string(selector)) + offset, err := b.buildSelector(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '[': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + selector := buf[:cursor] + b.addRecursiveNode(string(selector)) + offset, err := b.buildIndex(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + } + b.addRecursiveNode(string(buf)) + return len(buf), nil +} + +func (b *PathBuilder) buildIndex(buf []rune) (int, error) { + switch buf[0] { + case '.', '[', ']', '$': + return 0, errors.ErrInvalidPath("found invalid path character %c after left bracket", buf[0]) + case '\'': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with single quote character") + } + offset, err := b.buildQuoteSelector(buf[1:], SingleQuotePathSelector) + if err != nil { + return 0, err + } + return 1 + offset, nil + case '*': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with star character") + } + if buf[1] != ']' { + return 0, errors.ErrInvalidPath("expect right bracket character for index all path but found %c character", buf[1]) + } + b.addIndexAllNode() + offset := len("*]") + if len(buf) > 2 { + buildOffset, err := b.buildNext(buf[2:]) + if err != nil { + return 0, err + } + return offset + buildOffset, nil + } + return offset, nil + } + + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case ']': + index, err := strconv.ParseInt(string(buf[:cursor]), 10, 64) + if err != nil { + return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor]) + } + b.addIndexNode(int(index)) + return b.buildNextCharIfExists(buf, cursor+1) + } + } + return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context") +} + +func (b *PathBuilder) addIndexAllNode() { + node := newPathIndexAllNode() + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addRecursiveNode(selector string) { + node := newPathRecursiveNode(selector) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addSelectorNode(name string) { + node := newPathSelectorNode(name) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addIndexNode(idx int) { + node := newPathIndexNode(idx) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +type QuotePathSelector int + +const ( + SingleQuotePathSelector QuotePathSelector = 1 + DoubleQuotePathSelector QuotePathSelector = 2 +) + +type Path struct { + node PathNode + RootSelectorOnly bool + SingleQuotePathSelector bool + DoubleQuotePathSelector bool +} + +func (p *Path) Field(sel string) (PathNode, bool, error) { + if p.node == nil { + return nil, false, nil + } + return p.node.Field(sel) +} + +func (p *Path) Get(src, dst reflect.Value) error { + if p.node == nil { + return nil + } + return p.node.Get(src, dst) +} + +func (p *Path) String() string { + if p.node == nil { + return "$" + } + return p.node.String() +} + +type PathNode interface { + fmt.Stringer + Index(idx int) (PathNode, bool, error) + Field(fieldName string) (PathNode, bool, error) + Get(src, dst reflect.Value) error + chain(PathNode) PathNode + target() bool + single() bool +} + +type BasePathNode struct { + child PathNode +} + +func (n *BasePathNode) chain(node PathNode) PathNode { + n.child = node + return node +} + +func (n *BasePathNode) target() bool { + return n.child == nil +} + +func (n *BasePathNode) single() bool { + return true +} + +type PathSelectorNode struct { + *BasePathNode + selector string +} + +func newPathSelectorNode(selector string) *PathSelectorNode { + return &PathSelectorNode{ + BasePathNode: &BasePathNode{}, + selector: selector, + } +} + +func (n *PathSelectorNode) Index(idx int) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathSelectorNode) Field(fieldName string) (PathNode, bool, error) { + if n.selector == fieldName { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathSelectorNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Map: + iter := src.MapRange() + for iter.Next() { + key, ok := iter.Key().Interface().(string) + if !ok { + return fmt.Errorf("invalid map key type %T", src.Type().Key()) + } + child, found, err := n.Field(key) + if err != nil { + return err + } + if found { + if child != nil { + return child.Get(iter.Value(), dst) + } + return AssignValue(iter.Value(), dst) + } + } + case reflect.Struct: + typ := src.Type() + for i := 0; i < typ.Len(); i++ { + tag := runtime.StructTagFromField(typ.Field(i)) + child, found, err := n.Field(tag.Key) + if err != nil { + return err + } + if found { + if child != nil { + return child.Get(src.Field(i), dst) + } + return AssignValue(src.Field(i), dst) + } + } + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + case reflect.Float64, reflect.String, reflect.Bool: + return AssignValue(src, dst) + } + return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type()) +} + +func (n *PathSelectorNode) String() string { + s := fmt.Sprintf(".%s", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathIndexNode struct { + *BasePathNode + selector int +} + +func newPathIndexNode(selector int) *PathIndexNode { + return &PathIndexNode{ + BasePathNode: &BasePathNode{}, + selector: selector, + } +} + +func (n *PathIndexNode) Index(idx int) (PathNode, bool, error) { + if n.selector == idx { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathIndexNode) Field(fieldName string) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathIndexNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Array, reflect.Slice: + if src.Len() > n.selector { + if n.child != nil { + return n.child.Get(src.Index(n.selector), dst) + } + return AssignValue(src.Index(n.selector), dst) + } + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get [%d] value from %s", n.selector, src.Type()) +} + +func (n *PathIndexNode) String() string { + s := fmt.Sprintf("[%d]", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathIndexAllNode struct { + *BasePathNode +} + +func newPathIndexAllNode() *PathIndexAllNode { + return &PathIndexAllNode{ + BasePathNode: &BasePathNode{}, + } +} + +func (n *PathIndexAllNode) Index(idx int) (PathNode, bool, error) { + return n.child, true, nil +} + +func (n *PathIndexAllNode) Field(fieldName string) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathIndexAllNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Array, reflect.Slice: + var arr []interface{} + for i := 0; i < src.Len(); i++ { + var v interface{} + rv := reflect.ValueOf(&v) + if n.child != nil { + if err := n.child.Get(src.Index(i), rv); err != nil { + return err + } + } else { + if err := AssignValue(src.Index(i), rv); err != nil { + return err + } + } + arr = append(arr, v) + } + if err := AssignValue(reflect.ValueOf(arr), dst); err != nil { + return err + } + return nil + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get all value from %s", src.Type()) +} + +func (n *PathIndexAllNode) String() string { + s := "[*]" + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathRecursiveNode struct { + *BasePathNode + selector string +} + +func newPathRecursiveNode(selector string) *PathRecursiveNode { + node := newPathSelectorNode(selector) + return &PathRecursiveNode{ + BasePathNode: &BasePathNode{ + child: node, + }, + selector: selector, + } +} + +func (n *PathRecursiveNode) Field(fieldName string) (PathNode, bool, error) { + if n.selector == fieldName { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathRecursiveNode) Index(_ int) (PathNode, bool, error) { + return n, true, nil +} + +func valueToSliceValue(v interface{}) []interface{} { + rv := reflect.ValueOf(v) + ret := []interface{}{} + if rv.Type().Kind() == reflect.Slice || rv.Type().Kind() == reflect.Array { + for i := 0; i < rv.Len(); i++ { + ret = append(ret, rv.Index(i).Interface()) + } + return ret + } + return []interface{}{v} +} + +func (n *PathRecursiveNode) Get(src, dst reflect.Value) error { + if n.child == nil { + return fmt.Errorf("failed to get by recursive path ..%s", n.selector) + } + var arr []interface{} + switch src.Type().Kind() { + case reflect.Map: + iter := src.MapRange() + for iter.Next() { + key, ok := iter.Key().Interface().(string) + if !ok { + return fmt.Errorf("invalid map key type %T", src.Type().Key()) + } + child, found, err := n.Field(key) + if err != nil { + return err + } + if found { + var v interface{} + rv := reflect.ValueOf(&v) + _ = child.Get(iter.Value(), rv) + arr = append(arr, valueToSliceValue(v)...) + } else { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(iter.Value(), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Struct: + typ := src.Type() + for i := 0; i < typ.Len(); i++ { + tag := runtime.StructTagFromField(typ.Field(i)) + child, found, err := n.Field(tag.Key) + if err != nil { + return err + } + if found { + var v interface{} + rv := reflect.ValueOf(&v) + _ = child.Get(src.Field(i), rv) + arr = append(arr, valueToSliceValue(v)...) + } else { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(src.Field(i), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Array, reflect.Slice: + for i := 0; i < src.Len(); i++ { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(src.Index(i), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type()) +} + +func (n *PathRecursiveNode) String() string { + s := fmt.Sprintf("..%s", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/ptr.go b/vendor/github.com/goccy/go-json/internal/decoder/ptr.go index 2c83b9c..de12e10 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/ptr.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/ptr.go @@ -1,6 +1,7 @@ package decoder import ( + "fmt" "unsafe" "github.com/goccy/go-json/internal/runtime" @@ -34,6 +35,10 @@ func (d *ptrDecoder) contentDecoder() Decoder { //go:linkname unsafe_New reflect.unsafe_New func unsafe_New(*runtime.Type) unsafe.Pointer +func UnsafeNew(t *runtime.Type) unsafe.Pointer { + return unsafe_New(t) +} + func (d *ptrDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { if s.skipWhiteSpace() == nul { s.read() @@ -85,3 +90,7 @@ func (d *ptrDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P cursor = c return cursor, nil } + +func (d *ptrDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: ptr decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/slice.go b/vendor/github.com/goccy/go-json/internal/decoder/slice.go index 85b6e11..30a23e4 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/slice.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/slice.go @@ -299,3 +299,82 @@ func (d *sliceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe } } } + +func (d *sliceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + ret := [][]byte{} + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + case '[': + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == ']' { + cursor++ + return ret, cursor, nil + } + idx := 0 + for { + child, found, err := ctx.Option.Path.node.Index(idx) + if err != nil { + return nil, 0, err + } + if found { + if child != nil { + oldPath := ctx.Option.Path.node + ctx.Option.Path.node = child + paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) + if err != nil { + return nil, 0, err + } + ctx.Option.Path.node = oldPath + ret = append(ret, paths...) + cursor = c + } else { + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + ret = append(ret, buf[start:end]) + cursor = end + } + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + cursor = c + } + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case ']': + cursor++ + return ret, cursor, nil + case ',': + idx++ + default: + return nil, 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) + } + cursor++ + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return nil, 0, d.errNumber(cursor) + default: + return nil, 0, errors.ErrUnexpectedEndOfJSON("slice", cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/string.go b/vendor/github.com/goccy/go-json/internal/decoder/string.go index d07ad71..32602c9 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/string.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/string.go @@ -60,6 +60,17 @@ func (d *stringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsaf return cursor, nil } +func (d *stringDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, nil +} + var ( hexToInt = [256]int{ '0': 0, diff --git a/vendor/github.com/goccy/go-json/internal/decoder/struct.go b/vendor/github.com/goccy/go-json/internal/decoder/struct.go index 2c64680..313da15 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/struct.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/struct.go @@ -51,6 +51,14 @@ func init() { } } +func toASCIILower(s string) string { + b := []byte(s) + for i := range b { + b[i] = largeToSmallTable[b[i]] + } + return string(b) +} + func newStructDecoder(structName, fieldName string, fieldMap map[string]*structFieldSet) *structDecoder { return &structDecoder{ fieldMap: fieldMap, @@ -91,6 +99,10 @@ func (d *structDecoder) tryOptimize() { for k, v := range d.fieldMap { key := strings.ToLower(k) if key != k { + if key != toASCIILower(k) { + d.isTriedOptimize = true + return + } // already exists same key (e.g. Hello and HELLO has same lower case key if _, exists := conflicted[key]; exists { d.isTriedOptimize = true @@ -158,49 +170,53 @@ func (d *structDecoder) tryOptimize() { } // decode from '\uXXXX' -func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64) { +func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64, error) { const defaultOffset = 4 const surrogateOffset = 6 + if cursor+defaultOffset >= int64(len(buf)) { + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + r := unicodeToRune(buf[cursor : cursor+defaultOffset]) if utf16.IsSurrogate(r) { cursor += defaultOffset if cursor+surrogateOffset >= int64(len(buf)) || buf[cursor] != '\\' || buf[cursor+1] != 'u' { - return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1 + return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1, nil } cursor += 2 r2 := unicodeToRune(buf[cursor : cursor+defaultOffset]) if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { - return []byte(string(r)), cursor + defaultOffset - 1 + return []byte(string(r)), cursor + defaultOffset - 1, nil } } - return []byte(string(r)), cursor + defaultOffset - 1 + return []byte(string(r)), cursor + defaultOffset - 1, nil } -func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64) { +func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64, error) { c := buf[cursor] cursor++ switch c { case '"': - return []byte{'"'}, cursor + return []byte{'"'}, cursor, nil case '\\': - return []byte{'\\'}, cursor + return []byte{'\\'}, cursor, nil case '/': - return []byte{'/'}, cursor + return []byte{'/'}, cursor, nil case 'b': - return []byte{'\b'}, cursor + return []byte{'\b'}, cursor, nil case 'f': - return []byte{'\f'}, cursor + return []byte{'\f'}, cursor, nil case 'n': - return []byte{'\n'}, cursor + return []byte{'\n'}, cursor, nil case 'r': - return []byte{'\r'}, cursor + return []byte{'\r'}, cursor, nil case 't': - return []byte{'\t'}, cursor + return []byte{'\t'}, cursor, nil case 'u': return decodeKeyCharByUnicodeRune(buf, cursor) } - return nil, cursor + return nil, cursor, nil } func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) { @@ -242,7 +258,10 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) case '\\': cursor++ - chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor) + chars, nextCursor, err := decodeKeyCharByEscapedChar(buf, cursor) + if err != nil { + return 0, nil, err + } for _, c := range chars { curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -305,7 +324,10 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) case '\\': cursor++ - chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor) + chars, nextCursor, err := decodeKeyCharByEscapedChar(buf, cursor) + if err != nil { + return 0, nil, err + } for _, c := range chars { curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -817,3 +839,7 @@ func (d *structDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsaf cursor++ } } + +func (d *structDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: struct decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/type.go b/vendor/github.com/goccy/go-json/internal/decoder/type.go index 70e9907..beaf3ab 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/type.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/type.go @@ -10,6 +10,7 @@ import ( type Decoder interface { Decode(*RuntimeContext, int64, int64, unsafe.Pointer) (int64, error) + DecodePath(*RuntimeContext, int64, int64) ([][]byte, int64, error) DecodeStream(*Stream, int64, unsafe.Pointer) error } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/uint.go b/vendor/github.com/goccy/go-json/internal/decoder/uint.go index a62c514..4131731 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/uint.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/uint.go @@ -188,3 +188,7 @@ func (d *uintDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe. d.op(p, u64) return cursor, nil } + +func (d *uintDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: uint decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go index e9b25c6..4cd6dbd 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go @@ -3,6 +3,7 @@ package decoder import ( "context" "encoding/json" + "fmt" "unsafe" "github.com/goccy/go-json/internal/errors" @@ -97,3 +98,7 @@ func (d *unmarshalJSONDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, } return end, nil } + +func (d *unmarshalJSONDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: unmarshal json decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go index 1ef2877..6d37993 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go @@ -3,6 +3,7 @@ package decoder import ( "bytes" "encoding" + "fmt" "unicode" "unicode/utf16" "unicode/utf8" @@ -142,6 +143,10 @@ func (d *unmarshalTextDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, return end, nil } +func (d *unmarshalTextDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: unmarshal text decoder does not support decode path") +} + func unquoteBytes(s []byte) (t []byte, ok bool) { length := len(s) if length < 2 || s[0] != '"' || s[length-1] != '"' { diff --git a/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go b/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go index 66227ae..0c4e2e6 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go @@ -1,6 +1,7 @@ package decoder import ( + "fmt" "reflect" "unsafe" @@ -66,3 +67,7 @@ func (d *wrappedStringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, ctx.Buf = oldBuf return c, nil } + +func (d *wrappedStringDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: wrapped string decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/code.go b/vendor/github.com/goccy/go-json/internal/encoder/code.go index 8d62a9c..5b08fae 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/code.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/code.go @@ -397,7 +397,10 @@ func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) * func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode { // firstField is special StructHead operation for anonymous structure. // So, StructHead's next operation is truly struct head operation. - lastField := firstField.Next + for firstField.Op == OpStructHead || firstField.Op == OpStructField { + firstField = firstField.Next + } + lastField := firstField for lastField.NextField != nil { lastField = lastField.NextField } @@ -437,11 +440,6 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { } if isEndField { endField := fieldCodes.Last() - if isEmbeddedStruct(field) { - firstField.End = endField - lastField := c.lastAnonymousFieldCode(firstField) - lastField.NextField = endField - } if len(codes) > 0 { codes.First().End = endField } else { @@ -698,7 +696,15 @@ func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) O Indent: ctx.indent, } codes.Last().Next = end - codes.First().NextField = end + code := codes.First() + for code.Op == OpStructField || code.Op == OpStructHead { + code = code.Next + } + for code.NextField != nil { + code = code.NextField + } + code.NextField = end + codes = codes.Add(end) ctx.incOpcodeIndex() return codes diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compiler.go b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go index bf5e0f9..3ae39ba 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/compiler.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go @@ -506,8 +506,6 @@ func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) { func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) { switch { - case c.implementsMarshalJSON(typ): - return c.marshalJSONCode(typ) case c.implementsMarshalText(typ): return c.marshalTextCode(typ) } @@ -619,6 +617,13 @@ func (c *Compiler) structCode(typ *runtime.Type, isPtr bool) (*StructCode, error return code, nil } +func toElemType(t *runtime.Type) *runtime.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTag, isPtr, isOnlyOneFirstField bool) (*StructFieldCode, error) { field := tag.Field fieldType := runtime.Type2RType(field.Type) @@ -628,7 +633,7 @@ func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTa key: tag.Key, tag: tag, offset: field.Offset, - isAnonymous: field.Anonymous && !tag.IsTaggedKey, + isAnonymous: field.Anonymous && !tag.IsTaggedKey && toElemType(fieldType).Kind() == reflect.Struct, isTaggedKey: tag.IsTaggedKey, isNilableType: c.isNilableType(fieldType), isNilCheck: true, diff --git a/vendor/github.com/goccy/go-json/internal/encoder/opcode.go b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go index 05fc3ce..df22f55 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/opcode.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go @@ -1,7 +1,9 @@ package encoder import ( + "bytes" "fmt" + "sort" "strings" "unsafe" @@ -555,6 +557,87 @@ func (c *Opcode) Dump() string { return strings.Join(codes, "\n") } +func (c *Opcode) DumpDOT() string { + type edge struct { + from, to *Opcode + label string + weight int + } + var edges []edge + + b := &bytes.Buffer{} + fmt.Fprintf(b, "digraph \"%p\" {\n", c.Type) + fmt.Fprintln(b, "mclimit=1.5;\nrankdir=TD;\nordering=out;\nnode[shape=box];") + for code := c; !code.IsEnd(); { + label := code.Op.String() + fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, label) + if p := code.Next; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "Next", + weight: 10, + }) + } + if p := code.NextField; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "NextField", + weight: 2, + }) + } + if p := code.End; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "End", + weight: 1, + }) + } + if p := code.Jmp; p != nil { + edges = append(edges, edge{ + from: code, + to: p.Code, + label: "Jmp", + weight: 1, + }) + } + + switch code.Op.CodeType() { + case CodeSliceHead: + code = code.Next + case CodeMapHead: + code = code.Next + case CodeArrayElem, CodeSliceElem: + code = code.End + case CodeMapKey: + code = code.End + case CodeMapValue: + code = code.Next + case CodeMapEnd: + code = code.Next + case CodeStructField: + code = code.Next + case CodeStructEnd: + code = code.Next + default: + code = code.Next + } + if code.IsEnd() { + fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, code.Op.String()) + } + } + sort.Slice(edges, func(i, j int) bool { + return edges[i].to.DisplayIdx < edges[j].to.DisplayIdx + }) + for _, e := range edges { + fmt.Fprintf(b, "\"%p\" -> \"%p\" [label=%q][weight=%d];\n", e.from, e.to, e.label, e.weight) + } + fmt.Fprint(b, "}") + return b.String() +} + func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode { idx := opcodeOffset(ctx.ptrIndex) ctx.incPtrIndex() diff --git a/vendor/github.com/goccy/go-json/internal/encoder/option.go b/vendor/github.com/goccy/go-json/internal/encoder/option.go index 82d5ce3..12c58e4 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/option.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/option.go @@ -23,6 +23,7 @@ type Option struct { ColorScheme *ColorScheme Context context.Context DebugOut io.Writer + DebugDOTOut io.WriteCloser } type EncodeFormat struct { diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go index fbbc0de..82b6dd4 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "io" "github.com/goccy/go-json/internal/encoder" ) @@ -14,6 +15,11 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) } else { code = codeSet.NoescapeKeyCode } + if wc := ctx.Option.DebugDOTOut; wc != nil { + _, _ = io.WriteString(wc, code.DumpDOT()) + wc.Close() + ctx.Option.DebugDOTOut = nil + } if err := recover(); err != nil { w := ctx.Option.DebugOut diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go index 60e4a8e..2395abe 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go @@ -189,7 +189,7 @@ func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte { } func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { - return append(b, ':', ' ') + return append(b[:len(b)-2], ':', ' ') } func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte { @@ -229,8 +229,9 @@ func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 - b[last] = '\n' - b = appendIndent(ctx, b, code.Indent-1) + // replace comma to newline + b[last-1] = '\n' + b = appendIndent(ctx, b[:last], code.Indent) return append(b, '}', ',', '\n') } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go index fca8f18..6cb745e 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go @@ -133,7 +133,7 @@ func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte { } func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { - return append(b, ':', ' ') + return append(b[:len(b)-2], ':', ' ') } func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte { @@ -173,8 +173,9 @@ func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 - b[last] = '\n' - b = appendIndent(ctx, b, code.Indent-1) + // replace comma to newline + b[last-1] = '\n' + b = appendIndent(ctx, b[:last], code.Indent) return append(b, '}', ',', '\n') } diff --git a/vendor/github.com/goccy/go-json/internal/errors/error.go b/vendor/github.com/goccy/go-json/internal/errors/error.go index d58e39f..9207d0f 100644 --- a/vendor/github.com/goccy/go-json/internal/errors/error.go +++ b/vendor/github.com/goccy/go-json/internal/errors/error.go @@ -162,3 +162,22 @@ func ErrInvalidBeginningOfValue(c byte, cursor int64) *SyntaxError { Offset: cursor, } } + +type PathError struct { + msg string +} + +func (e *PathError) Error() string { + return fmt.Sprintf("json: invalid path format: %s", e.msg) +} + +func ErrInvalidPath(msg string, args ...interface{}) *PathError { + if len(args) != 0 { + return &PathError{msg: fmt.Sprintf(msg, args...)} + } + return &PathError{msg: msg} +} + +func ErrEmptyPath() *PathError { + return &PathError{msg: "path is empty"} +} diff --git a/vendor/github.com/goccy/go-json/option.go b/vendor/github.com/goccy/go-json/option.go index af400a4..378031a 100644 --- a/vendor/github.com/goccy/go-json/option.go +++ b/vendor/github.com/goccy/go-json/option.go @@ -48,6 +48,13 @@ func DebugWith(w io.Writer) EncodeOptionFunc { } } +// DebugDOT sets the destination to write opcodes graph. +func DebugDOT(w io.WriteCloser) EncodeOptionFunc { + return func(opt *EncodeOption) { + opt.DebugDOTOut = w + } +} + // Colorize add an identifier for coloring to the string of the encoded result. func Colorize(scheme *ColorScheme) EncodeOptionFunc { return func(opt *EncodeOption) { diff --git a/vendor/github.com/goccy/go-json/path.go b/vendor/github.com/goccy/go-json/path.go new file mode 100644 index 0000000..38abce7 --- /dev/null +++ b/vendor/github.com/goccy/go-json/path.go @@ -0,0 +1,84 @@ +package json + +import ( + "reflect" + + "github.com/goccy/go-json/internal/decoder" +) + +// CreatePath creates JSON Path. +// +// JSON Path rule +// $ : root object or element. The JSON Path format must start with this operator, which refers to the outermost level of the JSON-formatted string. +// . : child operator. You can identify child values using dot-notation. +// .. : recursive descent. +// [] : subscript operator. If the JSON object is an array, you can use brackets to specify the array index. +// [*] : all objects/elements for array. +// +// Reserved words must be properly escaped when included in Path. +// +// Escape Rule +// single quote style escape: e.g.) `$['a.b'].c` +// double quote style escape: e.g.) `$."a.b".c` +func CreatePath(p string) (*Path, error) { + path, err := decoder.PathString(p).Build() + if err != nil { + return nil, err + } + return &Path{path: path}, nil +} + +// Path represents JSON Path. +type Path struct { + path *decoder.Path +} + +// RootSelectorOnly whether only the root selector ($) is used. +func (p *Path) RootSelectorOnly() bool { + return p.path.RootSelectorOnly +} + +// UsedSingleQuotePathSelector whether single quote-based escaping was done when building the JSON Path. +func (p *Path) UsedSingleQuotePathSelector() bool { + return p.path.SingleQuotePathSelector +} + +// UsedSingleQuotePathSelector whether double quote-based escaping was done when building the JSON Path. +func (p *Path) UsedDoubleQuotePathSelector() bool { + return p.path.DoubleQuotePathSelector +} + +// Extract extracts a specific JSON string. +func (p *Path) Extract(data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) { + return extractFromPath(p, data, optFuncs...) +} + +// PathString returns original JSON Path string. +func (p *Path) PathString() string { + return p.path.String() +} + +// Unmarshal extract and decode the value of the part corresponding to JSON Path from the input data. +func (p *Path) Unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + contents, err := extractFromPath(p, data, optFuncs...) + if err != nil { + return err + } + results := make([]interface{}, 0, len(contents)) + for _, content := range contents { + var result interface{} + if err := Unmarshal(content, &result); err != nil { + return err + } + results = append(results, result) + } + if err := decoder.AssignValue(reflect.ValueOf(results), reflect.ValueOf(v)); err != nil { + return err + } + return nil +} + +// Get extract and substitute the value of the part corresponding to JSON Path from the input value. +func (p *Path) Get(src, dst interface{}) error { + return p.path.Get(reflect.ValueOf(src), reflect.ValueOf(dst)) +} diff --git a/vendor/github.com/klauspost/cpuid/v2/.gitignore b/vendor/github.com/klauspost/cpuid/v2/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/klauspost/cpuid/v2/.goreleaser.yml b/vendor/github.com/klauspost/cpuid/v2/.goreleaser.yml new file mode 100644 index 0000000..944cc00 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/.goreleaser.yml @@ -0,0 +1,74 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com + +builds: + - + id: "cpuid" + binary: cpuid + main: ./cmd/cpuid/main.go + env: + - CGO_ENABLED=0 + flags: + - -ldflags=-s -w + goos: + - aix + - linux + - freebsd + - netbsd + - windows + - darwin + goarch: + - 386 + - amd64 + - arm64 + goarm: + - 7 + +archives: + - + id: cpuid + name_template: "cpuid-{{ .Os }}_{{ .Arch }}_{{ .Version }}" + replacements: + aix: AIX + darwin: OSX + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + freebsd: FreeBSD + netbsd: NetBSD + format_overrides: + - goos: windows + format: zip + files: + - LICENSE +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^doc:' + - '^docs:' + - '^test:' + - '^tests:' + - '^Update\sREADME.md' + +nfpms: + - + file_name_template: "cpuid_package_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + vendor: Klaus Post + homepage: https://github.com/klauspost/cpuid + maintainer: Klaus Post + description: CPUID Tool + license: BSD 3-Clause + formats: + - deb + - rpm + replacements: + darwin: Darwin + linux: Linux + freebsd: FreeBSD + amd64: x86_64 diff --git a/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt b/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt new file mode 100644 index 0000000..2ef4714 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/CONTRIBUTING.txt @@ -0,0 +1,35 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2015- Klaus Post & Contributors. +Email: klauspost@gmail.com + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/github.com/klauspost/cpuid/v2/LICENSE b/vendor/github.com/klauspost/cpuid/v2/LICENSE new file mode 100644 index 0000000..5cec7ee --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Klaus Post + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/klauspost/cpuid/v2/README.md b/vendor/github.com/klauspost/cpuid/v2/README.md new file mode 100644 index 0000000..37b5167 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/README.md @@ -0,0 +1,492 @@ +# cpuid +Package cpuid provides information about the CPU running the current program. + +CPU features are detected on startup, and kept for fast access through the life of the application. +Currently x86 / x64 (AMD64/i386) and ARM (ARM64) is supported, and no external C (cgo) code is used, which should make the library very easy to use. + +You can access the CPU information by accessing the shared CPU variable of the cpuid library. + +Package home: https://github.com/klauspost/cpuid + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/klauspost/cpuid)](https://pkg.go.dev/github.com/klauspost/cpuid/v2) +[![Build Status][3]][4] + +[3]: https://travis-ci.org/klauspost/cpuid.svg?branch=master +[4]: https://travis-ci.org/klauspost/cpuid + +## installing + +`go get -u github.com/klauspost/cpuid/v2` using modules. +Drop `v2` for others. + +Installing binary: + +`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest` + +Or download binaries from release page: https://github.com/klauspost/cpuid/releases + +### Homebrew + +For macOS/Linux users, you can install via [brew](https://brew.sh/) + +```sh +$ brew install cpuid +``` + +## example + +```Go +package main + +import ( + "fmt" + "strings" + + . "github.com/klauspost/cpuid/v2" +) + +func main() { + // Print basic CPU information: + fmt.Println("Name:", CPU.BrandName) + fmt.Println("PhysicalCores:", CPU.PhysicalCores) + fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore) + fmt.Println("LogicalCores:", CPU.LogicalCores) + fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID) + fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ",")) + fmt.Println("Cacheline bytes:", CPU.CacheLine) + fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes") + fmt.Println("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") + fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes") + fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes") + fmt.Println("Frequency", CPU.Hz, "hz") + + // Test if we have these specific features: + if CPU.Supports(SSE, SSE2) { + fmt.Println("We have Streaming SIMD 2 Extensions") + } +} +``` + +Sample output: +``` +>go run main.go +Name: AMD Ryzen 9 3950X 16-Core Processor +PhysicalCores: 16 +ThreadsPerCore: 2 +LogicalCores: 32 +Family 23 Model: 113 Vendor ID: AMD +Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CMOV,CX16,F16C,FMA3,HTT,HYPERVISOR,LZCNT,MMX,MMXEXT,NX,POPCNT,RDRAND,RDSEED,RDTSCP,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3 +Cacheline bytes: 64 +L1 Data Cache: 32768 bytes +L1 Instruction Cache: 32768 bytes +L2 Cache: 524288 bytes +L3 Cache: 16777216 bytes +Frequency 0 hz +We have Streaming SIMD 2 Extensions +``` + +# usage + +The `cpuid.CPU` provides access to CPU features. Use `cpuid.CPU.Supports()` to check for CPU features. +A faster `cpuid.CPU.Has()` is provided which will usually be inlined by the gc compiler. + +To test a larger number of features, they can be combined using `f := CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2)`, etc. +This can be using with `cpuid.CPU.HasAll(f)` to quickly test if all features are supported. + +Note that for some cpu/os combinations some features will not be detected. +`amd64` has rather good support and should work reliably on all platforms. + +Note that hypervisors may not pass through all CPU features through to the guest OS, +so even if your host supports a feature it may not be visible on guests. + +## arm64 feature detection + +Not all operating systems provide ARM features directly +and there is no safe way to do so for the rest. + +Currently `arm64/linux` and `arm64/freebsd` should be quite reliable. +`arm64/darwin` adds features expected from the M1 processor, but a lot remains undetected. + +A `DetectARM()` can be used if you are able to control your deployment, +it will detect CPU features, but may crash if the OS doesn't intercept the calls. +A `-cpu.arm` flag for detecting unsafe ARM features can be added. See below. + +Note that currently only features are detected on ARM, +no additional information is currently available. + +## flags + +It is possible to add flags that affects cpu detection. + +For this the `Flags()` command is provided. + +This must be called *before* `flag.Parse()` AND after the flags have been parsed `Detect()` must be called. + +This means that any detection used in `init()` functions will not contain these flags. + +Example: + +```Go +package main + +import ( + "flag" + "fmt" + "strings" + + "github.com/klauspost/cpuid/v2" +) + +func main() { + cpuid.Flags() + flag.Parse() + cpuid.Detect() + + // Test if we have these specific features: + if cpuid.CPU.Supports(cpuid.SSE, cpuid.SSE2) { + fmt.Println("We have Streaming SIMD 2 Extensions") + } +} +``` + +## commandline + +Download as binary from: https://github.com/klauspost/cpuid/releases + +Install from source: + +`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest` + +### Example + +``` +λ cpuid +Name: AMD Ryzen 9 3950X 16-Core Processor +Vendor String: AuthenticAMD +Vendor ID: AMD +PhysicalCores: 16 +Threads Per Core: 2 +Logical Cores: 32 +CPU Family 23 Model: 113 +Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CLZERO,CMOV,CMPXCHG8,CPBOOST,CX16,F16C,FMA3,FXSR,FXSROPT,HTT,HYPERVISOR,LAHF,LZCNT,MCAOVERFLOW,MMX,MMXEXT,MOVBE,NX,OSXSAVE,POPCNT,RDRAND,RDSEED,RDTSCP,SCE,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3,SUCCOR,X87,XSAVE +Microarchitecture level: 3 +Cacheline bytes: 64 +L1 Instruction Cache: 32768 bytes +L1 Data Cache: 32768 bytes +L2 Cache: 524288 bytes +L3 Cache: 16777216 bytes + +``` +### JSON Output: + +``` +λ cpuid --json +{ + "BrandName": "AMD Ryzen 9 3950X 16-Core Processor", + "VendorID": 2, + "VendorString": "AuthenticAMD", + "PhysicalCores": 16, + "ThreadsPerCore": 2, + "LogicalCores": 32, + "Family": 23, + "Model": 113, + "CacheLine": 64, + "Hz": 0, + "BoostFreq": 0, + "Cache": { + "L1I": 32768, + "L1D": 32768, + "L2": 524288, + "L3": 16777216 + }, + "SGX": { + "Available": false, + "LaunchControl": false, + "SGX1Supported": false, + "SGX2Supported": false, + "MaxEnclaveSizeNot64": 0, + "MaxEnclaveSize64": 0, + "EPCSections": null + }, + "Features": [ + "ADX", + "AESNI", + "AVX", + "AVX2", + "BMI1", + "BMI2", + "CLMUL", + "CLZERO", + "CMOV", + "CMPXCHG8", + "CPBOOST", + "CX16", + "F16C", + "FMA3", + "FXSR", + "FXSROPT", + "HTT", + "HYPERVISOR", + "LAHF", + "LZCNT", + "MCAOVERFLOW", + "MMX", + "MMXEXT", + "MOVBE", + "NX", + "OSXSAVE", + "POPCNT", + "RDRAND", + "RDSEED", + "RDTSCP", + "SCE", + "SHA", + "SSE", + "SSE2", + "SSE3", + "SSE4", + "SSE42", + "SSE4A", + "SSSE3", + "SUCCOR", + "X87", + "XSAVE" + ], + "X64Level": 3 +} +``` + +### Check CPU microarch level + +``` +λ cpuid --check-level=3 +2022/03/18 17:04:40 AMD Ryzen 9 3950X 16-Core Processor +2022/03/18 17:04:40 Microarchitecture level 3 is supported. Max level is 3. +Exit Code 0 + +λ cpuid --check-level=4 +2022/03/18 17:06:18 AMD Ryzen 9 3950X 16-Core Processor +2022/03/18 17:06:18 Microarchitecture level 4 not supported. Max level is 3. +Exit Code 1 +``` + + +## Available flags + +### x86 & amd64 + +| Feature Flag | Description | +|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ADX | Intel ADX (Multi-Precision Add-Carry Instruction Extensions) | +| AESNI | Advanced Encryption Standard New Instructions | +| AMD3DNOW | AMD 3DNOW | +| AMD3DNOWEXT | AMD 3DNowExt | +| AMXBF16 | Tile computational operations on BFLOAT16 numbers | +| AMXINT8 | Tile computational operations on 8-bit integers | +| AMXFP16 | Tile computational operations on FP16 numbers | +| AMXTILE | Tile architecture | +| AVX | AVX functions | +| AVX2 | AVX2 functions | +| AVX512BF16 | AVX-512 BFLOAT16 Instructions | +| AVX512BITALG | AVX-512 Bit Algorithms | +| AVX512BW | AVX-512 Byte and Word Instructions | +| AVX512CD | AVX-512 Conflict Detection Instructions | +| AVX512DQ | AVX-512 Doubleword and Quadword Instructions | +| AVX512ER | AVX-512 Exponential and Reciprocal Instructions | +| AVX512F | AVX-512 Foundation | +| AVX512FP16 | AVX-512 FP16 Instructions | +| AVX512IFMA | AVX-512 Integer Fused Multiply-Add Instructions | +| AVX512PF | AVX-512 Prefetch Instructions | +| AVX512VBMI | AVX-512 Vector Bit Manipulation Instructions | +| AVX512VBMI2 | AVX-512 Vector Bit Manipulation Instructions, Version 2 | +| AVX512VL | AVX-512 Vector Length Extensions | +| AVX512VNNI | AVX-512 Vector Neural Network Instructions | +| AVX512VP2INTERSECT | AVX-512 Intersect for D/Q | +| AVX512VPOPCNTDQ | AVX-512 Vector Population Count Doubleword and Quadword | +| AVXIFMA | AVX-IFMA instructions | +| AVXNECONVERT | AVX-NE-CONVERT instructions | +| AVXSLOW | Indicates the CPU performs 2 128 bit operations instead of one | +| AVXVNNI | AVX (VEX encoded) VNNI neural network instructions | +| AVXVNNIINT8 | AVX-VNNI-INT8 instructions | +| BHI_CTRL | Branch History Injection and Intra-mode Branch Target Injection / CVE-2022-0001, CVE-2022-0002 / INTEL-SA-00598 | +| BMI1 | Bit Manipulation Instruction Set 1 | +| BMI2 | Bit Manipulation Instruction Set 2 | +| CETIBT | Intel CET Indirect Branch Tracking | +| CETSS | Intel CET Shadow Stack | +| CLDEMOTE | Cache Line Demote | +| CLMUL | Carry-less Multiplication | +| CLZERO | CLZERO instruction supported | +| CMOV | i686 CMOV | +| CMPCCXADD | CMPCCXADD instructions | +| CMPSB_SCADBS_SHORT | Fast short CMPSB and SCASB | +| CMPXCHG8 | CMPXCHG8 instruction | +| CPBOOST | Core Performance Boost | +| CPPC | AMD: Collaborative Processor Performance Control | +| CX16 | CMPXCHG16B Instruction | +| EFER_LMSLE_UNS | AMD: =Core::X86::Msr::EFER[LMSLE] is not supported, and MBZ | +| ENQCMD | Enqueue Command | +| ERMS | Enhanced REP MOVSB/STOSB | +| F16C | Half-precision floating-point conversion | +| FLUSH_L1D | Flush L1D cache | +| FMA3 | Intel FMA 3. Does not imply AVX. | +| FMA4 | Bulldozer FMA4 functions | +| FP128 | AMD: When set, the internal FP/SIMD execution datapath is 128-bits wide | +| FP256 | AMD: When set, the internal FP/SIMD execution datapath is 256-bits wide | +| FSRM | Fast Short Rep Mov | +| FXSR | FXSAVE, FXRESTOR instructions, CR4 bit 9 | +| FXSROPT | FXSAVE/FXRSTOR optimizations | +| GFNI | Galois Field New Instructions. May require other features (AVX, AVX512VL,AVX512F) based on usage. | +| HLE | Hardware Lock Elision | +| HRESET | If set CPU supports history reset and the IA32_HRESET_ENABLE MSR | +| HTT | Hyperthreading (enabled) | +| HWA | Hardware assert supported. Indicates support for MSRC001_10 | +| HYBRID_CPU | This part has CPUs of more than one type. | +| HYPERVISOR | This bit has been reserved by Intel & AMD for use by hypervisors | +| IA32_ARCH_CAP | IA32_ARCH_CAPABILITIES MSR (Intel) | +| IA32_CORE_CAP | IA32_CORE_CAPABILITIES MSR | +| IBPB | Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Predictor Barrier (IBPB) | +| IBRS | AMD: Indirect Branch Restricted Speculation | +| IBRS_PREFERRED | AMD: IBRS is preferred over software solution | +| IBRS_PROVIDES_SMP | AMD: IBRS provides Same Mode Protection | +| IBS | Instruction Based Sampling (AMD) | +| IBSBRNTRGT | Instruction Based Sampling Feature (AMD) | +| IBSFETCHSAM | Instruction Based Sampling Feature (AMD) | +| IBSFFV | Instruction Based Sampling Feature (AMD) | +| IBSOPCNT | Instruction Based Sampling Feature (AMD) | +| IBSOPCNTEXT | Instruction Based Sampling Feature (AMD) | +| IBSOPSAM | Instruction Based Sampling Feature (AMD) | +| IBSRDWROPCNT | Instruction Based Sampling Feature (AMD) | +| IBSRIPINVALIDCHK | Instruction Based Sampling Feature (AMD) | +| IBS_FETCH_CTLX | AMD: IBS fetch control extended MSR supported | +| IBS_OPDATA4 | AMD: IBS op data 4 MSR supported | +| IBS_OPFUSE | AMD: Indicates support for IbsOpFuse | +| IBS_PREVENTHOST | Disallowing IBS use by the host supported | +| IBS_ZEN4 | Fetch and Op IBS support IBS extensions added with Zen4 | +| IDPRED_CTRL | IPRED_DIS | +| INT_WBINVD | WBINVD/WBNOINVD are interruptible. | +| INVLPGB | NVLPGB and TLBSYNC instruction supported | +| LAHF | LAHF/SAHF in long mode | +| LAM | If set, CPU supports Linear Address Masking | +| LBRVIRT | LBR virtualization | +| LZCNT | LZCNT instruction | +| MCAOVERFLOW | MCA overflow recovery support. | +| MCDT_NO | Processor do not exhibit MXCSR Configuration Dependent Timing behavior and do not need to mitigate it. | +| MCOMMIT | MCOMMIT instruction supported | +| MD_CLEAR | VERW clears CPU buffers | +| MMX | standard MMX | +| MMXEXT | SSE integer functions or AMD MMX ext | +| MOVBE | MOVBE instruction (big-endian) | +| MOVDIR64B | Move 64 Bytes as Direct Store | +| MOVDIRI | Move Doubleword as Direct Store | +| MOVSB_ZL | Fast Zero-Length MOVSB | +| MPX | Intel MPX (Memory Protection Extensions) | +| MOVU | MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD | +| MSRIRC | Instruction Retired Counter MSR available | +| MSRLIST | Read/Write List of Model Specific Registers | +| MSR_PAGEFLUSH | Page Flush MSR available | +| NRIPS | Indicates support for NRIP save on VMEXIT | +| NX | NX (No-Execute) bit | +| OSXSAVE | XSAVE enabled by OS | +| PCONFIG | PCONFIG for Intel Multi-Key Total Memory Encryption | +| POPCNT | POPCNT instruction | +| PPIN | AMD: Protected Processor Inventory Number support. Indicates that Protected Processor Inventory Number (PPIN) capability can be enabled | +| PREFETCHI | PREFETCHIT0/1 instructions | +| PSFD | Predictive Store Forward Disable | +| RDPRU | RDPRU instruction supported | +| RDRAND | RDRAND instruction is available | +| RDSEED | RDSEED instruction is available | +| RDTSCP | RDTSCP Instruction | +| RRSBA_CTRL | Restricted RSB Alternate | +| RTM | Restricted Transactional Memory | +| RTM_ALWAYS_ABORT | Indicates that the loaded microcode is forcing RTM abort. | +| SERIALIZE | Serialize Instruction Execution | +| SEV | AMD Secure Encrypted Virtualization supported | +| SEV_64BIT | AMD SEV guest execution only allowed from a 64-bit host | +| SEV_ALTERNATIVE | AMD SEV Alternate Injection supported | +| SEV_DEBUGSWAP | Full debug state swap supported for SEV-ES guests | +| SEV_ES | AMD SEV Encrypted State supported | +| SEV_RESTRICTED | AMD SEV Restricted Injection supported | +| SEV_SNP | AMD SEV Secure Nested Paging supported | +| SGX | Software Guard Extensions | +| SGXLC | Software Guard Extensions Launch Control | +| SHA | Intel SHA Extensions | +| SME | AMD Secure Memory Encryption supported | +| SME_COHERENT | AMD Hardware cache coherency across encryption domains enforced | +| SPEC_CTRL_SSBD | Speculative Store Bypass Disable | +| SRBDS_CTRL | SRBDS mitigation MSR available | +| SSE | SSE functions | +| SSE2 | P4 SSE functions | +| SSE3 | Prescott SSE3 functions | +| SSE4 | Penryn SSE4.1 functions | +| SSE42 | Nehalem SSE4.2 functions | +| SSE4A | AMD Barcelona microarchitecture SSE4a instructions | +| SSSE3 | Conroe SSSE3 functions | +| STIBP | Single Thread Indirect Branch Predictors | +| STIBP_ALWAYSON | AMD: Single Thread Indirect Branch Prediction Mode has Enhanced Performance and may be left Always On | +| STOSB_SHORT | Fast short STOSB | +| SUCCOR | Software uncorrectable error containment and recovery capability. | +| SVM | AMD Secure Virtual Machine | +| SVMDA | Indicates support for the SVM decode assists. | +| SVMFBASID | SVM, Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush only the current ASID's TLB entries. Also indicates support for the extended VMCBTLB_Control | +| SVML | AMD SVM lock. Indicates support for SVM-Lock. | +| SVMNP | AMD SVM nested paging | +| SVMPF | SVM pause intercept filter. Indicates support for the pause intercept filter | +| SVMPFT | SVM PAUSE filter threshold. Indicates support for the PAUSE filter cycle count threshold | +| SYSCALL | System-Call Extension (SCE): SYSCALL and SYSRET instructions. | +| SYSEE | SYSENTER and SYSEXIT instructions | +| TBM | AMD Trailing Bit Manipulation | +| TLB_FLUSH_NESTED | AMD: Flushing includes all the nested translations for guest translations | +| TME | Intel Total Memory Encryption. The following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. | +| TOPEXT | TopologyExtensions: topology extensions support. Indicates support for CPUID Fn8000_001D_EAX_x[N:0]-CPUID Fn8000_001E_EDX. | +| TSCRATEMSR | MSR based TSC rate control. Indicates support for MSR TSC ratio MSRC000_0104 | +| TSXLDTRK | Intel TSX Suspend Load Address Tracking | +| VAES | Vector AES. AVX(512) versions requires additional checks. | +| VMCBCLEAN | VMCB clean bits. Indicates support for VMCB clean bits. | +| VMPL | AMD VM Permission Levels supported | +| VMSA_REGPROT | AMD VMSA Register Protection supported | +| VMX | Virtual Machine Extensions | +| VPCLMULQDQ | Carry-Less Multiplication Quadword. Requires AVX for 3 register versions. | +| VTE | AMD Virtual Transparent Encryption supported | +| WAITPKG | TPAUSE, UMONITOR, UMWAIT | +| WBNOINVD | Write Back and Do Not Invalidate Cache | +| WRMSRNS | Non-Serializing Write to Model Specific Register | +| X87 | FPU | +| XGETBV1 | Supports XGETBV with ECX = 1 | +| XOP | Bulldozer XOP functions | +| XSAVE | XSAVE, XRESTOR, XSETBV, XGETBV | +| XSAVEC | Supports XSAVEC and the compacted form of XRSTOR. | +| XSAVEOPT | XSAVEOPT available | +| XSAVES | Supports XSAVES/XRSTORS and IA32_XSS | + +# ARM features: + +| Feature Flag | Description | +|--------------|------------------------------------------------------------------| +| AESARM | AES instructions | +| ARMCPUID | Some CPU ID registers readable at user-level | +| ASIMD | Advanced SIMD | +| ASIMDDP | SIMD Dot Product | +| ASIMDHP | Advanced SIMD half-precision floating point | +| ASIMDRDM | Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH) | +| ATOMICS | Large System Extensions (LSE) | +| CRC32 | CRC32/CRC32C instructions | +| DCPOP | Data cache clean to Point of Persistence (DC CVAP) | +| EVTSTRM | Generic timer | +| FCMA | Floatin point complex number addition and multiplication | +| FP | Single-precision and double-precision floating point | +| FPHP | Half-precision floating point | +| GPA | Generic Pointer Authentication | +| JSCVT | Javascript-style double->int convert (FJCVTZS) | +| LRCPC | Weaker release consistency (LDAPR, etc) | +| PMULL | Polynomial Multiply instructions (PMULL/PMULL2) | +| SHA1 | SHA-1 instructions (SHA1C, etc) | +| SHA2 | SHA-2 instructions (SHA256H, etc) | +| SHA3 | SHA-3 instructions (EOR3, RAXI, XAR, BCAX) | +| SHA512 | SHA512 instructions | +| SM3 | SM3 instructions | +| SM4 | SM4 instructions | +| SVE | Scalable Vector Extension | + +# license + +This code is published under an MIT license. See LICENSE file for more information. diff --git a/vendor/github.com/klauspost/cpuid/v2/cpuid.go b/vendor/github.com/klauspost/cpuid/v2/cpuid.go new file mode 100644 index 0000000..89a861d --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/cpuid.go @@ -0,0 +1,1419 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// Package cpuid provides information about the CPU running the current program. +// +// CPU features are detected on startup, and kept for fast access through the life of the application. +// Currently x86 / x64 (AMD64) as well as arm64 is supported. +// +// You can access the CPU information by accessing the shared CPU variable of the cpuid library. +// +// Package home: https://github.com/klauspost/cpuid +package cpuid + +import ( + "flag" + "fmt" + "math" + "math/bits" + "os" + "runtime" + "strings" +) + +// AMD refererence: https://www.amd.com/system/files/TechDocs/25481.pdf +// and Processor Programming Reference (PPR) + +// Vendor is a representation of a CPU vendor. +type Vendor int + +const ( + VendorUnknown Vendor = iota + Intel + AMD + VIA + Transmeta + NSC + KVM // Kernel-based Virtual Machine + MSVM // Microsoft Hyper-V or Windows Virtual PC + VMware + XenHVM + Bhyve + Hygon + SiS + RDC + + Ampere + ARM + Broadcom + Cavium + DEC + Fujitsu + Infineon + Motorola + NVIDIA + AMCC + Qualcomm + Marvell + + lastVendor +) + +//go:generate stringer -type=FeatureID,Vendor + +// FeatureID is the ID of a specific cpu feature. +type FeatureID int + +const ( + // Keep index -1 as unknown + UNKNOWN = -1 + + // Add features + ADX FeatureID = iota // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + AESNI // Advanced Encryption Standard New Instructions + AMD3DNOW // AMD 3DNOW + AMD3DNOWEXT // AMD 3DNowExt + AMXBF16 // Tile computational operations on BFLOAT16 numbers + AMXFP16 // Tile computational operations on FP16 numbers + AMXINT8 // Tile computational operations on 8-bit integers + AMXTILE // Tile architecture + AVX // AVX functions + AVX2 // AVX2 functions + AVX512BF16 // AVX-512 BFLOAT16 Instructions + AVX512BITALG // AVX-512 Bit Algorithms + AVX512BW // AVX-512 Byte and Word Instructions + AVX512CD // AVX-512 Conflict Detection Instructions + AVX512DQ // AVX-512 Doubleword and Quadword Instructions + AVX512ER // AVX-512 Exponential and Reciprocal Instructions + AVX512F // AVX-512 Foundation + AVX512FP16 // AVX-512 FP16 Instructions + AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions + AVX512PF // AVX-512 Prefetch Instructions + AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions + AVX512VBMI2 // AVX-512 Vector Bit Manipulation Instructions, Version 2 + AVX512VL // AVX-512 Vector Length Extensions + AVX512VNNI // AVX-512 Vector Neural Network Instructions + AVX512VP2INTERSECT // AVX-512 Intersect for D/Q + AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword + AVXIFMA // AVX-IFMA instructions + AVXNECONVERT // AVX-NE-CONVERT instructions + AVXSLOW // Indicates the CPU performs 2 128 bit operations instead of one + AVXVNNI // AVX (VEX encoded) VNNI neural network instructions + AVXVNNIINT8 // AVX-VNNI-INT8 instructions + BHI_CTRL // Branch History Injection and Intra-mode Branch Target Injection / CVE-2022-0001, CVE-2022-0002 / INTEL-SA-00598 + BMI1 // Bit Manipulation Instruction Set 1 + BMI2 // Bit Manipulation Instruction Set 2 + CETIBT // Intel CET Indirect Branch Tracking + CETSS // Intel CET Shadow Stack + CLDEMOTE // Cache Line Demote + CLMUL // Carry-less Multiplication + CLZERO // CLZERO instruction supported + CMOV // i686 CMOV + CMPCCXADD // CMPCCXADD instructions + CMPSB_SCADBS_SHORT // Fast short CMPSB and SCASB + CMPXCHG8 // CMPXCHG8 instruction + CPBOOST // Core Performance Boost + CPPC // AMD: Collaborative Processor Performance Control + CX16 // CMPXCHG16B Instruction + EFER_LMSLE_UNS // AMD: =Core::X86::Msr::EFER[LMSLE] is not supported, and MBZ + ENQCMD // Enqueue Command + ERMS // Enhanced REP MOVSB/STOSB + F16C // Half-precision floating-point conversion + FLUSH_L1D // Flush L1D cache + FMA3 // Intel FMA 3. Does not imply AVX. + FMA4 // Bulldozer FMA4 functions + FP128 // AMD: When set, the internal FP/SIMD execution datapath is no more than 128-bits wide + FP256 // AMD: When set, the internal FP/SIMD execution datapath is no more than 256-bits wide + FSRM // Fast Short Rep Mov + FXSR // FXSAVE, FXRESTOR instructions, CR4 bit 9 + FXSROPT // FXSAVE/FXRSTOR optimizations + GFNI // Galois Field New Instructions. May require other features (AVX, AVX512VL,AVX512F) based on usage. + HLE // Hardware Lock Elision + HRESET // If set CPU supports history reset and the IA32_HRESET_ENABLE MSR + HTT // Hyperthreading (enabled) + HWA // Hardware assert supported. Indicates support for MSRC001_10 + HYBRID_CPU // This part has CPUs of more than one type. + HYPERVISOR // This bit has been reserved by Intel & AMD for use by hypervisors + IA32_ARCH_CAP // IA32_ARCH_CAPABILITIES MSR (Intel) + IA32_CORE_CAP // IA32_CORE_CAPABILITIES MSR + IBPB // Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Predictor Barrier (IBPB) + IBRS // AMD: Indirect Branch Restricted Speculation + IBRS_PREFERRED // AMD: IBRS is preferred over software solution + IBRS_PROVIDES_SMP // AMD: IBRS provides Same Mode Protection + IBS // Instruction Based Sampling (AMD) + IBSBRNTRGT // Instruction Based Sampling Feature (AMD) + IBSFETCHSAM // Instruction Based Sampling Feature (AMD) + IBSFFV // Instruction Based Sampling Feature (AMD) + IBSOPCNT // Instruction Based Sampling Feature (AMD) + IBSOPCNTEXT // Instruction Based Sampling Feature (AMD) + IBSOPSAM // Instruction Based Sampling Feature (AMD) + IBSRDWROPCNT // Instruction Based Sampling Feature (AMD) + IBSRIPINVALIDCHK // Instruction Based Sampling Feature (AMD) + IBS_FETCH_CTLX // AMD: IBS fetch control extended MSR supported + IBS_OPDATA4 // AMD: IBS op data 4 MSR supported + IBS_OPFUSE // AMD: Indicates support for IbsOpFuse + IBS_PREVENTHOST // Disallowing IBS use by the host supported + IBS_ZEN4 // AMD: Fetch and Op IBS support IBS extensions added with Zen4 + IDPRED_CTRL // IPRED_DIS + INT_WBINVD // WBINVD/WBNOINVD are interruptible. + INVLPGB // NVLPGB and TLBSYNC instruction supported + LAHF // LAHF/SAHF in long mode + LAM // If set, CPU supports Linear Address Masking + LBRVIRT // LBR virtualization + LZCNT // LZCNT instruction + MCAOVERFLOW // MCA overflow recovery support. + MCDT_NO // Processor do not exhibit MXCSR Configuration Dependent Timing behavior and do not need to mitigate it. + MCOMMIT // MCOMMIT instruction supported + MD_CLEAR // VERW clears CPU buffers + MMX // standard MMX + MMXEXT // SSE integer functions or AMD MMX ext + MOVBE // MOVBE instruction (big-endian) + MOVDIR64B // Move 64 Bytes as Direct Store + MOVDIRI // Move Doubleword as Direct Store + MOVSB_ZL // Fast Zero-Length MOVSB + MOVU // AMD: MOVU SSE instructions are more efficient and should be preferred to SSE MOVL/MOVH. MOVUPS is more efficient than MOVLPS/MOVHPS. MOVUPD is more efficient than MOVLPD/MOVHPD + MPX // Intel MPX (Memory Protection Extensions) + MSRIRC // Instruction Retired Counter MSR available + MSRLIST // Read/Write List of Model Specific Registers + MSR_PAGEFLUSH // Page Flush MSR available + NRIPS // Indicates support for NRIP save on VMEXIT + NX // NX (No-Execute) bit + OSXSAVE // XSAVE enabled by OS + PCONFIG // PCONFIG for Intel Multi-Key Total Memory Encryption + POPCNT // POPCNT instruction + PPIN // AMD: Protected Processor Inventory Number support. Indicates that Protected Processor Inventory Number (PPIN) capability can be enabled + PREFETCHI // PREFETCHIT0/1 instructions + PSFD // Predictive Store Forward Disable + RDPRU // RDPRU instruction supported + RDRAND // RDRAND instruction is available + RDSEED // RDSEED instruction is available + RDTSCP // RDTSCP Instruction + RRSBA_CTRL // Restricted RSB Alternate + RTM // Restricted Transactional Memory + RTM_ALWAYS_ABORT // Indicates that the loaded microcode is forcing RTM abort. + SERIALIZE // Serialize Instruction Execution + SEV // AMD Secure Encrypted Virtualization supported + SEV_64BIT // AMD SEV guest execution only allowed from a 64-bit host + SEV_ALTERNATIVE // AMD SEV Alternate Injection supported + SEV_DEBUGSWAP // Full debug state swap supported for SEV-ES guests + SEV_ES // AMD SEV Encrypted State supported + SEV_RESTRICTED // AMD SEV Restricted Injection supported + SEV_SNP // AMD SEV Secure Nested Paging supported + SGX // Software Guard Extensions + SGXLC // Software Guard Extensions Launch Control + SHA // Intel SHA Extensions + SME // AMD Secure Memory Encryption supported + SME_COHERENT // AMD Hardware cache coherency across encryption domains enforced + SPEC_CTRL_SSBD // Speculative Store Bypass Disable + SRBDS_CTRL // SRBDS mitigation MSR available + SSE // SSE functions + SSE2 // P4 SSE functions + SSE3 // Prescott SSE3 functions + SSE4 // Penryn SSE4.1 functions + SSE42 // Nehalem SSE4.2 functions + SSE4A // AMD Barcelona microarchitecture SSE4a instructions + SSSE3 // Conroe SSSE3 functions + STIBP // Single Thread Indirect Branch Predictors + STIBP_ALWAYSON // AMD: Single Thread Indirect Branch Prediction Mode has Enhanced Performance and may be left Always On + STOSB_SHORT // Fast short STOSB + SUCCOR // Software uncorrectable error containment and recovery capability. + SVM // AMD Secure Virtual Machine + SVMDA // Indicates support for the SVM decode assists. + SVMFBASID // SVM, Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush only the current ASID's TLB entries. Also indicates support for the extended VMCBTLB_Control + SVML // AMD SVM lock. Indicates support for SVM-Lock. + SVMNP // AMD SVM nested paging + SVMPF // SVM pause intercept filter. Indicates support for the pause intercept filter + SVMPFT // SVM PAUSE filter threshold. Indicates support for the PAUSE filter cycle count threshold + SYSCALL // System-Call Extension (SCE): SYSCALL and SYSRET instructions. + SYSEE // SYSENTER and SYSEXIT instructions + TBM // AMD Trailing Bit Manipulation + TLB_FLUSH_NESTED // AMD: Flushing includes all the nested translations for guest translations + TME // Intel Total Memory Encryption. The following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. + TOPEXT // TopologyExtensions: topology extensions support. Indicates support for CPUID Fn8000_001D_EAX_x[N:0]-CPUID Fn8000_001E_EDX. + TSCRATEMSR // MSR based TSC rate control. Indicates support for MSR TSC ratio MSRC000_0104 + TSXLDTRK // Intel TSX Suspend Load Address Tracking + VAES // Vector AES. AVX(512) versions requires additional checks. + VMCBCLEAN // VMCB clean bits. Indicates support for VMCB clean bits. + VMPL // AMD VM Permission Levels supported + VMSA_REGPROT // AMD VMSA Register Protection supported + VMX // Virtual Machine Extensions + VPCLMULQDQ // Carry-Less Multiplication Quadword. Requires AVX for 3 register versions. + VTE // AMD Virtual Transparent Encryption supported + WAITPKG // TPAUSE, UMONITOR, UMWAIT + WBNOINVD // Write Back and Do Not Invalidate Cache + WRMSRNS // Non-Serializing Write to Model Specific Register + X87 // FPU + XGETBV1 // Supports XGETBV with ECX = 1 + XOP // Bulldozer XOP functions + XSAVE // XSAVE, XRESTOR, XSETBV, XGETBV + XSAVEC // Supports XSAVEC and the compacted form of XRSTOR. + XSAVEOPT // XSAVEOPT available + XSAVES // Supports XSAVES/XRSTORS and IA32_XSS + + // ARM features: + AESARM // AES instructions + ARMCPUID // Some CPU ID registers readable at user-level + ASIMD // Advanced SIMD + ASIMDDP // SIMD Dot Product + ASIMDHP // Advanced SIMD half-precision floating point + ASIMDRDM // Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH) + ATOMICS // Large System Extensions (LSE) + CRC32 // CRC32/CRC32C instructions + DCPOP // Data cache clean to Point of Persistence (DC CVAP) + EVTSTRM // Generic timer + FCMA // Floatin point complex number addition and multiplication + FP // Single-precision and double-precision floating point + FPHP // Half-precision floating point + GPA // Generic Pointer Authentication + JSCVT // Javascript-style double->int convert (FJCVTZS) + LRCPC // Weaker release consistency (LDAPR, etc) + PMULL // Polynomial Multiply instructions (PMULL/PMULL2) + SHA1 // SHA-1 instructions (SHA1C, etc) + SHA2 // SHA-2 instructions (SHA256H, etc) + SHA3 // SHA-3 instructions (EOR3, RAXI, XAR, BCAX) + SHA512 // SHA512 instructions + SM3 // SM3 instructions + SM4 // SM4 instructions + SVE // Scalable Vector Extension + // Keep it last. It automatically defines the size of []flagSet + lastID + + firstID FeatureID = UNKNOWN + 1 +) + +// CPUInfo contains information about the detected system CPU. +type CPUInfo struct { + BrandName string // Brand name reported by the CPU + VendorID Vendor // Comparable CPU vendor ID + VendorString string // Raw vendor string. + featureSet flagSet // Features of the CPU + PhysicalCores int // Number of physical processor cores in your CPU. Will be 0 if undetectable. + ThreadsPerCore int // Number of threads per physical core. Will be 1 if undetectable. + LogicalCores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable. + Family int // CPU family number + Model int // CPU model number + Stepping int // CPU stepping info + CacheLine int // Cache line size in bytes. Will be 0 if undetectable. + Hz int64 // Clock speed, if known, 0 otherwise. Will attempt to contain base clock speed. + BoostFreq int64 // Max clock speed, if known, 0 otherwise + Cache struct { + L1I int // L1 Instruction Cache (per core or shared). Will be -1 if undetected + L1D int // L1 Data Cache (per core or shared). Will be -1 if undetected + L2 int // L2 Cache (per core or shared). Will be -1 if undetected + L3 int // L3 Cache (per core, per ccx or shared). Will be -1 if undetected + } + SGX SGXSupport + maxFunc uint32 + maxExFunc uint32 +} + +var cpuid func(op uint32) (eax, ebx, ecx, edx uint32) +var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32) +var xgetbv func(index uint32) (eax, edx uint32) +var rdtscpAsm func() (eax, ebx, ecx, edx uint32) +var darwinHasAVX512 = func() bool { return false } + +// CPU contains information about the CPU as detected on startup, +// or when Detect last was called. +// +// Use this as the primary entry point to you data. +var CPU CPUInfo + +func init() { + initCPU() + Detect() +} + +// Detect will re-detect current CPU info. +// This will replace the content of the exported CPU variable. +// +// Unless you expect the CPU to change while you are running your program +// you should not need to call this function. +// If you call this, you must ensure that no other goroutine is accessing the +// exported CPU variable. +func Detect() { + // Set defaults + CPU.ThreadsPerCore = 1 + CPU.Cache.L1I = -1 + CPU.Cache.L1D = -1 + CPU.Cache.L2 = -1 + CPU.Cache.L3 = -1 + safe := true + if detectArmFlag != nil { + safe = !*detectArmFlag + } + addInfo(&CPU, safe) + if displayFeats != nil && *displayFeats { + fmt.Println("cpu features:", strings.Join(CPU.FeatureSet(), ",")) + // Exit with non-zero so tests will print value. + os.Exit(1) + } + if disableFlag != nil { + s := strings.Split(*disableFlag, ",") + for _, feat := range s { + feat := ParseFeature(strings.TrimSpace(feat)) + if feat != UNKNOWN { + CPU.featureSet.unset(feat) + } + } + } +} + +// DetectARM will detect ARM64 features. +// This is NOT done automatically since it can potentially crash +// if the OS does not handle the command. +// If in the future this can be done safely this function may not +// do anything. +func DetectARM() { + addInfo(&CPU, false) +} + +var detectArmFlag *bool +var displayFeats *bool +var disableFlag *string + +// Flags will enable flags. +// This must be called *before* flag.Parse AND +// Detect must be called after the flags have been parsed. +// Note that this means that any detection used in init() functions +// will not contain these flags. +func Flags() { + disableFlag = flag.String("cpu.disable", "", "disable cpu features; comma separated list") + displayFeats = flag.Bool("cpu.features", false, "lists cpu features and exits") + detectArmFlag = flag.Bool("cpu.arm", false, "allow ARM features to be detected; can potentially crash") +} + +// Supports returns whether the CPU supports all of the requested features. +func (c CPUInfo) Supports(ids ...FeatureID) bool { + for _, id := range ids { + if !c.featureSet.inSet(id) { + return false + } + } + return true +} + +// Has allows for checking a single feature. +// Should be inlined by the compiler. +func (c *CPUInfo) Has(id FeatureID) bool { + return c.featureSet.inSet(id) +} + +// AnyOf returns whether the CPU supports one or more of the requested features. +func (c CPUInfo) AnyOf(ids ...FeatureID) bool { + for _, id := range ids { + if c.featureSet.inSet(id) { + return true + } + } + return false +} + +// Features contains several features combined for a fast check using +// CpuInfo.HasAll +type Features *flagSet + +// CombineFeatures allows to combine several features for a close to constant time lookup. +func CombineFeatures(ids ...FeatureID) Features { + var v flagSet + for _, id := range ids { + v.set(id) + } + return &v +} + +func (c *CPUInfo) HasAll(f Features) bool { + return c.featureSet.hasSetP(f) +} + +// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels +var oneOfLevel = CombineFeatures(SYSEE, SYSCALL) +var level1Features = CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SSE, SSE2) +var level2Features = CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3) +var level3Features = CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE) +var level4Features = CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE, AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL) + +// X64Level returns the microarchitecture level detected on the CPU. +// If features are lacking or non x64 mode, 0 is returned. +// See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels +func (c CPUInfo) X64Level() int { + if !c.featureSet.hasOneOf(oneOfLevel) { + return 0 + } + if c.featureSet.hasSetP(level4Features) { + return 4 + } + if c.featureSet.hasSetP(level3Features) { + return 3 + } + if c.featureSet.hasSetP(level2Features) { + return 2 + } + if c.featureSet.hasSetP(level1Features) { + return 1 + } + return 0 +} + +// Disable will disable one or several features. +func (c *CPUInfo) Disable(ids ...FeatureID) bool { + for _, id := range ids { + c.featureSet.unset(id) + } + return true +} + +// Enable will disable one or several features even if they were undetected. +// This is of course not recommended for obvious reasons. +func (c *CPUInfo) Enable(ids ...FeatureID) bool { + for _, id := range ids { + c.featureSet.set(id) + } + return true +} + +// IsVendor returns true if vendor is recognized as Intel +func (c CPUInfo) IsVendor(v Vendor) bool { + return c.VendorID == v +} + +// FeatureSet returns all available features as strings. +func (c CPUInfo) FeatureSet() []string { + s := make([]string, 0, c.featureSet.nEnabled()) + s = append(s, c.featureSet.Strings()...) + return s +} + +// RTCounter returns the 64-bit time-stamp counter +// Uses the RDTSCP instruction. The value 0 is returned +// if the CPU does not support the instruction. +func (c CPUInfo) RTCounter() uint64 { + if !c.Supports(RDTSCP) { + return 0 + } + a, _, _, d := rdtscpAsm() + return uint64(a) | (uint64(d) << 32) +} + +// Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP. +// This variable is OS dependent, but on Linux contains information +// about the current cpu/core the code is running on. +// If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned. +func (c CPUInfo) Ia32TscAux() uint32 { + if !c.Supports(RDTSCP) { + return 0 + } + _, _, ecx, _ := rdtscpAsm() + return ecx +} + +// LogicalCPU will return the Logical CPU the code is currently executing on. +// This is likely to change when the OS re-schedules the running thread +// to another CPU. +// If the current core cannot be detected, -1 will be returned. +func (c CPUInfo) LogicalCPU() int { + if c.maxFunc < 1 { + return -1 + } + _, ebx, _, _ := cpuid(1) + return int(ebx >> 24) +} + +// frequencies tries to compute the clock speed of the CPU. If leaf 15 is +// supported, use it, otherwise parse the brand string. Yes, really. +func (c *CPUInfo) frequencies() { + c.Hz, c.BoostFreq = 0, 0 + mfi := maxFunctionID() + if mfi >= 0x15 { + eax, ebx, ecx, _ := cpuid(0x15) + if eax != 0 && ebx != 0 && ecx != 0 { + c.Hz = (int64(ecx) * int64(ebx)) / int64(eax) + } + } + if mfi >= 0x16 { + a, b, _, _ := cpuid(0x16) + // Base... + if a&0xffff > 0 { + c.Hz = int64(a&0xffff) * 1_000_000 + } + // Boost... + if b&0xffff > 0 { + c.BoostFreq = int64(b&0xffff) * 1_000_000 + } + } + if c.Hz > 0 { + return + } + + // computeHz determines the official rated speed of a CPU from its brand + // string. This insanity is *actually the official documented way to do + // this according to Intel*, prior to leaf 0x15 existing. The official + // documentation only shows this working for exactly `x.xx` or `xxxx` + // cases, e.g., `2.50GHz` or `1300MHz`; this parser will accept other + // sizes. + model := c.BrandName + hz := strings.LastIndex(model, "Hz") + if hz < 3 { + return + } + var multiplier int64 + switch model[hz-1] { + case 'M': + multiplier = 1000 * 1000 + case 'G': + multiplier = 1000 * 1000 * 1000 + case 'T': + multiplier = 1000 * 1000 * 1000 * 1000 + } + if multiplier == 0 { + return + } + freq := int64(0) + divisor := int64(0) + decimalShift := int64(1) + var i int + for i = hz - 2; i >= 0 && model[i] != ' '; i-- { + if model[i] >= '0' && model[i] <= '9' { + freq += int64(model[i]-'0') * decimalShift + decimalShift *= 10 + } else if model[i] == '.' { + if divisor != 0 { + return + } + divisor = decimalShift + } else { + return + } + } + // we didn't find a space + if i < 0 { + return + } + if divisor != 0 { + c.Hz = (freq * multiplier) / divisor + return + } + c.Hz = freq * multiplier +} + +// VM Will return true if the cpu id indicates we are in +// a virtual machine. +func (c CPUInfo) VM() bool { + return CPU.featureSet.inSet(HYPERVISOR) +} + +// flags contains detected cpu features and characteristics +type flags uint64 + +// log2(bits_in_uint64) +const flagBitsLog2 = 6 +const flagBits = 1 << flagBitsLog2 +const flagMask = flagBits - 1 + +// flagSet contains detected cpu features and characteristics in an array of flags +type flagSet [(lastID + flagMask) / flagBits]flags + +func (s *flagSet) inSet(feat FeatureID) bool { + return s[feat>>flagBitsLog2]&(1<<(feat&flagMask)) != 0 +} + +func (s *flagSet) set(feat FeatureID) { + s[feat>>flagBitsLog2] |= 1 << (feat & flagMask) +} + +// setIf will set a feature if boolean is true. +func (s *flagSet) setIf(cond bool, features ...FeatureID) { + if cond { + for _, offset := range features { + s[offset>>flagBitsLog2] |= 1 << (offset & flagMask) + } + } +} + +func (s *flagSet) unset(offset FeatureID) { + bit := flags(1 << (offset & flagMask)) + s[offset>>flagBitsLog2] = s[offset>>flagBitsLog2] & ^bit +} + +// or with another flagset. +func (s *flagSet) or(other flagSet) { + for i, v := range other[:] { + s[i] |= v + } +} + +// hasSet returns whether all features are present. +func (s *flagSet) hasSet(other flagSet) bool { + for i, v := range other[:] { + if s[i]&v != v { + return false + } + } + return true +} + +// hasSet returns whether all features are present. +func (s *flagSet) hasSetP(other *flagSet) bool { + for i, v := range other[:] { + if s[i]&v != v { + return false + } + } + return true +} + +// hasOneOf returns whether one or more features are present. +func (s *flagSet) hasOneOf(other *flagSet) bool { + for i, v := range other[:] { + if s[i]&v != 0 { + return true + } + } + return false +} + +// nEnabled will return the number of enabled flags. +func (s *flagSet) nEnabled() (n int) { + for _, v := range s[:] { + n += bits.OnesCount64(uint64(v)) + } + return n +} + +func flagSetWith(feat ...FeatureID) flagSet { + var res flagSet + for _, f := range feat { + res.set(f) + } + return res +} + +// ParseFeature will parse the string and return the ID of the matching feature. +// Will return UNKNOWN if not found. +func ParseFeature(s string) FeatureID { + s = strings.ToUpper(s) + for i := firstID; i < lastID; i++ { + if i.String() == s { + return i + } + } + return UNKNOWN +} + +// Strings returns an array of the detected features for FlagsSet. +func (s flagSet) Strings() []string { + if len(s) == 0 { + return []string{""} + } + r := make([]string, 0) + for i := firstID; i < lastID; i++ { + if s.inSet(i) { + r = append(r, i.String()) + } + } + return r +} + +func maxExtendedFunction() uint32 { + eax, _, _, _ := cpuid(0x80000000) + return eax +} + +func maxFunctionID() uint32 { + a, _, _, _ := cpuid(0) + return a +} + +func brandName() string { + if maxExtendedFunction() >= 0x80000004 { + v := make([]uint32, 0, 48) + for i := uint32(0); i < 3; i++ { + a, b, c, d := cpuid(0x80000002 + i) + v = append(v, a, b, c, d) + } + return strings.Trim(string(valAsString(v...)), " ") + } + return "unknown" +} + +func threadsPerCore() int { + mfi := maxFunctionID() + vend, _ := vendorID() + + if mfi < 0x4 || (vend != Intel && vend != AMD) { + return 1 + } + + if mfi < 0xb { + if vend != Intel { + return 1 + } + _, b, _, d := cpuid(1) + if (d & (1 << 28)) != 0 { + // v will contain logical core count + v := (b >> 16) & 255 + if v > 1 { + a4, _, _, _ := cpuid(4) + // physical cores + v2 := (a4 >> 26) + 1 + if v2 > 0 { + return int(v) / int(v2) + } + } + } + return 1 + } + _, b, _, _ := cpuidex(0xb, 0) + if b&0xffff == 0 { + if vend == AMD { + // Workaround for AMD returning 0, assume 2 if >= Zen 2 + // It will be more correct than not. + fam, _, _ := familyModel() + _, _, _, d := cpuid(1) + if (d&(1<<28)) != 0 && fam >= 23 { + return 2 + } + } + return 1 + } + return int(b & 0xffff) +} + +func logicalCores() int { + mfi := maxFunctionID() + v, _ := vendorID() + switch v { + case Intel: + // Use this on old Intel processors + if mfi < 0xb { + if mfi < 1 { + return 0 + } + // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID) + // that can be assigned to logical processors in a physical package. + // The value may not be the same as the number of logical processors that are present in the hardware of a physical package. + _, ebx, _, _ := cpuid(1) + logical := (ebx >> 16) & 0xff + return int(logical) + } + _, b, _, _ := cpuidex(0xb, 1) + return int(b & 0xffff) + case AMD, Hygon: + _, b, _, _ := cpuid(1) + return int((b >> 16) & 0xff) + default: + return 0 + } +} + +func familyModel() (family, model, stepping int) { + if maxFunctionID() < 0x1 { + return 0, 0, 0 + } + eax, _, _, _ := cpuid(1) + // If BaseFamily[3:0] is less than Fh then ExtendedFamily[7:0] is reserved and Family is equal to BaseFamily[3:0]. + family = int((eax >> 8) & 0xf) + extFam := family == 0x6 // Intel is 0x6, needs extended model. + if family == 0xf { + // Add ExtFamily + family += int((eax >> 20) & 0xff) + extFam = true + } + // If BaseFamily[3:0] is less than 0Fh then ExtendedModel[3:0] is reserved and Model is equal to BaseModel[3:0]. + model = int((eax >> 4) & 0xf) + if extFam { + // Add ExtModel + model += int((eax >> 12) & 0xf0) + } + stepping = int(eax & 0xf) + return family, model, stepping +} + +func physicalCores() int { + v, _ := vendorID() + switch v { + case Intel: + return logicalCores() / threadsPerCore() + case AMD, Hygon: + lc := logicalCores() + tpc := threadsPerCore() + if lc > 0 && tpc > 0 { + return lc / tpc + } + + // The following is inaccurate on AMD EPYC 7742 64-Core Processor + if maxExtendedFunction() >= 0x80000008 { + _, _, c, _ := cpuid(0x80000008) + if c&0xff > 0 { + return int(c&0xff) + 1 + } + } + } + return 0 +} + +// Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID +var vendorMapping = map[string]Vendor{ + "AMDisbetter!": AMD, + "AuthenticAMD": AMD, + "CentaurHauls": VIA, + "GenuineIntel": Intel, + "TransmetaCPU": Transmeta, + "GenuineTMx86": Transmeta, + "Geode by NSC": NSC, + "VIA VIA VIA ": VIA, + "KVMKVMKVMKVM": KVM, + "Microsoft Hv": MSVM, + "VMwareVMware": VMware, + "XenVMMXenVMM": XenHVM, + "bhyve bhyve ": Bhyve, + "HygonGenuine": Hygon, + "Vortex86 SoC": SiS, + "SiS SiS SiS ": SiS, + "RiseRiseRise": SiS, + "Genuine RDC": RDC, +} + +func vendorID() (Vendor, string) { + _, b, c, d := cpuid(0) + v := string(valAsString(b, d, c)) + vend, ok := vendorMapping[v] + if !ok { + return VendorUnknown, v + } + return vend, v +} + +func cacheLine() int { + if maxFunctionID() < 0x1 { + return 0 + } + + _, ebx, _, _ := cpuid(1) + cache := (ebx & 0xff00) >> 5 // cflush size + if cache == 0 && maxExtendedFunction() >= 0x80000006 { + _, _, ecx, _ := cpuid(0x80000006) + cache = ecx & 0xff // cacheline size + } + // TODO: Read from Cache and TLB Information + return int(cache) +} + +func (c *CPUInfo) cacheSize() { + c.Cache.L1D = -1 + c.Cache.L1I = -1 + c.Cache.L2 = -1 + c.Cache.L3 = -1 + vendor, _ := vendorID() + switch vendor { + case Intel: + if maxFunctionID() < 4 { + return + } + c.Cache.L1I, c.Cache.L1D, c.Cache.L2, c.Cache.L3 = 0, 0, 0, 0 + for i := uint32(0); ; i++ { + eax, ebx, ecx, _ := cpuidex(4, i) + cacheType := eax & 15 + if cacheType == 0 { + break + } + cacheLevel := (eax >> 5) & 7 + coherency := int(ebx&0xfff) + 1 + partitions := int((ebx>>12)&0x3ff) + 1 + associativity := int((ebx>>22)&0x3ff) + 1 + sets := int(ecx) + 1 + size := associativity * partitions * coherency * sets + switch cacheLevel { + case 1: + if cacheType == 1 { + // 1 = Data Cache + c.Cache.L1D = size + } else if cacheType == 2 { + // 2 = Instruction Cache + c.Cache.L1I = size + } else { + if c.Cache.L1D < 0 { + c.Cache.L1I = size + } + if c.Cache.L1I < 0 { + c.Cache.L1I = size + } + } + case 2: + c.Cache.L2 = size + case 3: + c.Cache.L3 = size + } + } + case AMD, Hygon: + // Untested. + if maxExtendedFunction() < 0x80000005 { + return + } + _, _, ecx, edx := cpuid(0x80000005) + c.Cache.L1D = int(((ecx >> 24) & 0xFF) * 1024) + c.Cache.L1I = int(((edx >> 24) & 0xFF) * 1024) + + if maxExtendedFunction() < 0x80000006 { + return + } + _, _, ecx, _ = cpuid(0x80000006) + c.Cache.L2 = int(((ecx >> 16) & 0xFFFF) * 1024) + + // CPUID Fn8000_001D_EAX_x[N:0] Cache Properties + if maxExtendedFunction() < 0x8000001D || !c.Has(TOPEXT) { + return + } + + // Xen Hypervisor is buggy and returns the same entry no matter ECX value. + // Hack: When we encounter the same entry 100 times we break. + nSame := 0 + var last uint32 + for i := uint32(0); i < math.MaxUint32; i++ { + eax, ebx, ecx, _ := cpuidex(0x8000001D, i) + + level := (eax >> 5) & 7 + cacheNumSets := ecx + 1 + cacheLineSize := 1 + (ebx & 2047) + cachePhysPartitions := 1 + ((ebx >> 12) & 511) + cacheNumWays := 1 + ((ebx >> 22) & 511) + + typ := eax & 15 + size := int(cacheNumSets * cacheLineSize * cachePhysPartitions * cacheNumWays) + if typ == 0 { + return + } + + // Check for the same value repeated. + comb := eax ^ ebx ^ ecx + if comb == last { + nSame++ + if nSame == 100 { + return + } + } + last = comb + + switch level { + case 1: + switch typ { + case 1: + // Data cache + c.Cache.L1D = size + case 2: + // Inst cache + c.Cache.L1I = size + default: + if c.Cache.L1D < 0 { + c.Cache.L1I = size + } + if c.Cache.L1I < 0 { + c.Cache.L1I = size + } + } + case 2: + c.Cache.L2 = size + case 3: + c.Cache.L3 = size + } + } + } +} + +type SGXEPCSection struct { + BaseAddress uint64 + EPCSize uint64 +} + +type SGXSupport struct { + Available bool + LaunchControl bool + SGX1Supported bool + SGX2Supported bool + MaxEnclaveSizeNot64 int64 + MaxEnclaveSize64 int64 + EPCSections []SGXEPCSection +} + +func hasSGX(available, lc bool) (rval SGXSupport) { + rval.Available = available + + if !available { + return + } + + rval.LaunchControl = lc + + a, _, _, d := cpuidex(0x12, 0) + rval.SGX1Supported = a&0x01 != 0 + rval.SGX2Supported = a&0x02 != 0 + rval.MaxEnclaveSizeNot64 = 1 << (d & 0xFF) // pow 2 + rval.MaxEnclaveSize64 = 1 << ((d >> 8) & 0xFF) // pow 2 + rval.EPCSections = make([]SGXEPCSection, 0) + + for subleaf := uint32(2); subleaf < 2+8; subleaf++ { + eax, ebx, ecx, edx := cpuidex(0x12, subleaf) + leafType := eax & 0xf + + if leafType == 0 { + // Invalid subleaf, stop iterating + break + } else if leafType == 1 { + // EPC Section subleaf + baseAddress := uint64(eax&0xfffff000) + (uint64(ebx&0x000fffff) << 32) + size := uint64(ecx&0xfffff000) + (uint64(edx&0x000fffff) << 32) + + section := SGXEPCSection{BaseAddress: baseAddress, EPCSize: size} + rval.EPCSections = append(rval.EPCSections, section) + } + } + + return +} + +func support() flagSet { + var fs flagSet + mfi := maxFunctionID() + vend, _ := vendorID() + if mfi < 0x1 { + return fs + } + family, model, _ := familyModel() + + _, _, c, d := cpuid(1) + fs.setIf((d&(1<<0)) != 0, X87) + fs.setIf((d&(1<<8)) != 0, CMPXCHG8) + fs.setIf((d&(1<<11)) != 0, SYSEE) + fs.setIf((d&(1<<15)) != 0, CMOV) + fs.setIf((d&(1<<23)) != 0, MMX) + fs.setIf((d&(1<<24)) != 0, FXSR) + fs.setIf((d&(1<<25)) != 0, FXSROPT) + fs.setIf((d&(1<<25)) != 0, SSE) + fs.setIf((d&(1<<26)) != 0, SSE2) + fs.setIf((c&1) != 0, SSE3) + fs.setIf((c&(1<<5)) != 0, VMX) + fs.setIf((c&(1<<9)) != 0, SSSE3) + fs.setIf((c&(1<<19)) != 0, SSE4) + fs.setIf((c&(1<<20)) != 0, SSE42) + fs.setIf((c&(1<<25)) != 0, AESNI) + fs.setIf((c&(1<<1)) != 0, CLMUL) + fs.setIf(c&(1<<22) != 0, MOVBE) + fs.setIf(c&(1<<23) != 0, POPCNT) + fs.setIf(c&(1<<30) != 0, RDRAND) + + // This bit has been reserved by Intel & AMD for use by hypervisors, + // and indicates the presence of a hypervisor. + fs.setIf(c&(1<<31) != 0, HYPERVISOR) + fs.setIf(c&(1<<29) != 0, F16C) + fs.setIf(c&(1<<13) != 0, CX16) + + if vend == Intel && (d&(1<<28)) != 0 && mfi >= 4 { + fs.setIf(threadsPerCore() > 1, HTT) + } + if vend == AMD && (d&(1<<28)) != 0 && mfi >= 4 { + fs.setIf(threadsPerCore() > 1, HTT) + } + fs.setIf(c&1<<26 != 0, XSAVE) + fs.setIf(c&1<<27 != 0, OSXSAVE) + // Check XGETBV/XSAVE (26), OXSAVE (27) and AVX (28) bits + const avxCheck = 1<<26 | 1<<27 | 1<<28 + if c&avxCheck == avxCheck { + // Check for OS support + eax, _ := xgetbv(0) + if (eax & 0x6) == 0x6 { + fs.set(AVX) + switch vend { + case Intel: + // Older than Haswell. + fs.setIf(family == 6 && model < 60, AVXSLOW) + case AMD: + // Older than Zen 2 + fs.setIf(family < 23 || (family == 23 && model < 49), AVXSLOW) + } + } + } + // FMA3 can be used with SSE registers, so no OS support is strictly needed. + // fma3 and OSXSAVE needed. + const fma3Check = 1<<12 | 1<<27 + fs.setIf(c&fma3Check == fma3Check, FMA3) + + // Check AVX2, AVX2 requires OS support, but BMI1/2 don't. + if mfi >= 7 { + _, ebx, ecx, edx := cpuidex(7, 0) + if fs.inSet(AVX) && (ebx&0x00000020) != 0 { + fs.set(AVX2) + } + // CPUID.(EAX=7, ECX=0).EBX + if (ebx & 0x00000008) != 0 { + fs.set(BMI1) + fs.setIf((ebx&0x00000100) != 0, BMI2) + } + fs.setIf(ebx&(1<<2) != 0, SGX) + fs.setIf(ebx&(1<<4) != 0, HLE) + fs.setIf(ebx&(1<<9) != 0, ERMS) + fs.setIf(ebx&(1<<11) != 0, RTM) + fs.setIf(ebx&(1<<14) != 0, MPX) + fs.setIf(ebx&(1<<18) != 0, RDSEED) + fs.setIf(ebx&(1<<19) != 0, ADX) + fs.setIf(ebx&(1<<29) != 0, SHA) + + // CPUID.(EAX=7, ECX=0).ECX + fs.setIf(ecx&(1<<5) != 0, WAITPKG) + fs.setIf(ecx&(1<<7) != 0, CETSS) + fs.setIf(ecx&(1<<8) != 0, GFNI) + fs.setIf(ecx&(1<<9) != 0, VAES) + fs.setIf(ecx&(1<<10) != 0, VPCLMULQDQ) + fs.setIf(ecx&(1<<13) != 0, TME) + fs.setIf(ecx&(1<<25) != 0, CLDEMOTE) + fs.setIf(ecx&(1<<27) != 0, MOVDIRI) + fs.setIf(ecx&(1<<28) != 0, MOVDIR64B) + fs.setIf(ecx&(1<<29) != 0, ENQCMD) + fs.setIf(ecx&(1<<30) != 0, SGXLC) + + // CPUID.(EAX=7, ECX=0).EDX + fs.setIf(edx&(1<<4) != 0, FSRM) + fs.setIf(edx&(1<<9) != 0, SRBDS_CTRL) + fs.setIf(edx&(1<<10) != 0, MD_CLEAR) + fs.setIf(edx&(1<<11) != 0, RTM_ALWAYS_ABORT) + fs.setIf(edx&(1<<14) != 0, SERIALIZE) + fs.setIf(edx&(1<<15) != 0, HYBRID_CPU) + fs.setIf(edx&(1<<16) != 0, TSXLDTRK) + fs.setIf(edx&(1<<18) != 0, PCONFIG) + fs.setIf(edx&(1<<20) != 0, CETIBT) + fs.setIf(edx&(1<<26) != 0, IBPB) + fs.setIf(edx&(1<<27) != 0, STIBP) + fs.setIf(edx&(1<<28) != 0, FLUSH_L1D) + fs.setIf(edx&(1<<29) != 0, IA32_ARCH_CAP) + fs.setIf(edx&(1<<30) != 0, IA32_CORE_CAP) + fs.setIf(edx&(1<<31) != 0, SPEC_CTRL_SSBD) + + // CPUID.(EAX=7, ECX=1).EDX + fs.setIf(edx&(1<<4) != 0, AVXVNNIINT8) + fs.setIf(edx&(1<<5) != 0, AVXNECONVERT) + fs.setIf(edx&(1<<14) != 0, PREFETCHI) + + // CPUID.(EAX=7, ECX=1).EAX + eax1, _, _, _ := cpuidex(7, 1) + fs.setIf(fs.inSet(AVX) && eax1&(1<<4) != 0, AVXVNNI) + fs.setIf(eax1&(1<<7) != 0, CMPCCXADD) + fs.setIf(eax1&(1<<10) != 0, MOVSB_ZL) + fs.setIf(eax1&(1<<11) != 0, STOSB_SHORT) + fs.setIf(eax1&(1<<12) != 0, CMPSB_SCADBS_SHORT) + fs.setIf(eax1&(1<<22) != 0, HRESET) + fs.setIf(eax1&(1<<23) != 0, AVXIFMA) + fs.setIf(eax1&(1<<26) != 0, LAM) + + // Only detect AVX-512 features if XGETBV is supported + if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) { + // Check for OS support + eax, _ := xgetbv(0) + + // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and + // ZMM16-ZMM31 state are enabled by OS) + /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS). + hasAVX512 := (eax>>5)&7 == 7 && (eax>>1)&3 == 3 + if runtime.GOOS == "darwin" { + hasAVX512 = fs.inSet(AVX) && darwinHasAVX512() + } + if hasAVX512 { + fs.setIf(ebx&(1<<16) != 0, AVX512F) + fs.setIf(ebx&(1<<17) != 0, AVX512DQ) + fs.setIf(ebx&(1<<21) != 0, AVX512IFMA) + fs.setIf(ebx&(1<<26) != 0, AVX512PF) + fs.setIf(ebx&(1<<27) != 0, AVX512ER) + fs.setIf(ebx&(1<<28) != 0, AVX512CD) + fs.setIf(ebx&(1<<30) != 0, AVX512BW) + fs.setIf(ebx&(1<<31) != 0, AVX512VL) + // ecx + fs.setIf(ecx&(1<<1) != 0, AVX512VBMI) + fs.setIf(ecx&(1<<6) != 0, AVX512VBMI2) + fs.setIf(ecx&(1<<11) != 0, AVX512VNNI) + fs.setIf(ecx&(1<<12) != 0, AVX512BITALG) + fs.setIf(ecx&(1<<14) != 0, AVX512VPOPCNTDQ) + // edx + fs.setIf(edx&(1<<8) != 0, AVX512VP2INTERSECT) + fs.setIf(edx&(1<<22) != 0, AMXBF16) + fs.setIf(edx&(1<<23) != 0, AVX512FP16) + fs.setIf(edx&(1<<24) != 0, AMXTILE) + fs.setIf(edx&(1<<25) != 0, AMXINT8) + // eax1 = CPUID.(EAX=7, ECX=1).EAX + fs.setIf(eax1&(1<<5) != 0, AVX512BF16) + fs.setIf(eax1&(1<<19) != 0, WRMSRNS) + fs.setIf(eax1&(1<<21) != 0, AMXFP16) + fs.setIf(eax1&(1<<27) != 0, MSRLIST) + } + } + + // CPUID.(EAX=7, ECX=2) + _, _, _, edx = cpuidex(7, 2) + fs.setIf(edx&(1<<0) != 0, PSFD) + fs.setIf(edx&(1<<1) != 0, IDPRED_CTRL) + fs.setIf(edx&(1<<2) != 0, RRSBA_CTRL) + fs.setIf(edx&(1<<4) != 0, BHI_CTRL) + fs.setIf(edx&(1<<5) != 0, MCDT_NO) + + } + + // Processor Extended State Enumeration Sub-leaf (EAX = 0DH, ECX = 1) + // EAX + // Bit 00: XSAVEOPT is available. + // Bit 01: Supports XSAVEC and the compacted form of XRSTOR if set. + // Bit 02: Supports XGETBV with ECX = 1 if set. + // Bit 03: Supports XSAVES/XRSTORS and IA32_XSS if set. + // Bits 31 - 04: Reserved. + // EBX + // Bits 31 - 00: The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS. + // ECX + // Bits 31 - 00: Reports the supported bits of the lower 32 bits of the IA32_XSS MSR. IA32_XSS[n] can be set to 1 only if ECX[n] is 1. + // EDX? + // Bits 07 - 00: Used for XCR0. Bit 08: PT state. Bit 09: Used for XCR0. Bits 12 - 10: Reserved. Bit 13: HWP state. Bits 31 - 14: Reserved. + if mfi >= 0xd { + if fs.inSet(XSAVE) { + eax, _, _, _ := cpuidex(0xd, 1) + fs.setIf(eax&(1<<0) != 0, XSAVEOPT) + fs.setIf(eax&(1<<1) != 0, XSAVEC) + fs.setIf(eax&(1<<2) != 0, XGETBV1) + fs.setIf(eax&(1<<3) != 0, XSAVES) + } + } + if maxExtendedFunction() >= 0x80000001 { + _, _, c, d := cpuid(0x80000001) + if (c & (1 << 5)) != 0 { + fs.set(LZCNT) + fs.set(POPCNT) + } + // ECX + fs.setIf((c&(1<<0)) != 0, LAHF) + fs.setIf((c&(1<<2)) != 0, SVM) + fs.setIf((c&(1<<6)) != 0, SSE4A) + fs.setIf((c&(1<<10)) != 0, IBS) + fs.setIf((c&(1<<22)) != 0, TOPEXT) + + // EDX + fs.setIf(d&(1<<11) != 0, SYSCALL) + fs.setIf(d&(1<<20) != 0, NX) + fs.setIf(d&(1<<22) != 0, MMXEXT) + fs.setIf(d&(1<<23) != 0, MMX) + fs.setIf(d&(1<<24) != 0, FXSR) + fs.setIf(d&(1<<25) != 0, FXSROPT) + fs.setIf(d&(1<<27) != 0, RDTSCP) + fs.setIf(d&(1<<30) != 0, AMD3DNOWEXT) + fs.setIf(d&(1<<31) != 0, AMD3DNOW) + + /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be + * used unless the OS has AVX support. */ + if fs.inSet(AVX) { + fs.setIf((c&(1<<11)) != 0, XOP) + fs.setIf((c&(1<<16)) != 0, FMA4) + } + + } + if maxExtendedFunction() >= 0x80000007 { + _, b, _, d := cpuid(0x80000007) + fs.setIf((b&(1<<0)) != 0, MCAOVERFLOW) + fs.setIf((b&(1<<1)) != 0, SUCCOR) + fs.setIf((b&(1<<2)) != 0, HWA) + fs.setIf((d&(1<<9)) != 0, CPBOOST) + } + + if maxExtendedFunction() >= 0x80000008 { + _, b, _, _ := cpuid(0x80000008) + fs.setIf(b&(1<<28) != 0, PSFD) + fs.setIf(b&(1<<27) != 0, CPPC) + fs.setIf(b&(1<<24) != 0, SPEC_CTRL_SSBD) + fs.setIf(b&(1<<23) != 0, PPIN) + fs.setIf(b&(1<<21) != 0, TLB_FLUSH_NESTED) + fs.setIf(b&(1<<20) != 0, EFER_LMSLE_UNS) + fs.setIf(b&(1<<19) != 0, IBRS_PROVIDES_SMP) + fs.setIf(b&(1<<18) != 0, IBRS_PREFERRED) + fs.setIf(b&(1<<17) != 0, STIBP_ALWAYSON) + fs.setIf(b&(1<<15) != 0, STIBP) + fs.setIf(b&(1<<14) != 0, IBRS) + fs.setIf((b&(1<<13)) != 0, INT_WBINVD) + fs.setIf(b&(1<<12) != 0, IBPB) + fs.setIf((b&(1<<9)) != 0, WBNOINVD) + fs.setIf((b&(1<<8)) != 0, MCOMMIT) + fs.setIf((b&(1<<4)) != 0, RDPRU) + fs.setIf((b&(1<<3)) != 0, INVLPGB) + fs.setIf((b&(1<<1)) != 0, MSRIRC) + fs.setIf((b&(1<<0)) != 0, CLZERO) + } + + if fs.inSet(SVM) && maxExtendedFunction() >= 0x8000000A { + _, _, _, edx := cpuid(0x8000000A) + fs.setIf((edx>>0)&1 == 1, SVMNP) + fs.setIf((edx>>1)&1 == 1, LBRVIRT) + fs.setIf((edx>>2)&1 == 1, SVML) + fs.setIf((edx>>3)&1 == 1, NRIPS) + fs.setIf((edx>>4)&1 == 1, TSCRATEMSR) + fs.setIf((edx>>5)&1 == 1, VMCBCLEAN) + fs.setIf((edx>>6)&1 == 1, SVMFBASID) + fs.setIf((edx>>7)&1 == 1, SVMDA) + fs.setIf((edx>>10)&1 == 1, SVMPF) + fs.setIf((edx>>12)&1 == 1, SVMPFT) + } + + if maxExtendedFunction() >= 0x8000001a { + eax, _, _, _ := cpuid(0x8000001a) + fs.setIf((eax>>0)&1 == 1, FP128) + fs.setIf((eax>>1)&1 == 1, MOVU) + fs.setIf((eax>>2)&1 == 1, FP256) + } + + if maxExtendedFunction() >= 0x8000001b && fs.inSet(IBS) { + eax, _, _, _ := cpuid(0x8000001b) + fs.setIf((eax>>0)&1 == 1, IBSFFV) + fs.setIf((eax>>1)&1 == 1, IBSFETCHSAM) + fs.setIf((eax>>2)&1 == 1, IBSOPSAM) + fs.setIf((eax>>3)&1 == 1, IBSRDWROPCNT) + fs.setIf((eax>>4)&1 == 1, IBSOPCNT) + fs.setIf((eax>>5)&1 == 1, IBSBRNTRGT) + fs.setIf((eax>>6)&1 == 1, IBSOPCNTEXT) + fs.setIf((eax>>7)&1 == 1, IBSRIPINVALIDCHK) + fs.setIf((eax>>8)&1 == 1, IBS_OPFUSE) + fs.setIf((eax>>9)&1 == 1, IBS_FETCH_CTLX) + fs.setIf((eax>>10)&1 == 1, IBS_OPDATA4) // Doc says "Fixed,0. IBS op data 4 MSR supported", but assuming they mean 1. + fs.setIf((eax>>11)&1 == 1, IBS_ZEN4) + } + + if maxExtendedFunction() >= 0x8000001f && vend == AMD { + a, _, _, _ := cpuid(0x8000001f) + fs.setIf((a>>0)&1 == 1, SME) + fs.setIf((a>>1)&1 == 1, SEV) + fs.setIf((a>>2)&1 == 1, MSR_PAGEFLUSH) + fs.setIf((a>>3)&1 == 1, SEV_ES) + fs.setIf((a>>4)&1 == 1, SEV_SNP) + fs.setIf((a>>5)&1 == 1, VMPL) + fs.setIf((a>>10)&1 == 1, SME_COHERENT) + fs.setIf((a>>11)&1 == 1, SEV_64BIT) + fs.setIf((a>>12)&1 == 1, SEV_RESTRICTED) + fs.setIf((a>>13)&1 == 1, SEV_ALTERNATIVE) + fs.setIf((a>>14)&1 == 1, SEV_DEBUGSWAP) + fs.setIf((a>>15)&1 == 1, IBS_PREVENTHOST) + fs.setIf((a>>16)&1 == 1, VTE) + fs.setIf((a>>24)&1 == 1, VMSA_REGPROT) + } + + return fs +} + +func valAsString(values ...uint32) []byte { + r := make([]byte, 4*len(values)) + for i, v := range values { + dst := r[i*4:] + dst[0] = byte(v & 0xff) + dst[1] = byte((v >> 8) & 0xff) + dst[2] = byte((v >> 16) & 0xff) + dst[3] = byte((v >> 24) & 0xff) + switch { + case dst[0] == 0: + return r[:i*4] + case dst[1] == 0: + return r[:i*4+1] + case dst[2] == 0: + return r[:i*4+2] + case dst[3] == 0: + return r[:i*4+3] + } + } + return r +} diff --git a/vendor/github.com/klauspost/cpuid/v2/cpuid_386.s b/vendor/github.com/klauspost/cpuid/v2/cpuid_386.s new file mode 100644 index 0000000..8587c3a --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/cpuid_386.s @@ -0,0 +1,47 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//+build 386,!gccgo,!noasm,!appengine + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORL CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+4(FP) + MOVL BX, ebx+8(FP) + MOVL CX, ecx+12(FP) + MOVL DX, edx+16(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func xgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+4(FP) + MOVL DX, edx+8(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET + +// func asmDarwinHasAVX512() bool +TEXT ·asmDarwinHasAVX512(SB), 7, $0 + MOVL $0, eax+0(FP) + RET diff --git a/vendor/github.com/klauspost/cpuid/v2/cpuid_amd64.s b/vendor/github.com/klauspost/cpuid/v2/cpuid_amd64.s new file mode 100644 index 0000000..bc11f89 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/cpuid_amd64.s @@ -0,0 +1,72 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//+build amd64,!gccgo,!noasm,!appengine + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORQ CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmXgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+8(FP) + MOVL DX, edx+12(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET + +// From https://go-review.googlesource.com/c/sys/+/285572/ +// func asmDarwinHasAVX512() bool +TEXT ·asmDarwinHasAVX512(SB), 7, $0-1 + MOVB $0, ret+0(FP) // default to false + +#ifdef GOOS_darwin // return if not darwin +#ifdef GOARCH_amd64 // return if not amd64 +// These values from: +// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h +#define commpage64_base_address 0x00007fffffe00000 +#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) +#define commpage64_version (commpage64_base_address+0x01E) +#define hasAVX512F 0x0000004000000000 + MOVQ $commpage64_version, BX + MOVW (BX), AX + CMPW AX, $13 // versions < 13 do not support AVX512 + JL no_avx512 + MOVQ $commpage64_cpu_capabilities64, BX + MOVQ (BX), AX + MOVQ $hasAVX512F, CX + ANDQ CX, AX + JZ no_avx512 + MOVB $1, ret+0(FP) + +no_avx512: +#endif +#endif + RET + diff --git a/vendor/github.com/klauspost/cpuid/v2/cpuid_arm64.s b/vendor/github.com/klauspost/cpuid/v2/cpuid_arm64.s new file mode 100644 index 0000000..b31d6ae --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/cpuid_arm64.s @@ -0,0 +1,26 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//+build arm64,!gccgo,!noasm,!appengine + +// See https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt + +// func getMidr +TEXT ·getMidr(SB), 7, $0 + WORD $0xd5380000 // mrs x0, midr_el1 /* Main ID Register */ + MOVD R0, midr+0(FP) + RET + +// func getProcFeatures +TEXT ·getProcFeatures(SB), 7, $0 + WORD $0xd5380400 // mrs x0, id_aa64pfr0_el1 /* Processor Feature Register 0 */ + MOVD R0, procFeatures+0(FP) + RET + +// func getInstAttributes +TEXT ·getInstAttributes(SB), 7, $0 + WORD $0xd5380600 // mrs x0, id_aa64isar0_el1 /* Instruction Set Attribute Register 0 */ + WORD $0xd5380621 // mrs x1, id_aa64isar1_el1 /* Instruction Set Attribute Register 1 */ + MOVD R0, instAttrReg0+0(FP) + MOVD R1, instAttrReg1+8(FP) + RET + diff --git a/vendor/github.com/klauspost/cpuid/v2/detect_arm64.go b/vendor/github.com/klauspost/cpuid/v2/detect_arm64.go new file mode 100644 index 0000000..9a53504 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/detect_arm64.go @@ -0,0 +1,247 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//go:build arm64 && !gccgo && !noasm && !appengine +// +build arm64,!gccgo,!noasm,!appengine + +package cpuid + +import "runtime" + +func getMidr() (midr uint64) +func getProcFeatures() (procFeatures uint64) +func getInstAttributes() (instAttrReg0, instAttrReg1 uint64) + +func initCPU() { + cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 } + cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 } + xgetbv = func(uint32) (a, b uint32) { return 0, 0 } + rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 } +} + +func addInfo(c *CPUInfo, safe bool) { + // Seems to be safe to assume on ARM64 + c.CacheLine = 64 + detectOS(c) + + // ARM64 disabled since it may crash if interrupt is not intercepted by OS. + if safe && !c.Supports(ARMCPUID) && runtime.GOOS != "freebsd" { + return + } + midr := getMidr() + + // MIDR_EL1 - Main ID Register + // https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/midr_el1 + // x--------------------------------------------------x + // | Name | bits | visible | + // |--------------------------------------------------| + // | Implementer | [31-24] | y | + // |--------------------------------------------------| + // | Variant | [23-20] | y | + // |--------------------------------------------------| + // | Architecture | [19-16] | y | + // |--------------------------------------------------| + // | PartNum | [15-4] | y | + // |--------------------------------------------------| + // | Revision | [3-0] | y | + // x--------------------------------------------------x + + switch (midr >> 24) & 0xff { + case 0xC0: + c.VendorString = "Ampere Computing" + c.VendorID = Ampere + case 0x41: + c.VendorString = "Arm Limited" + c.VendorID = ARM + case 0x42: + c.VendorString = "Broadcom Corporation" + c.VendorID = Broadcom + case 0x43: + c.VendorString = "Cavium Inc" + c.VendorID = Cavium + case 0x44: + c.VendorString = "Digital Equipment Corporation" + c.VendorID = DEC + case 0x46: + c.VendorString = "Fujitsu Ltd" + c.VendorID = Fujitsu + case 0x49: + c.VendorString = "Infineon Technologies AG" + c.VendorID = Infineon + case 0x4D: + c.VendorString = "Motorola or Freescale Semiconductor Inc" + c.VendorID = Motorola + case 0x4E: + c.VendorString = "NVIDIA Corporation" + c.VendorID = NVIDIA + case 0x50: + c.VendorString = "Applied Micro Circuits Corporation" + c.VendorID = AMCC + case 0x51: + c.VendorString = "Qualcomm Inc" + c.VendorID = Qualcomm + case 0x56: + c.VendorString = "Marvell International Ltd" + c.VendorID = Marvell + case 0x69: + c.VendorString = "Intel Corporation" + c.VendorID = Intel + } + + // Lower 4 bits: Architecture + // Architecture Meaning + // 0b0001 Armv4. + // 0b0010 Armv4T. + // 0b0011 Armv5 (obsolete). + // 0b0100 Armv5T. + // 0b0101 Armv5TE. + // 0b0110 Armv5TEJ. + // 0b0111 Armv6. + // 0b1111 Architectural features are individually identified in the ID_* registers, see 'ID registers'. + // Upper 4 bit: Variant + // An IMPLEMENTATION DEFINED variant number. + // Typically, this field is used to distinguish between different product variants, or major revisions of a product. + c.Family = int(midr>>16) & 0xff + + // PartNum, bits [15:4] + // An IMPLEMENTATION DEFINED primary part number for the device. + // On processors implemented by Arm, if the top four bits of the primary + // part number are 0x0 or 0x7, the variant and architecture are encoded differently. + // Revision, bits [3:0] + // An IMPLEMENTATION DEFINED revision number for the device. + c.Model = int(midr) & 0xffff + + procFeatures := getProcFeatures() + + // ID_AA64PFR0_EL1 - Processor Feature Register 0 + // x--------------------------------------------------x + // | Name | bits | visible | + // |--------------------------------------------------| + // | DIT | [51-48] | y | + // |--------------------------------------------------| + // | SVE | [35-32] | y | + // |--------------------------------------------------| + // | GIC | [27-24] | n | + // |--------------------------------------------------| + // | AdvSIMD | [23-20] | y | + // |--------------------------------------------------| + // | FP | [19-16] | y | + // |--------------------------------------------------| + // | EL3 | [15-12] | n | + // |--------------------------------------------------| + // | EL2 | [11-8] | n | + // |--------------------------------------------------| + // | EL1 | [7-4] | n | + // |--------------------------------------------------| + // | EL0 | [3-0] | n | + // x--------------------------------------------------x + + var f flagSet + // if procFeatures&(0xf<<48) != 0 { + // fmt.Println("DIT") + // } + f.setIf(procFeatures&(0xf<<32) != 0, SVE) + if procFeatures&(0xf<<20) != 15<<20 { + f.set(ASIMD) + // https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64pfr0_el1 + // 0b0001 --> As for 0b0000, and also includes support for half-precision floating-point arithmetic. + f.setIf(procFeatures&(0xf<<20) == 1<<20, FPHP, ASIMDHP) + } + f.setIf(procFeatures&(0xf<<16) != 0, FP) + + instAttrReg0, instAttrReg1 := getInstAttributes() + + // https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1 + // + // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 + // x--------------------------------------------------x + // | Name | bits | visible | + // |--------------------------------------------------| + // | TS | [55-52] | y | + // |--------------------------------------------------| + // | FHM | [51-48] | y | + // |--------------------------------------------------| + // | DP | [47-44] | y | + // |--------------------------------------------------| + // | SM4 | [43-40] | y | + // |--------------------------------------------------| + // | SM3 | [39-36] | y | + // |--------------------------------------------------| + // | SHA3 | [35-32] | y | + // |--------------------------------------------------| + // | RDM | [31-28] | y | + // |--------------------------------------------------| + // | ATOMICS | [23-20] | y | + // |--------------------------------------------------| + // | CRC32 | [19-16] | y | + // |--------------------------------------------------| + // | SHA2 | [15-12] | y | + // |--------------------------------------------------| + // | SHA1 | [11-8] | y | + // |--------------------------------------------------| + // | AES | [7-4] | y | + // x--------------------------------------------------x + + // if instAttrReg0&(0xf<<52) != 0 { + // fmt.Println("TS") + // } + // if instAttrReg0&(0xf<<48) != 0 { + // fmt.Println("FHM") + // } + f.setIf(instAttrReg0&(0xf<<44) != 0, ASIMDDP) + f.setIf(instAttrReg0&(0xf<<40) != 0, SM4) + f.setIf(instAttrReg0&(0xf<<36) != 0, SM3) + f.setIf(instAttrReg0&(0xf<<32) != 0, SHA3) + f.setIf(instAttrReg0&(0xf<<28) != 0, ASIMDRDM) + f.setIf(instAttrReg0&(0xf<<20) != 0, ATOMICS) + f.setIf(instAttrReg0&(0xf<<16) != 0, CRC32) + f.setIf(instAttrReg0&(0xf<<12) != 0, SHA2) + // https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1 + // 0b0010 --> As 0b0001, plus SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented. + f.setIf(instAttrReg0&(0xf<<12) == 2<<12, SHA512) + f.setIf(instAttrReg0&(0xf<<8) != 0, SHA1) + f.setIf(instAttrReg0&(0xf<<4) != 0, AESARM) + // https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1 + // 0b0010 --> As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit data quantities. + f.setIf(instAttrReg0&(0xf<<4) == 2<<4, PMULL) + + // https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar1_el1 + // + // ID_AA64ISAR1_EL1 - Instruction set attribute register 1 + // x--------------------------------------------------x + // | Name | bits | visible | + // |--------------------------------------------------| + // | GPI | [31-28] | y | + // |--------------------------------------------------| + // | GPA | [27-24] | y | + // |--------------------------------------------------| + // | LRCPC | [23-20] | y | + // |--------------------------------------------------| + // | FCMA | [19-16] | y | + // |--------------------------------------------------| + // | JSCVT | [15-12] | y | + // |--------------------------------------------------| + // | API | [11-8] | y | + // |--------------------------------------------------| + // | APA | [7-4] | y | + // |--------------------------------------------------| + // | DPB | [3-0] | y | + // x--------------------------------------------------x + + // if instAttrReg1&(0xf<<28) != 0 { + // fmt.Println("GPI") + // } + f.setIf(instAttrReg1&(0xf<<28) != 24, GPA) + f.setIf(instAttrReg1&(0xf<<20) != 0, LRCPC) + f.setIf(instAttrReg1&(0xf<<16) != 0, FCMA) + f.setIf(instAttrReg1&(0xf<<12) != 0, JSCVT) + // if instAttrReg1&(0xf<<8) != 0 { + // fmt.Println("API") + // } + // if instAttrReg1&(0xf<<4) != 0 { + // fmt.Println("APA") + // } + f.setIf(instAttrReg1&(0xf<<0) != 0, DCPOP) + + // Store + c.featureSet.or(f) +} diff --git a/vendor/github.com/klauspost/cpuid/v2/detect_ref.go b/vendor/github.com/klauspost/cpuid/v2/detect_ref.go new file mode 100644 index 0000000..9636c2b --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/detect_ref.go @@ -0,0 +1,15 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//go:build (!amd64 && !386 && !arm64) || gccgo || noasm || appengine +// +build !amd64,!386,!arm64 gccgo noasm appengine + +package cpuid + +func initCPU() { + cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 } + cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 } + xgetbv = func(uint32) (a, b uint32) { return 0, 0 } + rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 } +} + +func addInfo(info *CPUInfo, safe bool) {} diff --git a/vendor/github.com/klauspost/cpuid/v2/detect_x86.go b/vendor/github.com/klauspost/cpuid/v2/detect_x86.go new file mode 100644 index 0000000..c946824 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/detect_x86.go @@ -0,0 +1,36 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//go:build (386 && !gccgo && !noasm && !appengine) || (amd64 && !gccgo && !noasm && !appengine) +// +build 386,!gccgo,!noasm,!appengine amd64,!gccgo,!noasm,!appengine + +package cpuid + +func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +func asmXgetbv(index uint32) (eax, edx uint32) +func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +func asmDarwinHasAVX512() bool + +func initCPU() { + cpuid = asmCpuid + cpuidex = asmCpuidex + xgetbv = asmXgetbv + rdtscpAsm = asmRdtscpAsm + darwinHasAVX512 = asmDarwinHasAVX512 +} + +func addInfo(c *CPUInfo, safe bool) { + c.maxFunc = maxFunctionID() + c.maxExFunc = maxExtendedFunction() + c.BrandName = brandName() + c.CacheLine = cacheLine() + c.Family, c.Model, c.Stepping = familyModel() + c.featureSet = support() + c.SGX = hasSGX(c.featureSet.inSet(SGX), c.featureSet.inSet(SGXLC)) + c.ThreadsPerCore = threadsPerCore() + c.LogicalCores = logicalCores() + c.PhysicalCores = physicalCores() + c.VendorID, c.VendorString = vendorID() + c.cacheSize() + c.frequencies() +} diff --git a/vendor/github.com/klauspost/cpuid/v2/featureid_string.go b/vendor/github.com/klauspost/cpuid/v2/featureid_string.go new file mode 100644 index 0000000..2a27f44 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/featureid_string.go @@ -0,0 +1,271 @@ +// Code generated by "stringer -type=FeatureID,Vendor"; DO NOT EDIT. + +package cpuid + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[ADX-1] + _ = x[AESNI-2] + _ = x[AMD3DNOW-3] + _ = x[AMD3DNOWEXT-4] + _ = x[AMXBF16-5] + _ = x[AMXFP16-6] + _ = x[AMXINT8-7] + _ = x[AMXTILE-8] + _ = x[AVX-9] + _ = x[AVX2-10] + _ = x[AVX512BF16-11] + _ = x[AVX512BITALG-12] + _ = x[AVX512BW-13] + _ = x[AVX512CD-14] + _ = x[AVX512DQ-15] + _ = x[AVX512ER-16] + _ = x[AVX512F-17] + _ = x[AVX512FP16-18] + _ = x[AVX512IFMA-19] + _ = x[AVX512PF-20] + _ = x[AVX512VBMI-21] + _ = x[AVX512VBMI2-22] + _ = x[AVX512VL-23] + _ = x[AVX512VNNI-24] + _ = x[AVX512VP2INTERSECT-25] + _ = x[AVX512VPOPCNTDQ-26] + _ = x[AVXIFMA-27] + _ = x[AVXNECONVERT-28] + _ = x[AVXSLOW-29] + _ = x[AVXVNNI-30] + _ = x[AVXVNNIINT8-31] + _ = x[BHI_CTRL-32] + _ = x[BMI1-33] + _ = x[BMI2-34] + _ = x[CETIBT-35] + _ = x[CETSS-36] + _ = x[CLDEMOTE-37] + _ = x[CLMUL-38] + _ = x[CLZERO-39] + _ = x[CMOV-40] + _ = x[CMPCCXADD-41] + _ = x[CMPSB_SCADBS_SHORT-42] + _ = x[CMPXCHG8-43] + _ = x[CPBOOST-44] + _ = x[CPPC-45] + _ = x[CX16-46] + _ = x[EFER_LMSLE_UNS-47] + _ = x[ENQCMD-48] + _ = x[ERMS-49] + _ = x[F16C-50] + _ = x[FLUSH_L1D-51] + _ = x[FMA3-52] + _ = x[FMA4-53] + _ = x[FP128-54] + _ = x[FP256-55] + _ = x[FSRM-56] + _ = x[FXSR-57] + _ = x[FXSROPT-58] + _ = x[GFNI-59] + _ = x[HLE-60] + _ = x[HRESET-61] + _ = x[HTT-62] + _ = x[HWA-63] + _ = x[HYBRID_CPU-64] + _ = x[HYPERVISOR-65] + _ = x[IA32_ARCH_CAP-66] + _ = x[IA32_CORE_CAP-67] + _ = x[IBPB-68] + _ = x[IBRS-69] + _ = x[IBRS_PREFERRED-70] + _ = x[IBRS_PROVIDES_SMP-71] + _ = x[IBS-72] + _ = x[IBSBRNTRGT-73] + _ = x[IBSFETCHSAM-74] + _ = x[IBSFFV-75] + _ = x[IBSOPCNT-76] + _ = x[IBSOPCNTEXT-77] + _ = x[IBSOPSAM-78] + _ = x[IBSRDWROPCNT-79] + _ = x[IBSRIPINVALIDCHK-80] + _ = x[IBS_FETCH_CTLX-81] + _ = x[IBS_OPDATA4-82] + _ = x[IBS_OPFUSE-83] + _ = x[IBS_PREVENTHOST-84] + _ = x[IBS_ZEN4-85] + _ = x[IDPRED_CTRL-86] + _ = x[INT_WBINVD-87] + _ = x[INVLPGB-88] + _ = x[LAHF-89] + _ = x[LAM-90] + _ = x[LBRVIRT-91] + _ = x[LZCNT-92] + _ = x[MCAOVERFLOW-93] + _ = x[MCDT_NO-94] + _ = x[MCOMMIT-95] + _ = x[MD_CLEAR-96] + _ = x[MMX-97] + _ = x[MMXEXT-98] + _ = x[MOVBE-99] + _ = x[MOVDIR64B-100] + _ = x[MOVDIRI-101] + _ = x[MOVSB_ZL-102] + _ = x[MOVU-103] + _ = x[MPX-104] + _ = x[MSRIRC-105] + _ = x[MSRLIST-106] + _ = x[MSR_PAGEFLUSH-107] + _ = x[NRIPS-108] + _ = x[NX-109] + _ = x[OSXSAVE-110] + _ = x[PCONFIG-111] + _ = x[POPCNT-112] + _ = x[PPIN-113] + _ = x[PREFETCHI-114] + _ = x[PSFD-115] + _ = x[RDPRU-116] + _ = x[RDRAND-117] + _ = x[RDSEED-118] + _ = x[RDTSCP-119] + _ = x[RRSBA_CTRL-120] + _ = x[RTM-121] + _ = x[RTM_ALWAYS_ABORT-122] + _ = x[SERIALIZE-123] + _ = x[SEV-124] + _ = x[SEV_64BIT-125] + _ = x[SEV_ALTERNATIVE-126] + _ = x[SEV_DEBUGSWAP-127] + _ = x[SEV_ES-128] + _ = x[SEV_RESTRICTED-129] + _ = x[SEV_SNP-130] + _ = x[SGX-131] + _ = x[SGXLC-132] + _ = x[SHA-133] + _ = x[SME-134] + _ = x[SME_COHERENT-135] + _ = x[SPEC_CTRL_SSBD-136] + _ = x[SRBDS_CTRL-137] + _ = x[SSE-138] + _ = x[SSE2-139] + _ = x[SSE3-140] + _ = x[SSE4-141] + _ = x[SSE42-142] + _ = x[SSE4A-143] + _ = x[SSSE3-144] + _ = x[STIBP-145] + _ = x[STIBP_ALWAYSON-146] + _ = x[STOSB_SHORT-147] + _ = x[SUCCOR-148] + _ = x[SVM-149] + _ = x[SVMDA-150] + _ = x[SVMFBASID-151] + _ = x[SVML-152] + _ = x[SVMNP-153] + _ = x[SVMPF-154] + _ = x[SVMPFT-155] + _ = x[SYSCALL-156] + _ = x[SYSEE-157] + _ = x[TBM-158] + _ = x[TLB_FLUSH_NESTED-159] + _ = x[TME-160] + _ = x[TOPEXT-161] + _ = x[TSCRATEMSR-162] + _ = x[TSXLDTRK-163] + _ = x[VAES-164] + _ = x[VMCBCLEAN-165] + _ = x[VMPL-166] + _ = x[VMSA_REGPROT-167] + _ = x[VMX-168] + _ = x[VPCLMULQDQ-169] + _ = x[VTE-170] + _ = x[WAITPKG-171] + _ = x[WBNOINVD-172] + _ = x[WRMSRNS-173] + _ = x[X87-174] + _ = x[XGETBV1-175] + _ = x[XOP-176] + _ = x[XSAVE-177] + _ = x[XSAVEC-178] + _ = x[XSAVEOPT-179] + _ = x[XSAVES-180] + _ = x[AESARM-181] + _ = x[ARMCPUID-182] + _ = x[ASIMD-183] + _ = x[ASIMDDP-184] + _ = x[ASIMDHP-185] + _ = x[ASIMDRDM-186] + _ = x[ATOMICS-187] + _ = x[CRC32-188] + _ = x[DCPOP-189] + _ = x[EVTSTRM-190] + _ = x[FCMA-191] + _ = x[FP-192] + _ = x[FPHP-193] + _ = x[GPA-194] + _ = x[JSCVT-195] + _ = x[LRCPC-196] + _ = x[PMULL-197] + _ = x[SHA1-198] + _ = x[SHA2-199] + _ = x[SHA3-200] + _ = x[SHA512-201] + _ = x[SM3-202] + _ = x[SM4-203] + _ = x[SVE-204] + _ = x[lastID-205] + _ = x[firstID-0] +} + +const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXFP16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXIFMAAVXNECONVERTAVXSLOWAVXVNNIAVXVNNIINT8BHI_CTRLBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPCCXADDCMPSB_SCADBS_SHORTCMPXCHG8CPBOOSTCPPCCX16EFER_LMSLE_UNSENQCMDERMSF16CFLUSH_L1DFMA3FMA4FP128FP256FSRMFXSRFXSROPTGFNIHLEHRESETHTTHWAHYBRID_CPUHYPERVISORIA32_ARCH_CAPIA32_CORE_CAPIBPBIBRSIBRS_PREFERREDIBRS_PROVIDES_SMPIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKIBS_FETCH_CTLXIBS_OPDATA4IBS_OPFUSEIBS_PREVENTHOSTIBS_ZEN4IDPRED_CTRLINT_WBINVDINVLPGBLAHFLAMLBRVIRTLZCNTMCAOVERFLOWMCDT_NOMCOMMITMD_CLEARMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMOVSB_ZLMOVUMPXMSRIRCMSRLISTMSR_PAGEFLUSHNRIPSNXOSXSAVEPCONFIGPOPCNTPPINPREFETCHIPSFDRDPRURDRANDRDSEEDRDTSCPRRSBA_CTRLRTMRTM_ALWAYS_ABORTSERIALIZESEVSEV_64BITSEV_ALTERNATIVESEV_DEBUGSWAPSEV_ESSEV_RESTRICTEDSEV_SNPSGXSGXLCSHASMESME_COHERENTSPEC_CTRL_SSBDSRBDS_CTRLSSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSTIBP_ALWAYSONSTOSB_SHORTSUCCORSVMSVMDASVMFBASIDSVMLSVMNPSVMPFSVMPFTSYSCALLSYSEETBMTLB_FLUSH_NESTEDTMETOPEXTTSCRATEMSRTSXLDTRKVAESVMCBCLEANVMPLVMSA_REGPROTVMXVPCLMULQDQVTEWAITPKGWBNOINVDWRMSRNSX87XGETBV1XOPXSAVEXSAVECXSAVEOPTXSAVESAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID" + +var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 62, 65, 69, 79, 91, 99, 107, 115, 123, 130, 140, 150, 158, 168, 179, 187, 197, 215, 230, 237, 249, 256, 263, 274, 282, 286, 290, 296, 301, 309, 314, 320, 324, 333, 351, 359, 366, 370, 374, 388, 394, 398, 402, 411, 415, 419, 424, 429, 433, 437, 444, 448, 451, 457, 460, 463, 473, 483, 496, 509, 513, 517, 531, 548, 551, 561, 572, 578, 586, 597, 605, 617, 633, 647, 658, 668, 683, 691, 702, 712, 719, 723, 726, 733, 738, 749, 756, 763, 771, 774, 780, 785, 794, 801, 809, 813, 816, 822, 829, 842, 847, 849, 856, 863, 869, 873, 882, 886, 891, 897, 903, 909, 919, 922, 938, 947, 950, 959, 974, 987, 993, 1007, 1014, 1017, 1022, 1025, 1028, 1040, 1054, 1064, 1067, 1071, 1075, 1079, 1084, 1089, 1094, 1099, 1113, 1124, 1130, 1133, 1138, 1147, 1151, 1156, 1161, 1167, 1174, 1179, 1182, 1198, 1201, 1207, 1217, 1225, 1229, 1238, 1242, 1254, 1257, 1267, 1270, 1277, 1285, 1292, 1295, 1302, 1305, 1310, 1316, 1324, 1330, 1336, 1344, 1349, 1356, 1363, 1371, 1378, 1383, 1388, 1395, 1399, 1401, 1405, 1408, 1413, 1418, 1423, 1427, 1431, 1435, 1441, 1444, 1447, 1450, 1456} + +func (i FeatureID) String() string { + if i < 0 || i >= FeatureID(len(_FeatureID_index)-1) { + return "FeatureID(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _FeatureID_name[_FeatureID_index[i]:_FeatureID_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[VendorUnknown-0] + _ = x[Intel-1] + _ = x[AMD-2] + _ = x[VIA-3] + _ = x[Transmeta-4] + _ = x[NSC-5] + _ = x[KVM-6] + _ = x[MSVM-7] + _ = x[VMware-8] + _ = x[XenHVM-9] + _ = x[Bhyve-10] + _ = x[Hygon-11] + _ = x[SiS-12] + _ = x[RDC-13] + _ = x[Ampere-14] + _ = x[ARM-15] + _ = x[Broadcom-16] + _ = x[Cavium-17] + _ = x[DEC-18] + _ = x[Fujitsu-19] + _ = x[Infineon-20] + _ = x[Motorola-21] + _ = x[NVIDIA-22] + _ = x[AMCC-23] + _ = x[Qualcomm-24] + _ = x[Marvell-25] + _ = x[lastVendor-26] +} + +const _Vendor_name = "VendorUnknownIntelAMDVIATransmetaNSCKVMMSVMVMwareXenHVMBhyveHygonSiSRDCAmpereARMBroadcomCaviumDECFujitsuInfineonMotorolaNVIDIAAMCCQualcommMarvelllastVendor" + +var _Vendor_index = [...]uint8{0, 13, 18, 21, 24, 33, 36, 39, 43, 49, 55, 60, 65, 68, 71, 77, 80, 88, 94, 97, 104, 112, 120, 126, 130, 138, 145, 155} + +func (i Vendor) String() string { + if i < 0 || i >= Vendor(len(_Vendor_index)-1) { + return "Vendor(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Vendor_name[_Vendor_index[i]:_Vendor_index[i+1]] +} diff --git a/vendor/github.com/klauspost/cpuid/v2/os_darwin_arm64.go b/vendor/github.com/klauspost/cpuid/v2/os_darwin_arm64.go new file mode 100644 index 0000000..84b1acd --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/os_darwin_arm64.go @@ -0,0 +1,121 @@ +// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file. + +package cpuid + +import ( + "runtime" + "strings" + + "golang.org/x/sys/unix" +) + +func detectOS(c *CPUInfo) bool { + if runtime.GOOS != "ios" { + tryToFillCPUInfoFomSysctl(c) + } + // There are no hw.optional sysctl values for the below features on Mac OS 11.0 + // to detect their supported state dynamically. Assume the CPU features that + // Apple Silicon M1 supports to be available as a minimal set of features + // to all Go programs running on darwin/arm64. + // TODO: Add more if we know them. + c.featureSet.setIf(runtime.GOOS != "ios", AESARM, PMULL, SHA1, SHA2) + + return true +} + +func sysctlGetBool(name string) bool { + value, err := unix.SysctlUint32(name) + if err != nil { + return false + } + return value != 0 +} + +func sysctlGetString(name string) string { + value, err := unix.Sysctl(name) + if err != nil { + return "" + } + return value +} + +func sysctlGetInt(unknown int, names ...string) int { + for _, name := range names { + value, err := unix.SysctlUint32(name) + if err != nil { + continue + } + if value != 0 { + return int(value) + } + } + return unknown +} + +func sysctlGetInt64(unknown int, names ...string) int { + for _, name := range names { + value64, err := unix.SysctlUint64(name) + if err != nil { + continue + } + if int(value64) != unknown { + return int(value64) + } + } + return unknown +} + +func setFeature(c *CPUInfo, name string, feature FeatureID) { + c.featureSet.setIf(sysctlGetBool(name), feature) +} +func tryToFillCPUInfoFomSysctl(c *CPUInfo) { + c.BrandName = sysctlGetString("machdep.cpu.brand_string") + + if len(c.BrandName) != 0 { + c.VendorString = strings.Fields(c.BrandName)[0] + } + + c.PhysicalCores = sysctlGetInt(runtime.NumCPU(), "hw.physicalcpu") + c.ThreadsPerCore = sysctlGetInt(1, "machdep.cpu.thread_count", "kern.num_threads") / + sysctlGetInt(1, "hw.physicalcpu") + c.LogicalCores = sysctlGetInt(runtime.NumCPU(), "machdep.cpu.core_count") + c.Family = sysctlGetInt(0, "machdep.cpu.family", "hw.cpufamily") + c.Model = sysctlGetInt(0, "machdep.cpu.model") + c.CacheLine = sysctlGetInt64(0, "hw.cachelinesize") + c.Cache.L1I = sysctlGetInt64(-1, "hw.l1icachesize") + c.Cache.L1D = sysctlGetInt64(-1, "hw.l1dcachesize") + c.Cache.L2 = sysctlGetInt64(-1, "hw.l2cachesize") + c.Cache.L3 = sysctlGetInt64(-1, "hw.l3cachesize") + + // from https://developer.arm.com/downloads/-/exploration-tools/feature-names-for-a-profile + setFeature(c, "hw.optional.arm.FEAT_AES", AESARM) + setFeature(c, "hw.optional.AdvSIMD", ASIMD) + setFeature(c, "hw.optional.arm.FEAT_DotProd", ASIMDDP) + setFeature(c, "hw.optional.arm.FEAT_RDM", ASIMDRDM) + setFeature(c, "hw.optional.FEAT_CRC32", CRC32) + setFeature(c, "hw.optional.arm.FEAT_DPB", DCPOP) + // setFeature(c, "", EVTSTRM) + setFeature(c, "hw.optional.arm.FEAT_FCMA", FCMA) + setFeature(c, "hw.optional.arm.FEAT_FP", FP) + setFeature(c, "hw.optional.arm.FEAT_FP16", FPHP) + setFeature(c, "hw.optional.arm.FEAT_PAuth", GPA) + setFeature(c, "hw.optional.arm.FEAT_JSCVT", JSCVT) + setFeature(c, "hw.optional.arm.FEAT_LRCPC", LRCPC) + setFeature(c, "hw.optional.arm.FEAT_PMULL", PMULL) + setFeature(c, "hw.optional.arm.FEAT_SHA1", SHA1) + setFeature(c, "hw.optional.arm.FEAT_SHA256", SHA2) + setFeature(c, "hw.optional.arm.FEAT_SHA3", SHA3) + setFeature(c, "hw.optional.arm.FEAT_SHA512", SHA512) + // setFeature(c, "", SM3) + // setFeature(c, "", SM4) + setFeature(c, "hw.optional.arm.FEAT_SVE", SVE) + + // from empirical observation + setFeature(c, "hw.optional.AdvSIMD_HPFPCvt", ASIMDHP) + setFeature(c, "hw.optional.armv8_1_atomics", ATOMICS) + setFeature(c, "hw.optional.floatingpoint", FP) + setFeature(c, "hw.optional.armv8_2_sha3", SHA3) + setFeature(c, "hw.optional.armv8_2_sha512", SHA512) + setFeature(c, "hw.optional.armv8_3_compnum", FCMA) + setFeature(c, "hw.optional.armv8_crc32", CRC32) +} diff --git a/vendor/github.com/klauspost/cpuid/v2/os_linux_arm64.go b/vendor/github.com/klauspost/cpuid/v2/os_linux_arm64.go new file mode 100644 index 0000000..ee278b9 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/os_linux_arm64.go @@ -0,0 +1,130 @@ +// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file. + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file located +// here https://github.com/golang/sys/blob/master/LICENSE + +package cpuid + +import ( + "encoding/binary" + "io/ioutil" + "runtime" +) + +// HWCAP bits. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +func detectOS(c *CPUInfo) bool { + // For now assuming no hyperthreading is reasonable. + c.LogicalCores = runtime.NumCPU() + c.PhysicalCores = c.LogicalCores + c.ThreadsPerCore = 1 + if hwcap == 0 { + // We did not get values from the runtime. + // Try reading /proc/self/auxv + + // From https://github.com/golang/sys + const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + uintSize = int(32 << (^uint(0) >> 63)) + ) + + buf, err := ioutil.ReadFile("/proc/self/auxv") + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false. On some + // architectures (e.g. arm64) doinit() implements a fallback + // readout and will set Initialized = true again. + return false + } + bo := binary.LittleEndian + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwcap = val + case _AT_HWCAP2: + // Not used + } + } + if hwcap == 0 { + return false + } + } + + // HWCap was populated by the runtime from the auxiliary vector. + // Use HWCap information since reading aarch64 system registers + // is not supported in user space on older linux kernels. + c.featureSet.setIf(isSet(hwcap, hwcap_AES), AESARM) + c.featureSet.setIf(isSet(hwcap, hwcap_ASIMD), ASIMD) + c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDDP), ASIMDDP) + c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDHP), ASIMDHP) + c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDRDM), ASIMDRDM) + c.featureSet.setIf(isSet(hwcap, hwcap_CPUID), ARMCPUID) + c.featureSet.setIf(isSet(hwcap, hwcap_CRC32), CRC32) + c.featureSet.setIf(isSet(hwcap, hwcap_DCPOP), DCPOP) + c.featureSet.setIf(isSet(hwcap, hwcap_EVTSTRM), EVTSTRM) + c.featureSet.setIf(isSet(hwcap, hwcap_FCMA), FCMA) + c.featureSet.setIf(isSet(hwcap, hwcap_FP), FP) + c.featureSet.setIf(isSet(hwcap, hwcap_FPHP), FPHP) + c.featureSet.setIf(isSet(hwcap, hwcap_JSCVT), JSCVT) + c.featureSet.setIf(isSet(hwcap, hwcap_LRCPC), LRCPC) + c.featureSet.setIf(isSet(hwcap, hwcap_PMULL), PMULL) + c.featureSet.setIf(isSet(hwcap, hwcap_SHA1), SHA1) + c.featureSet.setIf(isSet(hwcap, hwcap_SHA2), SHA2) + c.featureSet.setIf(isSet(hwcap, hwcap_SHA3), SHA3) + c.featureSet.setIf(isSet(hwcap, hwcap_SHA512), SHA512) + c.featureSet.setIf(isSet(hwcap, hwcap_SM3), SM3) + c.featureSet.setIf(isSet(hwcap, hwcap_SM4), SM4) + c.featureSet.setIf(isSet(hwcap, hwcap_SVE), SVE) + + // The Samsung S9+ kernel reports support for atomics, but not all cores + // actually support them, resulting in SIGILL. See issue #28431. + // TODO(elias.naur): Only disable the optimization on bad chipsets on android. + c.featureSet.setIf(isSet(hwcap, hwcap_ATOMICS) && runtime.GOOS != "android", ATOMICS) + + return true +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/github.com/klauspost/cpuid/v2/os_other_arm64.go b/vendor/github.com/klauspost/cpuid/v2/os_other_arm64.go new file mode 100644 index 0000000..8733ba3 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/os_other_arm64.go @@ -0,0 +1,16 @@ +// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file. + +//go:build arm64 && !linux && !darwin +// +build arm64,!linux,!darwin + +package cpuid + +import "runtime" + +func detectOS(c *CPUInfo) bool { + c.PhysicalCores = runtime.NumCPU() + // For now assuming 1 thread per core... + c.ThreadsPerCore = 1 + c.LogicalCores = c.PhysicalCores + return false +} diff --git a/vendor/github.com/klauspost/cpuid/v2/os_safe_linux_arm64.go b/vendor/github.com/klauspost/cpuid/v2/os_safe_linux_arm64.go new file mode 100644 index 0000000..f8f201b --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/os_safe_linux_arm64.go @@ -0,0 +1,8 @@ +// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file. + +//go:build nounsafe +// +build nounsafe + +package cpuid + +var hwcap uint diff --git a/vendor/github.com/klauspost/cpuid/v2/os_unsafe_linux_arm64.go b/vendor/github.com/klauspost/cpuid/v2/os_unsafe_linux_arm64.go new file mode 100644 index 0000000..92af622 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/os_unsafe_linux_arm64.go @@ -0,0 +1,11 @@ +// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file. + +//go:build !nounsafe +// +build !nounsafe + +package cpuid + +import _ "unsafe" // needed for go:linkname + +//go:linkname hwcap internal/cpu.HWCap +var hwcap uint diff --git a/vendor/github.com/klauspost/cpuid/v2/test-architectures.sh b/vendor/github.com/klauspost/cpuid/v2/test-architectures.sh new file mode 100644 index 0000000..471d986 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/v2/test-architectures.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +go tool dist list | while IFS=/ read os arch; do + echo "Checking $os/$arch..." + echo " normal" + GOARCH=$arch GOOS=$os go build -o /dev/null . + echo " noasm" + GOARCH=$arch GOOS=$os go build -tags noasm -o /dev/null . + echo " appengine" + GOARCH=$arch GOOS=$os go build -tags appengine -o /dev/null . + echo " noasm,appengine" + GOARCH=$arch GOOS=$os go build -tags 'appengine noasm' -o /dev/null . +done diff --git a/vendor/github.com/leodido/go-urn/.gitignore b/vendor/github.com/leodido/go-urn/.gitignore index 5bcf4ba..89d4bc5 100644 --- a/vendor/github.com/leodido/go-urn/.gitignore +++ b/vendor/github.com/leodido/go-urn/.gitignore @@ -8,4 +8,5 @@ *.out *.txt -vendor/ \ No newline at end of file +vendor/ +/removecomments \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/.travis.yml b/vendor/github.com/leodido/go-urn/.travis.yml deleted file mode 100644 index 21f348d..0000000 --- a/vendor/github.com/leodido/go-urn/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go - -go: - - 1.13.x - - 1.14.x - - 1.15.x - - tip - -before_install: - - go get -t -v ./... - -script: - - go test -race -coverprofile=coverage.txt -covermode=atomic - -after_success: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/README.md b/vendor/github.com/leodido/go-urn/README.md index cc902ec..731eecb 100644 --- a/vendor/github.com/leodido/go-urn/README.md +++ b/vendor/github.com/leodido/go-urn/README.md @@ -1,4 +1,4 @@ -[![Build](https://img.shields.io/travis/leodido/go-urn/master.svg?style=for-the-badge)](https://travis-ci.org/leodido/go-urn) [![Coverage](https://img.shields.io/codecov/c/github/leodido/go-urn.svg?style=for-the-badge)](https://codecov.io/gh/leodido/go-urn) [![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://godoc.org/github.com/leodido/go-urn) +[![Build](https://img.shields.io/circleci/build/github/leodido/go-urn?style=for-the-badge)](https://app.circleci.com/pipelines/github/leodido/go-urn) [![Coverage](https://img.shields.io/codecov/c/github/leodido/go-urn.svg?style=for-the-badge)](https://codecov.io/gh/leodido/go-urn) [![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://godoc.org/github.com/leodido/go-urn) **A parser for URNs**. @@ -52,4 +52,30 @@ no/19/urn:UrN:NSS__________________________________/-4 20000000 399 ns --- +## Example +```go +package main + +import ( + "fmt" + "github.com/leodido/go-urn" +) + +func main() { + var uid = "URN:foo:a123,456" + + u, ok := urn.Parse([]byte(uid)) + if !ok { + panic("error parsing urn") + } + + fmt.Println(u.ID) + fmt.Println(u.SS) + + // Output: + // foo + // a123,456 +} +``` + [![Analytics](https://ga-beacon.appspot.com/UA-49657176-1/go-urn?flat)](https://github.com/igrigorik/ga-beacon) \ No newline at end of file diff --git a/vendor/github.com/leodido/go-urn/machine.go b/vendor/github.com/leodido/go-urn/machine.go index fe5a0cc..f8d57b4 100644 --- a/vendor/github.com/leodido/go-urn/machine.go +++ b/vendor/github.com/leodido/go-urn/machine.go @@ -61,11 +61,9 @@ func (m *machine) Parse(input []byte) (*URN, error) { m.err = nil m.tolower = []int{} output := &URN{} - { m.cs = start } - { if (m.p) == (m.pe) { goto _testEof @@ -1674,7 +1672,6 @@ func (m *machine) Parse(input []byte) (*URN, error) { { goto st46 } - } } diff --git a/vendor/github.com/leodido/go-urn/makefile b/vendor/github.com/leodido/go-urn/makefile index 47026d5..df87cdc 100644 --- a/vendor/github.com/leodido/go-urn/makefile +++ b/vendor/github.com/leodido/go-urn/makefile @@ -1,18 +1,37 @@ SHELL := /bin/bash +RAGEL := ragel +GOFMT := go fmt +export GO_TEST=env GOTRACEBACK=all go test $(GO_ARGS) + +.PHONY: build build: machine.go +.PHONY: clean +clean: + @rm -rf docs + @rm -f machine.go + +.PHONY: images images: docs/urn.png +.PHONY: removecomments +removecomments: + @cd ./tools/removecomments; go build -o ../../removecomments . + machine.go: machine.go.rl - ragel -Z -G2 -e -o $@ $< - @sed -i '/^\/\/line/d' $@ - @$(MAKE) -s file=$@ snake2camel - @gofmt -w -s $@ + +machine.go: removecomments + +machine.go: + $(RAGEL) -Z -G2 -e -o $@ $< + @./removecomments $@ + $(MAKE) -s file=$@ snake2camel + $(GOFMT) $@ docs/urn.dot: machine.go.rl @mkdir -p docs - ragel -Z -e -Vp $< -o $@ + $(RAGEL) -Z -e -Vp $< -o $@ docs/urn.png: docs/urn.dot dot $< -Tpng -o $@ @@ -22,13 +41,8 @@ bench: *_test.go machine.go go test -bench=. -benchmem -benchtime=5s ./... .PHONY: tests -tests: *_test.go machine.go - go test -race -timeout 10s -coverprofile=coverage.out -covermode=atomic -v ./... - -.PHONY: clean -clean: - @rm -rf docs - @rm -f machine.go +tests: *_test.go + $(GO_TEST) ./... .PHONY: snake2camel snake2camel: @@ -36,4 +50,4 @@ snake2camel: while ( match($$0, /(.*)([a-z]+[0-9]*)_([a-zA-Z0-9])(.*)/, cap) ) \ $$0 = cap[1] cap[2] toupper(cap[3]) cap[4]; \ print \ - }' $(file) \ No newline at end of file + }' $(file) diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 39bbcf0..d569c0c 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -1,5 +1,5 @@ -//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine -// +build darwin freebsd openbsd netbsd dragonfly +//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine +// +build darwin freebsd openbsd netbsd dragonfly hurd // +build !appengine package isatty diff --git a/vendor/github.com/modern-go/concurrent/.gitignore b/vendor/github.com/modern-go/concurrent/.gitignore new file mode 100644 index 0000000..3f2bc47 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/.gitignore @@ -0,0 +1 @@ +/coverage.txt diff --git a/vendor/github.com/modern-go/concurrent/.travis.yml b/vendor/github.com/modern-go/concurrent/.travis.yml new file mode 100644 index 0000000..449e67c --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.8.x + - 1.x + +before_install: + - go get -t -v ./... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/modern-go/concurrent/README.md b/vendor/github.com/modern-go/concurrent/README.md index 91d6adb..acab320 100644 --- a/vendor/github.com/modern-go/concurrent/README.md +++ b/vendor/github.com/modern-go/concurrent/README.md @@ -1,2 +1,49 @@ # concurrent -concurrency utilities + +[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/concurrent/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/concurrent?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/concurrent) +[![Build Status](https://travis-ci.org/modern-go/concurrent.svg?branch=master)](https://travis-ci.org/modern-go/concurrent) +[![codecov](https://codecov.io/gh/modern-go/concurrent/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/concurrent) +[![rcard](https://goreportcard.com/badge/github.com/modern-go/concurrent)](https://goreportcard.com/report/github.com/modern-go/concurrent) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/concurrent/master/LICENSE) + +* concurrent.Map: backport sync.Map for go below 1.9 +* concurrent.Executor: goroutine with explicit ownership and cancellable + +# concurrent.Map + +because sync.Map is only available in go 1.9, we can use concurrent.Map to make code portable + +```go +m := concurrent.NewMap() +m.Store("hello", "world") +elem, found := m.Load("hello") +// elem will be "world" +// found will be true +``` + +# concurrent.Executor + +```go +executor := concurrent.NewUnboundedExecutor() +executor.Go(func(ctx context.Context) { + everyMillisecond := time.NewTicker(time.Millisecond) + for { + select { + case <-ctx.Done(): + fmt.Println("goroutine exited") + return + case <-everyMillisecond.C: + // do something + } + } +}) +time.Sleep(time.Second) +executor.StopAndWaitForever() +fmt.Println("executor stopped") +``` + +attach goroutine to executor instance, so that we can + +* cancel it by stop the executor with Stop/StopAndWait/StopAndWaitForever +* handle panic by callback: the default behavior will no longer crash your application \ No newline at end of file diff --git a/vendor/github.com/modern-go/concurrent/executor.go b/vendor/github.com/modern-go/concurrent/executor.go index 56e5d22..623dba1 100644 --- a/vendor/github.com/modern-go/concurrent/executor.go +++ b/vendor/github.com/modern-go/concurrent/executor.go @@ -2,6 +2,13 @@ package concurrent import "context" +// Executor replace go keyword to start a new goroutine +// the goroutine should cancel itself if the context passed in has been cancelled +// the goroutine started by the executor, is owned by the executor +// we can cancel all executors owned by the executor just by stop the executor itself +// however Executor interface does not Stop method, the one starting and owning executor +// should use the concrete type of executor, instead of this interface. type Executor interface { + // Go starts a new goroutine controlled by the context Go(handler func(ctx context.Context)) -} \ No newline at end of file +} diff --git a/vendor/github.com/modern-go/concurrent/go_above_19.go b/vendor/github.com/modern-go/concurrent/go_above_19.go index a9f2593..aeabf8c 100644 --- a/vendor/github.com/modern-go/concurrent/go_above_19.go +++ b/vendor/github.com/modern-go/concurrent/go_above_19.go @@ -4,10 +4,12 @@ package concurrent import "sync" +// Map is a wrapper for sync.Map introduced in go1.9 type Map struct { sync.Map } +// NewMap creates a thread safe Map func NewMap() *Map { return &Map{} -} \ No newline at end of file +} diff --git a/vendor/github.com/modern-go/concurrent/go_below_19.go b/vendor/github.com/modern-go/concurrent/go_below_19.go index 3f79f4f..b9c8df7 100644 --- a/vendor/github.com/modern-go/concurrent/go_below_19.go +++ b/vendor/github.com/modern-go/concurrent/go_below_19.go @@ -4,17 +4,20 @@ package concurrent import "sync" +// Map implements a thread safe map for go version below 1.9 using mutex type Map struct { lock sync.RWMutex data map[interface{}]interface{} } +// NewMap creates a thread safe map func NewMap() *Map { return &Map{ data: make(map[interface{}]interface{}, 32), } } +// Load is same as sync.Map Load func (m *Map) Load(key interface{}) (elem interface{}, found bool) { m.lock.RLock() elem, found = m.data[key] @@ -22,9 +25,9 @@ func (m *Map) Load(key interface{}) (elem interface{}, found bool) { return } +// Load is same as sync.Map Store func (m *Map) Store(key interface{}, elem interface{}) { m.lock.Lock() m.data[key] = elem m.lock.Unlock() } - diff --git a/vendor/github.com/modern-go/concurrent/log.go b/vendor/github.com/modern-go/concurrent/log.go new file mode 100644 index 0000000..9756fcc --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/log.go @@ -0,0 +1,13 @@ +package concurrent + +import ( + "os" + "log" + "io/ioutil" +) + +// ErrorLogger is used to print out error, can be set to writer other than stderr +var ErrorLogger = log.New(os.Stderr, "", 0) + +// InfoLogger is used to print informational message, default to off +var InfoLogger = log.New(ioutil.Discard, "", 0) \ No newline at end of file diff --git a/vendor/github.com/modern-go/concurrent/test.sh b/vendor/github.com/modern-go/concurrent/test.sh new file mode 100644 index 0000000..d1e6b2e --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $(go list ./... | grep -v vendor); do + go test -coverprofile=profile.out -coverpkg=github.com/modern-go/concurrent $d + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done diff --git a/vendor/github.com/modern-go/concurrent/unbounded_executor.go b/vendor/github.com/modern-go/concurrent/unbounded_executor.go index 70a1cf0..05a77dc 100644 --- a/vendor/github.com/modern-go/concurrent/unbounded_executor.go +++ b/vendor/github.com/modern-go/concurrent/unbounded_executor.go @@ -4,33 +4,37 @@ import ( "context" "fmt" "runtime" + "runtime/debug" "sync" "time" - "runtime/debug" + "reflect" ) -var LogInfo = func(event string, properties ...interface{}) { -} - -var LogPanic = func(recovered interface{}, properties ...interface{}) interface{} { - fmt.Println(fmt.Sprintf("paniced: %v", recovered)) - debug.PrintStack() - return recovered +// HandlePanic logs goroutine panic by default +var HandlePanic = func(recovered interface{}, funcName string) { + ErrorLogger.Println(fmt.Sprintf("%s panic: %v", funcName, recovered)) + ErrorLogger.Println(string(debug.Stack())) } -const StopSignal = "STOP!" - +// UnboundedExecutor is a executor without limits on counts of alive goroutines +// it tracks the goroutine started by it, and can cancel them when shutdown type UnboundedExecutor struct { ctx context.Context cancel context.CancelFunc activeGoroutinesMutex *sync.Mutex activeGoroutines map[string]int + HandlePanic func(recovered interface{}, funcName string) } // GlobalUnboundedExecutor has the life cycle of the program itself // any goroutine want to be shutdown before main exit can be started from this executor +// GlobalUnboundedExecutor expects the main function to call stop +// it does not magically knows the main function exits var GlobalUnboundedExecutor = NewUnboundedExecutor() +// NewUnboundedExecutor creates a new UnboundedExecutor, +// UnboundedExecutor can not be created by &UnboundedExecutor{} +// HandlePanic can be set with a callback to override global HandlePanic func NewUnboundedExecutor() *UnboundedExecutor { ctx, cancel := context.WithCancel(context.TODO()) return &UnboundedExecutor{ @@ -41,8 +45,13 @@ func NewUnboundedExecutor() *UnboundedExecutor { } } +// Go starts a new goroutine and tracks its lifecycle. +// Panic will be recovered and logged automatically, except for StopSignal func (executor *UnboundedExecutor) Go(handler func(ctx context.Context)) { - _, file, line, _ := runtime.Caller(1) + pc := reflect.ValueOf(handler).Pointer() + f := runtime.FuncForPC(pc) + funcName := f.Name() + file, line := f.FileLine(pc) executor.activeGoroutinesMutex.Lock() defer executor.activeGoroutinesMutex.Unlock() startFrom := fmt.Sprintf("%s:%d", file, line) @@ -50,46 +59,57 @@ func (executor *UnboundedExecutor) Go(handler func(ctx context.Context)) { go func() { defer func() { recovered := recover() - if recovered != nil && recovered != StopSignal { - LogPanic(recovered) + // if you want to quit a goroutine without trigger HandlePanic + // use runtime.Goexit() to quit + if recovered != nil { + if executor.HandlePanic == nil { + HandlePanic(recovered, funcName) + } else { + executor.HandlePanic(recovered, funcName) + } } executor.activeGoroutinesMutex.Lock() - defer executor.activeGoroutinesMutex.Unlock() executor.activeGoroutines[startFrom] -= 1 + executor.activeGoroutinesMutex.Unlock() }() handler(executor.ctx) }() } +// Stop cancel all goroutines started by this executor without wait func (executor *UnboundedExecutor) Stop() { executor.cancel() } +// StopAndWaitForever cancel all goroutines started by this executor and +// wait until all goroutines exited func (executor *UnboundedExecutor) StopAndWaitForever() { executor.StopAndWait(context.Background()) } +// StopAndWait cancel all goroutines started by this executor and wait. +// Wait can be cancelled by the context passed in. func (executor *UnboundedExecutor) StopAndWait(ctx context.Context) { executor.cancel() for { - fiveSeconds := time.NewTimer(time.Millisecond * 100) + oneHundredMilliseconds := time.NewTimer(time.Millisecond * 100) select { - case <-fiveSeconds.C: + case <-oneHundredMilliseconds.C: + if executor.checkNoActiveGoroutines() { + return + } case <-ctx.Done(): return } - if executor.checkGoroutines() { - return - } } } -func (executor *UnboundedExecutor) checkGoroutines() bool { +func (executor *UnboundedExecutor) checkNoActiveGoroutines() bool { executor.activeGoroutinesMutex.Lock() defer executor.activeGoroutinesMutex.Unlock() for startFrom, count := range executor.activeGoroutines { if count > 0 { - LogInfo("event!unbounded_executor.still waiting goroutines to quit", + InfoLogger.Println("UnboundedExecutor is still waiting goroutines to quit", "startFrom", startFrom, "count", count) return false diff --git a/vendor/github.com/pelletier/go-toml/v2/README.md b/vendor/github.com/pelletier/go-toml/v2/README.md index 9f8439c..d53f439 100644 --- a/vendor/github.com/pelletier/go-toml/v2/README.md +++ b/vendor/github.com/pelletier/go-toml/v2/README.md @@ -553,7 +553,7 @@ complete solutions exist out there. ## Versioning -Go-toml follows [Semantic Versioning](http://semver.org/). The supported version +Go-toml follows [Semantic Versioning](https://semver.org). The supported version of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of this document. The last two major versions of Go are supported (see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)). diff --git a/vendor/github.com/pelletier/go-toml/v2/ci.sh b/vendor/github.com/pelletier/go-toml/v2/ci.sh index d916c5f..05c76f2 100644 --- a/vendor/github.com/pelletier/go-toml/v2/ci.sh +++ b/vendor/github.com/pelletier/go-toml/v2/ci.sh @@ -77,7 +77,7 @@ cover() { pushd "$dir" go test -covermode=atomic -coverpkg=./... -coverprofile=coverage.out.tmp ./... - cat coverage.out.tmp | grep -v testsuite | grep -v tomltestgen | grep -v gotoml-test-decoder > coverage.out + cat coverage.out.tmp | grep -v fuzz | grep -v testsuite | grep -v tomltestgen | grep -v gotoml-test-decoder > coverage.out go tool cover -func=coverage.out popd diff --git a/vendor/github.com/pelletier/go-toml/v2/marshaler.go b/vendor/github.com/pelletier/go-toml/v2/marshaler.go index 07aceb9..6ab1d82 100644 --- a/vendor/github.com/pelletier/go-toml/v2/marshaler.go +++ b/vendor/github.com/pelletier/go-toml/v2/marshaler.go @@ -357,9 +357,9 @@ func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v r if !ctx.inline { b = enc.encodeComment(ctx.indent, options.comment, b) + b = enc.indent(ctx.indent, b) } - b = enc.indent(ctx.indent, b) b = enc.encodeKey(b, ctx.key) b = append(b, " = "...) @@ -577,11 +577,23 @@ func (enc *Encoder) encodeKey(b []byte, k string) []byte { } } -func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) { - if v.Type().Key().Kind() != reflect.String { - return nil, fmt.Errorf("toml: type %s is not supported as a map key", v.Type().Key().Kind()) +func (enc *Encoder) keyToString(k reflect.Value) (string, error) { + keyType := k.Type() + switch { + case keyType.Kind() == reflect.String: + return k.String(), nil + + case keyType.Implements(textMarshalerType): + keyB, err := k.Interface().(encoding.TextMarshaler).MarshalText() + if err != nil { + return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err) + } + return string(keyB), nil } + return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind()) +} +func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) { var ( t table emptyValueOptions valueOptions @@ -589,13 +601,17 @@ func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte iter := v.MapRange() for iter.Next() { - k := iter.Key().String() v := iter.Value() if isNil(v) { continue } + k, err := enc.keyToString(iter.Key()) + if err != nil { + return nil, err + } + if willConvertToTableOrArrayTable(ctx, v) { t.pushTable(k, v, emptyValueOptions) } else { diff --git a/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go index 70f6ec5..3935034 100644 --- a/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go +++ b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go @@ -60,7 +60,7 @@ func (d *Decoder) DisallowUnknownFields() *Decoder { // are ignored. See Decoder.DisallowUnknownFields() to change this behavior. // // When a TOML local date, time, or date-time is decoded into a time.Time, its -// value is represented in time.Local timezone. Otherwise the approriate Local* +// value is represented in time.Local timezone. Otherwise the appropriate Local* // structure is used. For time values, precision up to the nanosecond is // supported by truncating extra digits. // @@ -417,7 +417,10 @@ func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn h vt := v.Type() // Create the key for the map element. Convert to key type. - mk := reflect.ValueOf(string(key.Node().Data)).Convert(vt.Key()) + mk, err := d.keyFromData(vt.Key(), key.Node().Data) + if err != nil { + return reflect.Value{}, err + } // If the map does not exist, create it. if v.IsNil() { @@ -746,7 +749,7 @@ func (d *decoder) unmarshalInlineTable(itable *unstable.Node, v reflect.Value) e } return d.unmarshalInlineTable(itable, elem) default: - return unstable.NewParserError(itable.Data, "cannot store inline table in Go type %s", v.Kind()) + return unstable.NewParserError(d.p.Raw(itable.Raw), "cannot store inline table in Go type %s", v.Kind()) } it := itable.Children() @@ -887,6 +890,11 @@ func init() { } func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error { + kind := v.Kind() + if kind == reflect.Float32 || kind == reflect.Float64 { + return d.unmarshalFloat(value, v) + } + i, err := parseInteger(value.Data) if err != nil { return err @@ -894,7 +902,7 @@ func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error var r reflect.Value - switch v.Kind() { + switch kind { case reflect.Int64: v.SetInt(i) return nil @@ -1004,6 +1012,31 @@ func (d *decoder) handleKeyValueInner(key unstable.Iterator, value *unstable.Nod return reflect.Value{}, d.handleValue(value, v) } +func (d *decoder) keyFromData(keyType reflect.Type, data []byte) (reflect.Value, error) { + switch { + case stringType.AssignableTo(keyType): + return reflect.ValueOf(string(data)), nil + + case stringType.ConvertibleTo(keyType): + return reflect.ValueOf(string(data)).Convert(keyType), nil + + case keyType.Implements(textUnmarshalerType): + mk := reflect.New(keyType.Elem()) + if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { + return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err) + } + return mk, nil + + case reflect.PtrTo(keyType).Implements(textUnmarshalerType): + mk := reflect.New(keyType) + if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { + return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err) + } + return mk.Elem(), nil + } + return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType) +} + func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) { // contains the replacement for v var rv reflect.Value @@ -1014,16 +1047,9 @@ func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node case reflect.Map: vt := v.Type() - mk := reflect.ValueOf(string(key.Node().Data)) - mkt := stringType - - keyType := vt.Key() - if !mkt.AssignableTo(keyType) { - if !mkt.ConvertibleTo(keyType) { - return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", mkt, keyType) - } - - mk = mk.Convert(keyType) + mk, err := d.keyFromData(vt.Key(), key.Node().Data) + if err != nil { + return reflect.Value{}, err } // If the map does not exist, create it. @@ -1034,15 +1060,9 @@ func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node mv := v.MapIndex(mk) set := false - if !mv.IsValid() { + if !mv.IsValid() || key.IsLast() { set = true mv = reflect.New(v.Type().Elem()).Elem() - } else { - if key.IsLast() { - var x interface{} - mv = reflect.ValueOf(&x).Elem() - set = true - } } nv, err := d.handleKeyValueInner(key, value, mv) @@ -1072,6 +1092,19 @@ func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node d.errorContext.Field = path f := fieldByIndex(v, path) + + if !f.CanSet() { + // If the field is not settable, need to take a slower path and make a copy of + // the struct itself to a new location. + nvp := reflect.New(v.Type()) + nvp.Elem().Set(v) + v = nvp.Elem() + _, err := d.handleKeyValuePart(key, value, v) + if err != nil { + return reflect.Value{}, err + } + return nvp.Elem(), nil + } x, err := d.handleKeyValueInner(key, value, f) if err != nil { return reflect.Value{}, err diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go index b60d9bf..f526bf2 100644 --- a/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go +++ b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go @@ -58,7 +58,7 @@ func (c *Iterator) Node() *Node { // - Table and ArrayTable's children represent a dotted key (same as // KeyValue, but without the first node being the value). // -// When relevant, Raw describes the range of bytes this node is refering to in +// When relevant, Raw describes the range of bytes this node is referring to in // the input document. Use Parser.Raw() to retrieve the actual bytes. type Node struct { Kind Kind diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go index 52db88e..a8eb052 100644 --- a/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go +++ b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go @@ -49,8 +49,6 @@ func NewParserError(highlight []byte, format string, args ...interface{}) error // For performance reasons, go-toml doesn't make a copy of the input bytes to // the parser. Make sure to copy all the bytes you need to outlive the slice // given to the parser. -// -// The parser doesn't provide nodes for comments yet, nor for whitespace. type Parser struct { data []byte builder builder @@ -58,6 +56,8 @@ type Parser struct { left []byte err error first bool + + KeepComments bool } // Data returns the slice provided to the last call to Reset. @@ -132,16 +132,54 @@ func (p *Parser) NextExpression() bool { } // Expression returns a pointer to the node representing the last successfully -// parsed expresion. +// parsed expression. func (p *Parser) Expression() *Node { return p.builder.NodeAt(p.ref) } -// Error returns any error that has occured during parsing. +// Error returns any error that has occurred during parsing. func (p *Parser) Error() error { return p.err } +// Position describes a position in the input. +type Position struct { + // Number of bytes from the beginning of the input. + Offset int + // Line number, starting at 1. + Line int + // Column number, starting at 1. + Column int +} + +// Shape describes the position of a range in the input. +type Shape struct { + Start Position + End Position +} + +func (p *Parser) position(b []byte) Position { + offset := danger.SubsliceOffset(p.data, b) + + lead := p.data[:offset] + + return Position{ + Offset: offset, + Line: bytes.Count(lead, []byte{'\n'}) + 1, + Column: len(lead) - bytes.LastIndex(lead, []byte{'\n'}), + } +} + +// Shape returns the shape of the given range in the input. Will +// panic if the range is not a subslice of the input. +func (p *Parser) Shape(r Range) Shape { + raw := p.Raw(r) + return Shape{ + Start: p.position(raw), + End: p.position(raw[r.Length:]), + } +} + func (p *Parser) parseNewline(b []byte) ([]byte, error) { if b[0] == '\n' { return b[1:], nil @@ -155,6 +193,19 @@ func (p *Parser) parseNewline(b []byte) ([]byte, error) { return nil, NewParserError(b[0:1], "expected newline but got %#U", b[0]) } +func (p *Parser) parseComment(b []byte) (reference, []byte, error) { + ref := invalidReference + data, rest, err := scanComment(b) + if p.KeepComments && err == nil { + ref = p.builder.Push(Node{ + Kind: Comment, + Raw: p.Range(data), + Data: data, + }) + } + return ref, rest, err +} + func (p *Parser) parseExpression(b []byte) (reference, []byte, error) { // expression = ws [ comment ] // expression =/ ws keyval ws [ comment ] @@ -168,7 +219,7 @@ func (p *Parser) parseExpression(b []byte) (reference, []byte, error) { } if b[0] == '#' { - _, rest, err := scanComment(b) + ref, rest, err := p.parseComment(b) return ref, rest, err } @@ -190,7 +241,10 @@ func (p *Parser) parseExpression(b []byte) (reference, []byte, error) { b = p.parseWhitespace(b) if len(b) > 0 && b[0] == '#' { - _, rest, err := scanComment(b) + cref, rest, err := p.parseComment(b) + if cref != invalidReference { + p.builder.Chain(ref, cref) + } return ref, rest, err } @@ -402,6 +456,7 @@ func (p *Parser) parseInlineTable(b []byte) (reference, []byte, error) { // inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ] parent := p.builder.Push(Node{ Kind: InlineTable, + Raw: p.Range(b[:1]), }) first := true @@ -470,17 +525,33 @@ func (p *Parser) parseValArray(b []byte) (reference, []byte, error) { Kind: Array, }) + // First indicates whether the parser is looking for the first element + // (non-comment) of the array. first := true - var lastChild reference + lastChild := invalidReference + + addChild := func(valueRef reference) { + if lastChild == invalidReference { + p.builder.AttachChild(parent, valueRef) + } else { + p.builder.Chain(lastChild, valueRef) + } + lastChild = valueRef + } var err error for len(b) > 0 { - b, err = p.parseOptionalWhitespaceCommentNewline(b) + cref := invalidReference + cref, b, err = p.parseOptionalWhitespaceCommentNewline(b) if err != nil { return parent, nil, err } + if cref != invalidReference { + addChild(cref) + } + if len(b) == 0 { return parent, nil, NewParserError(arrayStart[:1], "array is incomplete") } @@ -495,10 +566,13 @@ func (p *Parser) parseValArray(b []byte) (reference, []byte, error) { } b = b[1:] - b, err = p.parseOptionalWhitespaceCommentNewline(b) + cref, b, err = p.parseOptionalWhitespaceCommentNewline(b) if err != nil { return parent, nil, err } + if cref != invalidReference { + addChild(cref) + } } else if !first { return parent, nil, NewParserError(b[0:1], "array elements must be separated by commas") } @@ -514,17 +588,16 @@ func (p *Parser) parseValArray(b []byte) (reference, []byte, error) { return parent, nil, err } - if first { - p.builder.AttachChild(parent, valueRef) - } else { - p.builder.Chain(lastChild, valueRef) - } - lastChild = valueRef + addChild(valueRef) - b, err = p.parseOptionalWhitespaceCommentNewline(b) + cref, b, err = p.parseOptionalWhitespaceCommentNewline(b) if err != nil { return parent, nil, err } + if cref != invalidReference { + addChild(cref) + } + first = false } @@ -533,15 +606,34 @@ func (p *Parser) parseValArray(b []byte) (reference, []byte, error) { return parent, rest, err } -func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error) { +func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) (reference, []byte, error) { + rootCommentRef := invalidReference + latestCommentRef := invalidReference + + addComment := func(ref reference) { + if rootCommentRef == invalidReference { + rootCommentRef = ref + } else if latestCommentRef == invalidReference { + p.builder.AttachChild(rootCommentRef, ref) + latestCommentRef = ref + } else { + p.builder.Chain(latestCommentRef, ref) + latestCommentRef = ref + } + } + for len(b) > 0 { var err error b = p.parseWhitespace(b) if len(b) > 0 && b[0] == '#' { - _, b, err = scanComment(b) + var ref reference + ref, b, err = p.parseComment(b) if err != nil { - return nil, err + return invalidReference, nil, err + } + if ref != invalidReference { + addComment(ref) } } @@ -552,14 +644,14 @@ func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error) if b[0] == '\n' || b[0] == '\r' { b, err = p.parseNewline(b) if err != nil { - return nil, err + return invalidReference, nil, err } } else { break } } - return b, nil + return rootCommentRef, b, nil } func (p *Parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, []byte, error) { diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go index af22ebb..0512181 100644 --- a/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go +++ b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go @@ -151,7 +151,6 @@ func scanWhitespace(b []byte) ([]byte, []byte) { return b, b[len(b):] } -//nolint:unparam func scanComment(b []byte) ([]byte, []byte, error) { // comment-start-symbol = %x23 ; # // non-ascii = %x80-D7FF / %xE000-10FFFF diff --git a/vendor/github.com/twitchyliquid64/golang-asm/LICENSE b/vendor/github.com/twitchyliquid64/golang-asm/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arch.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arch.go new file mode 100644 index 0000000..b8ddbc9 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arch.go @@ -0,0 +1,716 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package arch defines architecture-specific information and support functions. +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/arm" + "github.com/twitchyliquid64/golang-asm/obj/arm64" + "github.com/twitchyliquid64/golang-asm/obj/mips" + "github.com/twitchyliquid64/golang-asm/obj/ppc64" + "github.com/twitchyliquid64/golang-asm/obj/riscv" + "github.com/twitchyliquid64/golang-asm/obj/s390x" + "github.com/twitchyliquid64/golang-asm/obj/wasm" + "github.com/twitchyliquid64/golang-asm/obj/x86" + "fmt" + "strings" +) + +// Pseudo-registers whose names are the constant name without the leading R. +const ( + RFP = -(iota + 1) + RSB + RSP + RPC +) + +// Arch wraps the link architecture object with more architecture-specific information. +type Arch struct { + *obj.LinkArch + // Map of instruction names to enumeration. + Instructions map[string]obj.As + // Map of register names to enumeration. + Register map[string]int16 + // Table of register prefix names. These are things like R for R(0) and SPR for SPR(268). + RegisterPrefix map[string]bool + // RegisterNumber converts R(10) into arm.REG_R10. + RegisterNumber func(string, int16) (int16, bool) + // Instruction is a jump. + IsJump func(word string) bool +} + +// nilRegisterNumber is the register number function for architectures +// that do not accept the R(N) notation. It always returns failure. +func nilRegisterNumber(name string, n int16) (int16, bool) { + return 0, false +} + +// Set configures the architecture specified by GOARCH and returns its representation. +// It returns nil if GOARCH is not recognized. +func Set(GOARCH string) *Arch { + switch GOARCH { + case "386": + return archX86(&x86.Link386) + case "amd64": + return archX86(&x86.Linkamd64) + case "arm": + return archArm() + case "arm64": + return archArm64() + case "mips": + return archMips(&mips.Linkmips) + case "mipsle": + return archMips(&mips.Linkmipsle) + case "mips64": + return archMips64(&mips.Linkmips64) + case "mips64le": + return archMips64(&mips.Linkmips64le) + case "ppc64": + return archPPC64(&ppc64.Linkppc64) + case "ppc64le": + return archPPC64(&ppc64.Linkppc64le) + case "riscv64": + return archRISCV64() + case "s390x": + return archS390x() + case "wasm": + return archWasm() + } + return nil +} + +func jumpX86(word string) bool { + return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN" +} + +func jumpRISCV(word string) bool { + switch word { + case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ", + "BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP": + return true + } + return false +} + +func jumpWasm(word string) bool { + return word == "JMP" || word == "CALL" || word == "Call" || word == "Br" || word == "BrIf" +} + +func archX86(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + for i, s := range x86.Register { + register[s] = int16(i + x86.REG_AL) + } + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Register prefix not used on this architecture. + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range x86.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseAMD64 + } + } + // Annoying aliases. + instructions["JA"] = x86.AJHI /* alternate */ + instructions["JAE"] = x86.AJCC /* alternate */ + instructions["JB"] = x86.AJCS /* alternate */ + instructions["JBE"] = x86.AJLS /* alternate */ + instructions["JC"] = x86.AJCS /* alternate */ + instructions["JCC"] = x86.AJCC /* carry clear (CF = 0) */ + instructions["JCS"] = x86.AJCS /* carry set (CF = 1) */ + instructions["JE"] = x86.AJEQ /* alternate */ + instructions["JEQ"] = x86.AJEQ /* equal (ZF = 1) */ + instructions["JG"] = x86.AJGT /* alternate */ + instructions["JGE"] = x86.AJGE /* greater than or equal (signed) (SF = OF) */ + instructions["JGT"] = x86.AJGT /* greater than (signed) (ZF = 0 && SF = OF) */ + instructions["JHI"] = x86.AJHI /* higher (unsigned) (CF = 0 && ZF = 0) */ + instructions["JHS"] = x86.AJCC /* alternate */ + instructions["JL"] = x86.AJLT /* alternate */ + instructions["JLE"] = x86.AJLE /* less than or equal (signed) (ZF = 1 || SF != OF) */ + instructions["JLO"] = x86.AJCS /* alternate */ + instructions["JLS"] = x86.AJLS /* lower or same (unsigned) (CF = 1 || ZF = 1) */ + instructions["JLT"] = x86.AJLT /* less than (signed) (SF != OF) */ + instructions["JMI"] = x86.AJMI /* negative (minus) (SF = 1) */ + instructions["JNA"] = x86.AJLS /* alternate */ + instructions["JNAE"] = x86.AJCS /* alternate */ + instructions["JNB"] = x86.AJCC /* alternate */ + instructions["JNBE"] = x86.AJHI /* alternate */ + instructions["JNC"] = x86.AJCC /* alternate */ + instructions["JNE"] = x86.AJNE /* not equal (ZF = 0) */ + instructions["JNG"] = x86.AJLE /* alternate */ + instructions["JNGE"] = x86.AJLT /* alternate */ + instructions["JNL"] = x86.AJGE /* alternate */ + instructions["JNLE"] = x86.AJGT /* alternate */ + instructions["JNO"] = x86.AJOC /* alternate */ + instructions["JNP"] = x86.AJPC /* alternate */ + instructions["JNS"] = x86.AJPL /* alternate */ + instructions["JNZ"] = x86.AJNE /* alternate */ + instructions["JO"] = x86.AJOS /* alternate */ + instructions["JOC"] = x86.AJOC /* overflow clear (OF = 0) */ + instructions["JOS"] = x86.AJOS /* overflow set (OF = 1) */ + instructions["JP"] = x86.AJPS /* alternate */ + instructions["JPC"] = x86.AJPC /* parity clear (PF = 0) */ + instructions["JPE"] = x86.AJPS /* alternate */ + instructions["JPL"] = x86.AJPL /* non-negative (plus) (SF = 0) */ + instructions["JPO"] = x86.AJPC /* alternate */ + instructions["JPS"] = x86.AJPS /* parity set (PF = 1) */ + instructions["JS"] = x86.AJMI /* alternate */ + instructions["JZ"] = x86.AJEQ /* alternate */ + instructions["MASKMOVDQU"] = x86.AMASKMOVOU + instructions["MOVD"] = x86.AMOVQ + instructions["MOVDQ2Q"] = x86.AMOVQ + instructions["MOVNTDQ"] = x86.AMOVNTO + instructions["MOVOA"] = x86.AMOVO + instructions["PSLLDQ"] = x86.APSLLO + instructions["PSRLDQ"] = x86.APSRLO + instructions["PADDD"] = x86.APADDL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpX86, + } +} + +func archArm() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := arm.REG_R0; i < arm.REG_SPSR; i++ { + register[obj.Rconv(i)] = int16(i) + } + // Avoid unintentionally clobbering g using R10. + delete(register, "R10") + register["g"] = arm.REG_R10 + for i := 0; i < 16; i++ { + register[fmt.Sprintf("C%d", i)] = int16(i) + } + + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + register["SP"] = RSP + registerPrefix := map[string]bool{ + "F": true, + "R": true, + } + + // special operands for DMB/DSB instructions + register["MB_SY"] = arm.REG_MB_SY + register["MB_ST"] = arm.REG_MB_ST + register["MB_ISH"] = arm.REG_MB_ISH + register["MB_ISHST"] = arm.REG_MB_ISHST + register["MB_NSH"] = arm.REG_MB_NSH + register["MB_NSHST"] = arm.REG_MB_NSHST + register["MB_OSH"] = arm.REG_MB_OSH + register["MB_OSHST"] = arm.REG_MB_OSHST + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range arm.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseARM + } + } + // Annoying aliases. + instructions["B"] = obj.AJMP + instructions["BL"] = obj.ACALL + // MCR differs from MRC by the way fields of the word are encoded. + // (Details in arm.go). Here we add the instruction so parse will find + // it, but give it an opcode number known only to us. + instructions["MCR"] = aMCR + + return &Arch{ + LinkArch: &arm.Linkarm, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: armRegisterNumber, + IsJump: jumpArm, + } +} + +func archArm64() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for 386 and amd64. + register[obj.Rconv(arm64.REGSP)] = int16(arm64.REGSP) + for i := arm64.REG_R0; i <= arm64.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + // Rename R18 to R18_PLATFORM to avoid accidental use. + register["R18_PLATFORM"] = register["R18"] + delete(register, "R18") + for i := arm64.REG_F0; i <= arm64.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := arm64.REG_V0; i <= arm64.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + + // System registers. + for i := 0; i < len(arm64.SystemReg); i++ { + register[arm64.SystemReg[i].Name] = arm64.SystemReg[i].Reg + } + + register["LR"] = arm64.REGLINK + register["DAIFSet"] = arm64.REG_DAIFSet + register["DAIFClr"] = arm64.REG_DAIFClr + register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP + register["PLDL1STRM"] = arm64.REG_PLDL1STRM + register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP + register["PLDL2STRM"] = arm64.REG_PLDL2STRM + register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP + register["PLDL3STRM"] = arm64.REG_PLDL3STRM + register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP + register["PLIL1STRM"] = arm64.REG_PLIL1STRM + register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP + register["PLIL2STRM"] = arm64.REG_PLIL2STRM + register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP + register["PLIL3STRM"] = arm64.REG_PLIL3STRM + register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP + register["PSTL1STRM"] = arm64.REG_PSTL1STRM + register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP + register["PSTL2STRM"] = arm64.REG_PSTL2STRM + register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP + register["PSTL3STRM"] = arm64.REG_PSTL3STRM + + // Conditional operators, like EQ, NE, etc. + register["EQ"] = arm64.COND_EQ + register["NE"] = arm64.COND_NE + register["HS"] = arm64.COND_HS + register["CS"] = arm64.COND_HS + register["LO"] = arm64.COND_LO + register["CC"] = arm64.COND_LO + register["MI"] = arm64.COND_MI + register["PL"] = arm64.COND_PL + register["VS"] = arm64.COND_VS + register["VC"] = arm64.COND_VC + register["HI"] = arm64.COND_HI + register["LS"] = arm64.COND_LS + register["GE"] = arm64.COND_GE + register["LT"] = arm64.COND_LT + register["GT"] = arm64.COND_GT + register["LE"] = arm64.COND_LE + register["AL"] = arm64.COND_AL + register["NV"] = arm64.COND_NV + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + register["SP"] = RSP + // Avoid unintentionally clobbering g using R28. + delete(register, "R28") + register["g"] = arm64.REG_R28 + registerPrefix := map[string]bool{ + "F": true, + "R": true, + "V": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range arm64.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseARM64 + } + } + // Annoying aliases. + instructions["B"] = arm64.AB + instructions["BL"] = arm64.ABL + + return &Arch{ + LinkArch: &arm64.Linkarm64, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: arm64RegisterNumber, + IsJump: jumpArm64, + } + +} + +func archPPC64(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_V0; i <= ppc64.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_VS0; i <= ppc64.REG_VS63; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["CR"] = ppc64.REG_CR + register["XER"] = ppc64.REG_XER + register["LR"] = ppc64.REG_LR + register["CTR"] = ppc64.REG_CTR + register["FPSCR"] = ppc64.REG_FPSCR + register["MSR"] = ppc64.REG_MSR + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = ppc64.REG_R30 + registerPrefix := map[string]bool{ + "CR": true, + "F": true, + "R": true, + "SPR": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range ppc64.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABasePPC64 + } + } + // Annoying aliases. + instructions["BR"] = ppc64.ABR + instructions["BL"] = ppc64.ABL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: ppc64RegisterNumber, + IsJump: jumpPPC64, + } +} + +func archMips(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := mips.REG_R0; i <= mips.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + + for i := mips.REG_F0; i <= mips.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_M0; i <= mips.REG_M31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["HI"] = mips.REG_HI + register["LO"] = mips.REG_LO + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = mips.REG_R30 + + registerPrefix := map[string]bool{ + "F": true, + "FCR": true, + "M": true, + "R": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range mips.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseMIPS + } + } + // Annoying alias. + instructions["JAL"] = mips.AJAL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: mipsRegisterNumber, + IsJump: jumpMIPS, + } +} + +func archMips64(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := mips.REG_R0; i <= mips.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_F0; i <= mips.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_M0; i <= mips.REG_M31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_W0; i <= mips.REG_W31; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["HI"] = mips.REG_HI + register["LO"] = mips.REG_LO + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = mips.REG_R30 + // Avoid unintentionally clobbering RSB using R28. + delete(register, "R28") + register["RSB"] = mips.REG_R28 + registerPrefix := map[string]bool{ + "F": true, + "FCR": true, + "M": true, + "R": true, + "W": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range mips.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseMIPS + } + } + // Annoying alias. + instructions["JAL"] = mips.AJAL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: mipsRegisterNumber, + IsJump: jumpMIPS, + } +} + +func archRISCV64() *Arch { + register := make(map[string]int16) + + // Standard register names. + for i := riscv.REG_X0; i <= riscv.REG_X31; i++ { + name := fmt.Sprintf("X%d", i-riscv.REG_X0) + register[name] = int16(i) + } + for i := riscv.REG_F0; i <= riscv.REG_F31; i++ { + name := fmt.Sprintf("F%d", i-riscv.REG_F0) + register[name] = int16(i) + } + + // General registers with ABI names. + register["ZERO"] = riscv.REG_ZERO + register["RA"] = riscv.REG_RA + register["SP"] = riscv.REG_SP + register["GP"] = riscv.REG_GP + register["TP"] = riscv.REG_TP + register["T0"] = riscv.REG_T0 + register["T1"] = riscv.REG_T1 + register["T2"] = riscv.REG_T2 + register["S0"] = riscv.REG_S0 + register["S1"] = riscv.REG_S1 + register["A0"] = riscv.REG_A0 + register["A1"] = riscv.REG_A1 + register["A2"] = riscv.REG_A2 + register["A3"] = riscv.REG_A3 + register["A4"] = riscv.REG_A4 + register["A5"] = riscv.REG_A5 + register["A6"] = riscv.REG_A6 + register["A7"] = riscv.REG_A7 + register["S2"] = riscv.REG_S2 + register["S3"] = riscv.REG_S3 + register["S4"] = riscv.REG_S4 + register["S5"] = riscv.REG_S5 + register["S6"] = riscv.REG_S6 + register["S7"] = riscv.REG_S7 + register["S8"] = riscv.REG_S8 + register["S9"] = riscv.REG_S9 + register["S10"] = riscv.REG_S10 + register["S11"] = riscv.REG_S11 + register["T3"] = riscv.REG_T3 + register["T4"] = riscv.REG_T4 + register["T5"] = riscv.REG_T5 + register["T6"] = riscv.REG_T6 + + // Go runtime register names. + register["g"] = riscv.REG_G + register["CTXT"] = riscv.REG_CTXT + register["TMP"] = riscv.REG_TMP + + // ABI names for floating point register. + register["FT0"] = riscv.REG_FT0 + register["FT1"] = riscv.REG_FT1 + register["FT2"] = riscv.REG_FT2 + register["FT3"] = riscv.REG_FT3 + register["FT4"] = riscv.REG_FT4 + register["FT5"] = riscv.REG_FT5 + register["FT6"] = riscv.REG_FT6 + register["FT7"] = riscv.REG_FT7 + register["FS0"] = riscv.REG_FS0 + register["FS1"] = riscv.REG_FS1 + register["FA0"] = riscv.REG_FA0 + register["FA1"] = riscv.REG_FA1 + register["FA2"] = riscv.REG_FA2 + register["FA3"] = riscv.REG_FA3 + register["FA4"] = riscv.REG_FA4 + register["FA5"] = riscv.REG_FA5 + register["FA6"] = riscv.REG_FA6 + register["FA7"] = riscv.REG_FA7 + register["FS2"] = riscv.REG_FS2 + register["FS3"] = riscv.REG_FS3 + register["FS4"] = riscv.REG_FS4 + register["FS5"] = riscv.REG_FS5 + register["FS6"] = riscv.REG_FS6 + register["FS7"] = riscv.REG_FS7 + register["FS8"] = riscv.REG_FS8 + register["FS9"] = riscv.REG_FS9 + register["FS10"] = riscv.REG_FS10 + register["FS11"] = riscv.REG_FS11 + register["FT8"] = riscv.REG_FT8 + register["FT9"] = riscv.REG_FT9 + register["FT10"] = riscv.REG_FT10 + register["FT11"] = riscv.REG_FT11 + + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range riscv.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseRISCV + } + } + + return &Arch{ + LinkArch: &riscv.LinkRISCV64, + Instructions: instructions, + Register: register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpRISCV, + } +} + +func archS390x() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := s390x.REG_R0; i <= s390x.REG_R15; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_F0; i <= s390x.REG_F15; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_V0; i <= s390x.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_AR0; i <= s390x.REG_AR15; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["LR"] = s390x.REG_LR + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R13. + delete(register, "R13") + register["g"] = s390x.REG_R13 + registerPrefix := map[string]bool{ + "AR": true, + "F": true, + "R": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range s390x.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseS390X + } + } + // Annoying aliases. + instructions["BR"] = s390x.ABR + instructions["BL"] = s390x.ABL + + return &Arch{ + LinkArch: &s390x.Links390x, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: s390xRegisterNumber, + IsJump: jumpS390x, + } +} + +func archWasm() *Arch { + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range wasm.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseWasm + } + } + + return &Arch{ + LinkArch: &wasm.Linkwasm, + Instructions: instructions, + Register: wasm.Register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpWasm, + } +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm.go new file mode 100644 index 0000000..645e98a --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm.go @@ -0,0 +1,257 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the ARM +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "strings" + + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/arm" +) + +var armLS = map[string]uint8{ + "U": arm.C_UBIT, + "S": arm.C_SBIT, + "W": arm.C_WBIT, + "P": arm.C_PBIT, + "PW": arm.C_WBIT | arm.C_PBIT, + "WP": arm.C_WBIT | arm.C_PBIT, +} + +var armSCOND = map[string]uint8{ + "EQ": arm.C_SCOND_EQ, + "NE": arm.C_SCOND_NE, + "CS": arm.C_SCOND_HS, + "HS": arm.C_SCOND_HS, + "CC": arm.C_SCOND_LO, + "LO": arm.C_SCOND_LO, + "MI": arm.C_SCOND_MI, + "PL": arm.C_SCOND_PL, + "VS": arm.C_SCOND_VS, + "VC": arm.C_SCOND_VC, + "HI": arm.C_SCOND_HI, + "LS": arm.C_SCOND_LS, + "GE": arm.C_SCOND_GE, + "LT": arm.C_SCOND_LT, + "GT": arm.C_SCOND_GT, + "LE": arm.C_SCOND_LE, + "AL": arm.C_SCOND_NONE, + "U": arm.C_UBIT, + "S": arm.C_SBIT, + "W": arm.C_WBIT, + "P": arm.C_PBIT, + "PW": arm.C_WBIT | arm.C_PBIT, + "WP": arm.C_WBIT | arm.C_PBIT, + "F": arm.C_FBIT, + "IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT, + "IAW": arm.C_WBIT | arm.C_UBIT, + "DBW": arm.C_WBIT | arm.C_PBIT, + "DAW": arm.C_WBIT, + "IB": arm.C_PBIT | arm.C_UBIT, + "IA": arm.C_UBIT, + "DB": arm.C_PBIT, + "DA": 0, +} + +var armJump = map[string]bool{ + "B": true, + "BL": true, + "BX": true, + "BEQ": true, + "BNE": true, + "BCS": true, + "BHS": true, + "BCC": true, + "BLO": true, + "BMI": true, + "BPL": true, + "BVS": true, + "BVC": true, + "BHI": true, + "BLS": true, + "BGE": true, + "BLT": true, + "BGT": true, + "BLE": true, + "CALL": true, + "JMP": true, +} + +func jumpArm(word string) bool { + return armJump[word] +} + +// IsARMCMP reports whether the op (as defined by an arm.A* constant) is +// one of the comparison instructions that require special handling. +func IsARMCMP(op obj.As) bool { + switch op { + case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST: + return true + } + return false +} + +// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is +// one of the STREX-like instructions that require special handling. +func IsARMSTREX(op obj.As) bool { + switch op { + case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU: + return true + } + return false +} + +// MCR is not defined by the obj/arm; instead we define it privately here. +// It is encoded as an MRC with a bit inside the instruction word, +// passed to arch.ARMMRCOffset. +const aMCR = arm.ALAST + 1 + +// IsARMMRC reports whether the op (as defined by an arm.A* constant) is +// MRC or MCR +func IsARMMRC(op obj.As) bool { + switch op { + case arm.AMRC, aMCR: // Note: aMCR is defined in this package. + return true + } + return false +} + +// IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the +// BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg". +func IsARMBFX(op obj.As) bool { + switch op { + case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI: + return true + } + return false +} + +// IsARMFloatCmp reports whether the op is a floating comparison instruction. +func IsARMFloatCmp(op obj.As) bool { + switch op { + case arm.ACMPF, arm.ACMPD: + return true + } + return false +} + +// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions. +// The difference between MRC and MCR is represented by a bit high in the word, not +// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so +// we return the opcode for MRC so that asm doesn't need to import obj/arm. +func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) { + op1 := int64(0) + if op == arm.AMRC { + op1 = 1 + } + bits, ok := ParseARMCondition(cond) + if !ok { + return + } + offset = (0xe << 24) | // opcode + (op1 << 20) | // MCR/MRC + ((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond + ((x0 & 15) << 8) | //coprocessor number + ((x1 & 7) << 21) | // coprocessor operation + ((x2 & 15) << 12) | // ARM register + ((x3 & 15) << 16) | // Crn + ((x4 & 15) << 0) | // Crm + ((x5 & 7) << 5) | // coprocessor information + (1 << 4) /* must be set */ + return offset, arm.AMRC, true +} + +// IsARMMULA reports whether the op (as defined by an arm.A* constant) is +// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions. +func IsARMMULA(op obj.As) bool { + switch op { + case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT: + return true + } + return false +} + +var bcode = []obj.As{ + arm.ABEQ, + arm.ABNE, + arm.ABCS, + arm.ABCC, + arm.ABMI, + arm.ABPL, + arm.ABVS, + arm.ABVC, + arm.ABHI, + arm.ABLS, + arm.ABGE, + arm.ABLT, + arm.ABGT, + arm.ABLE, + arm.AB, + obj.ANOP, +} + +// ARMConditionCodes handles the special condition code situation for the ARM. +// It returns a boolean to indicate success; failure means cond was unrecognized. +func ARMConditionCodes(prog *obj.Prog, cond string) bool { + if cond == "" { + return true + } + bits, ok := ParseARMCondition(cond) + if !ok { + return false + } + /* hack to make B.NE etc. work: turn it into the corresponding conditional */ + if prog.As == arm.AB { + prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf] + bits = (bits &^ 0xf) | arm.C_SCOND_NONE + } + prog.Scond = bits + return true +} + +// ParseARMCondition parses the conditions attached to an ARM instruction. +// The input is a single string consisting of period-separated condition +// codes, such as ".P.W". An initial period is ignored. +func ParseARMCondition(cond string) (uint8, bool) { + return parseARMCondition(cond, armLS, armSCOND) +} + +func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) { + cond = strings.TrimPrefix(cond, ".") + if cond == "" { + return arm.C_SCOND_NONE, true + } + names := strings.Split(cond, ".") + bits := uint8(0) + for _, name := range names { + if b, present := ls[name]; present { + bits |= b + continue + } + if b, present := scond[name]; present { + bits = (bits &^ arm.C_SCOND) | b + continue + } + return 0, false + } + return bits, true +} + +func armRegisterNumber(name string, n int16) (int16, bool) { + if n < 0 || 15 < n { + return 0, false + } + switch name { + case "R": + return arm.REG_R0 + n, true + case "F": + return arm.REG_F0 + n, true + } + return 0, false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm64.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm64.go new file mode 100644 index 0000000..b0606be --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/arm64.go @@ -0,0 +1,350 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the ARM64 +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/arm64" + "errors" +) + +var arm64LS = map[string]uint8{ + "P": arm64.C_XPOST, + "W": arm64.C_XPRE, +} + +var arm64Jump = map[string]bool{ + "B": true, + "BL": true, + "BEQ": true, + "BNE": true, + "BCS": true, + "BHS": true, + "BCC": true, + "BLO": true, + "BMI": true, + "BPL": true, + "BVS": true, + "BVC": true, + "BHI": true, + "BLS": true, + "BGE": true, + "BLT": true, + "BGT": true, + "BLE": true, + "CALL": true, + "CBZ": true, + "CBZW": true, + "CBNZ": true, + "CBNZW": true, + "JMP": true, + "TBNZ": true, + "TBZ": true, +} + +func jumpArm64(word string) bool { + return arm64Jump[word] +} + +// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is +// one of the comparison instructions that require special handling. +func IsARM64CMP(op obj.As) bool { + switch op { + case arm64.ACMN, arm64.ACMP, arm64.ATST, + arm64.ACMNW, arm64.ACMPW, arm64.ATSTW, + arm64.AFCMPS, arm64.AFCMPD, + arm64.AFCMPES, arm64.AFCMPED: + return true + } + return false +} + +// IsARM64STLXR reports whether the op (as defined by an arm64.A* +// constant) is one of the STLXR-like instructions that require special +// handling. +func IsARM64STLXR(op obj.As) bool { + switch op { + case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR, + arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR, + arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW: + return true + } + // atomic instructions + if arm64.IsAtomicInstruction(op) { + return true + } + return false +} + +// ARM64Suffix handles the special suffix for the ARM64. +// It returns a boolean to indicate success; failure means +// cond was unrecognized. +func ARM64Suffix(prog *obj.Prog, cond string) bool { + if cond == "" { + return true + } + bits, ok := parseARM64Suffix(cond) + if !ok { + return false + } + prog.Scond = bits + return true +} + +// parseARM64Suffix parses the suffix attached to an ARM64 instruction. +// The input is a single string consisting of period-separated condition +// codes, such as ".P.W". An initial period is ignored. +func parseARM64Suffix(cond string) (uint8, bool) { + if cond == "" { + return 0, true + } + return parseARMCondition(cond, arm64LS, nil) +} + +func arm64RegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "F": + if 0 <= n && n <= 31 { + return arm64.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 30 { // not 31 + return arm64.REG_R0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return arm64.REG_V0 + n, true + } + } + return 0, false +} + +// IsARM64TBL reports whether the op (as defined by an arm64.A* +// constant) is one of the table lookup instructions that require special +// handling. +func IsARM64TBL(op obj.As) bool { + return op == arm64.AVTBL +} + +// ARM64RegisterExtension parses an ARM64 register with extension or arrangement. +func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { + Rnum := (reg & 31) + int16(num<<5) + if isAmount { + if num < 0 || num > 7 { + return errors.New("index shift amount is out of range") + } + } + switch ext { + case "UXTB": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTB + Rnum + case "UXTH": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTH + Rnum + case "UXTW": + if !isAmount { + return errors.New("invalid register extension") + } + // effective address of memory is a base register value and an offset register value. + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_UXTW + Rnum + } else { + a.Reg = arm64.REG_UXTW + Rnum + } + case "UXTX": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTX + Rnum + case "SXTB": + if !isAmount { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_SXTB + Rnum + case "SXTH": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_SXTH + Rnum + case "SXTW": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_SXTW + Rnum + } else { + a.Reg = arm64.REG_SXTW + Rnum + } + case "SXTX": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_SXTX + Rnum + } else { + a.Reg = arm64.REG_SXTX + Rnum + } + case "LSL": + if !isAmount { + return errors.New("invalid register extension") + } + a.Index = arm64.REG_LSL + Rnum + case "B8": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) + case "B16": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) + case "H4": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) + case "H8": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) + case "S2": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) + case "S4": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) + case "D1": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5) + case "D2": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) + case "Q1": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5) + case "B": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) + a.Index = num + case "H": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) + a.Index = num + case "S": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) + a.Index = num + case "D": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) + a.Index = num + default: + return errors.New("unsupported register extension type: " + ext) + } + + return nil +} + +// ARM64RegisterArrangement parses an ARM64 vector register arrangement. +func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { + var curQ, curSize uint16 + if name[0] != 'V' { + return 0, errors.New("expect V0 through V31; found: " + name) + } + if reg < 0 { + return 0, errors.New("invalid register number: " + name) + } + switch arng { + case "B8": + curSize = 0 + curQ = 0 + case "B16": + curSize = 0 + curQ = 1 + case "H4": + curSize = 1 + curQ = 0 + case "H8": + curSize = 1 + curQ = 1 + case "S2": + curSize = 2 + curQ = 0 + case "S4": + curSize = 2 + curQ = 1 + case "D1": + curSize = 3 + curQ = 0 + case "D2": + curSize = 3 + curQ = 1 + default: + return 0, errors.New("invalid arrangement in ARM64 register list") + } + return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil +} + +// ARM64RegisterListOffset generates offset encoding according to AArch64 specification. +func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { + offset := int64(firstReg) + switch regCnt { + case 1: + offset |= 0x7 << 12 + case 2: + offset |= 0xa << 12 + case 3: + offset |= 0x6 << 12 + case 4: + offset |= 0x2 << 12 + default: + return 0, errors.New("invalid register numbers in ARM64 register list") + } + offset |= arrangement + // arm64 uses the 60th bit to differentiate from other archs + // For more details, refer to: obj/arm64/list7.go + offset |= 1 << 60 + return offset, nil +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/mips.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/mips.go new file mode 100644 index 0000000..7af9dbb --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/mips.go @@ -0,0 +1,72 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the +// MIPS (MIPS64) instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/mips" +) + +func jumpMIPS(word string) bool { + switch word { + case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL": + return true + } + return false +} + +// IsMIPSCMP reports whether the op (as defined by an mips.A* constant) is +// one of the CMP instructions that require special handling. +func IsMIPSCMP(op obj.As) bool { + switch op { + case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED, + mips.ACMPGTF, mips.ACMPGTD: + return true + } + return false +} + +// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is +// one of the MUL/DIV/REM/MADD/MSUB instructions that require special handling. +func IsMIPSMUL(op obj.As) bool { + switch op { + case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU, + mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU, + mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU, + mips.AMADD, mips.AMSUB: + return true + } + return false +} + +func mipsRegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "F": + if 0 <= n && n <= 31 { + return mips.REG_F0 + n, true + } + case "FCR": + if 0 <= n && n <= 31 { + return mips.REG_FCR0 + n, true + } + case "M": + if 0 <= n && n <= 31 { + return mips.REG_M0 + n, true + } + case "R": + if 0 <= n && n <= 31 { + return mips.REG_R0 + n, true + } + case "W": + if 0 <= n && n <= 31 { + return mips.REG_W0 + n, true + } + } + return 0, false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/ppc64.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/ppc64.go new file mode 100644 index 0000000..8b2f097 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/ppc64.go @@ -0,0 +1,102 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the +// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/ppc64" +) + +func jumpPPC64(word string) bool { + switch word { + case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP": + return true + } + return false +} + +// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is +// one of the RLD-like instructions that require special handling. +// The FMADD-like instructions behave similarly. +func IsPPC64RLD(op obj.As) bool { + switch op { + case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC, + ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC, + ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC: + return true + case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC, + ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC, + ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC, + ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC: + return true + } + return false +} + +func IsPPC64ISEL(op obj.As) bool { + return op == ppc64.AISEL +} + +// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is +// one of the CMP instructions that require special handling. +func IsPPC64CMP(op obj.As) bool { + switch op { + case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPU: + return true + } + return false +} + +// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is +// one of the NEG-like instructions that require special handling. +func IsPPC64NEG(op obj.As) bool { + switch op { + case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME, + ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE, + ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW, + ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH, + ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC, + ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV, + ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV, + ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV, + ppc64.ASUBZE: + return true + } + return false +} + +func ppc64RegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "CR": + if 0 <= n && n <= 7 { + return ppc64.REG_CR0 + n, true + } + case "VS": + if 0 <= n && n <= 63 { + return ppc64.REG_VS0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return ppc64.REG_V0 + n, true + } + case "F": + if 0 <= n && n <= 31 { + return ppc64.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 31 { + return ppc64.REG_R0 + n, true + } + case "SPR": + if 0 <= n && n <= 1024 { + return ppc64.REG_SPR0 + n, true + } + } + return 0, false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/riscv64.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/riscv64.go new file mode 100644 index 0000000..e4f1753 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/riscv64.go @@ -0,0 +1,28 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the RISCV64 +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/obj/riscv" +) + +// IsRISCV64AMO reports whether the op (as defined by a riscv.A* +// constant) is one of the AMO instructions that requires special +// handling. +func IsRISCV64AMO(op obj.As) bool { + switch op { + case riscv.ASCW, riscv.ASCD, riscv.AAMOSWAPW, riscv.AAMOSWAPD, riscv.AAMOADDW, riscv.AAMOADDD, + riscv.AAMOANDW, riscv.AAMOANDD, riscv.AAMOORW, riscv.AAMOORD, riscv.AAMOXORW, riscv.AAMOXORD, + riscv.AAMOMINW, riscv.AAMOMIND, riscv.AAMOMINUW, riscv.AAMOMINUD, + riscv.AAMOMAXW, riscv.AAMOMAXD, riscv.AAMOMAXUW, riscv.AAMOMAXUD: + return true + } + return false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/s390x.go b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/s390x.go new file mode 100644 index 0000000..1e33f1e --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/asm/arch/s390x.go @@ -0,0 +1,81 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the +// s390x instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "github.com/twitchyliquid64/golang-asm/obj/s390x" +) + +func jumpS390x(word string) bool { + switch word { + case "BRC", + "BC", + "BCL", + "BEQ", + "BGE", + "BGT", + "BL", + "BLE", + "BLEU", + "BLT", + "BLTU", + "BNE", + "BR", + "BVC", + "BVS", + "BRCT", + "BRCTG", + "CMPBEQ", + "CMPBGE", + "CMPBGT", + "CMPBLE", + "CMPBLT", + "CMPBNE", + "CMPUBEQ", + "CMPUBGE", + "CMPUBGT", + "CMPUBLE", + "CMPUBLT", + "CMPUBNE", + "CRJ", + "CGRJ", + "CLRJ", + "CLGRJ", + "CIJ", + "CGIJ", + "CLIJ", + "CLGIJ", + "CALL", + "JMP": + return true + } + return false +} + +func s390xRegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "AR": + if 0 <= n && n <= 15 { + return s390x.REG_AR0 + n, true + } + case "F": + if 0 <= n && n <= 15 { + return s390x.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 15 { + return s390x.REG_R0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return s390x.REG_V0 + n, true + } + } + return 0, false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/bio/buf.go b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf.go new file mode 100644 index 0000000..c4c2514 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf.go @@ -0,0 +1,148 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bio implements common I/O abstractions used within the Go toolchain. +package bio + +import ( + "bufio" + "io" + "log" + "os" +) + +// Reader implements a seekable buffered io.Reader. +type Reader struct { + f *os.File + *bufio.Reader +} + +// Writer implements a seekable buffered io.Writer. +type Writer struct { + f *os.File + *bufio.Writer +} + +// Create creates the file named name and returns a Writer +// for that file. +func Create(name string) (*Writer, error) { + f, err := os.Create(name) + if err != nil { + return nil, err + } + return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil +} + +// Open returns a Reader for the file named name. +func Open(name string) (*Reader, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + return NewReader(f), nil +} + +// NewReader returns a Reader from an open file. +func NewReader(f *os.File) *Reader { + return &Reader{f: f, Reader: bufio.NewReader(f)} +} + +func (r *Reader) MustSeek(offset int64, whence int) int64 { + if whence == 1 { + offset -= int64(r.Buffered()) + } + off, err := r.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + r.Reset(r.f) + return off +} + +func (w *Writer) MustSeek(offset int64, whence int) int64 { + if err := w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + off, err := w.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + return off +} + +func (r *Reader) Offset() int64 { + off, err := r.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) + } + off -= int64(r.Buffered()) + return off +} + +func (w *Writer) Offset() int64 { + if err := w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + off, err := w.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) + } + return off +} + +func (r *Reader) Close() error { + return r.f.Close() +} + +func (w *Writer) Close() error { + err := w.Flush() + err1 := w.f.Close() + if err == nil { + err = err1 + } + return err +} + +func (r *Reader) File() *os.File { + return r.f +} + +func (w *Writer) File() *os.File { + return w.f +} + +// Slice reads the next length bytes of r into a slice. +// +// This slice may be backed by mmap'ed memory. Currently, this memory +// will never be unmapped. The second result reports whether the +// backing memory is read-only. +func (r *Reader) Slice(length uint64) ([]byte, bool, error) { + if length == 0 { + return []byte{}, false, nil + } + + data, ok := r.sliceOS(length) + if ok { + return data, true, nil + } + + data = make([]byte, length) + _, err := io.ReadFull(r, data) + if err != nil { + return nil, false, err + } + return data, false, nil +} + +// SliceRO returns a slice containing the next length bytes of r +// backed by a read-only mmap'd data. If the mmap cannot be +// established (limit exceeded, region too small, etc) a nil slice +// will be returned. If mmap succeeds, it will never be unmapped. +func (r *Reader) SliceRO(length uint64) []byte { + data, ok := r.sliceOS(length) + if ok { + return data + } + return nil +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_mmap.go b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_mmap.go new file mode 100644 index 0000000..4b43d74 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_mmap.go @@ -0,0 +1,62 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package bio + +import ( + "runtime" + "sync/atomic" + "syscall" +) + +// mmapLimit is the maximum number of mmaped regions to create before +// falling back to reading into a heap-allocated slice. This exists +// because some operating systems place a limit on the number of +// distinct mapped regions per process. As of this writing: +// +// Darwin unlimited +// DragonFly 1000000 (vm.max_proc_mmap) +// FreeBSD unlimited +// Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count? +// NetBSD unlimited +// OpenBSD unlimited +var mmapLimit int32 = 1<<31 - 1 + +func init() { + // Linux is the only practically concerning OS. + if runtime.GOOS == "linux" { + mmapLimit = 30000 + } +} + +func (r *Reader) sliceOS(length uint64) ([]byte, bool) { + // For small slices, don't bother with the overhead of a + // mapping, especially since we have no way to unmap it. + const threshold = 16 << 10 + if length < threshold { + return nil, false + } + + // Have we reached the mmap limit? + if atomic.AddInt32(&mmapLimit, -1) < 0 { + atomic.AddInt32(&mmapLimit, 1) + return nil, false + } + + // Page-align the offset. + off := r.Offset() + align := syscall.Getpagesize() + aoff := off &^ int64(align-1) + + data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE) + if err != nil { + return nil, false + } + + data = data[off-aoff:] + r.MustSeek(int64(length), 1) + return data, true +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_nommap.go b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_nommap.go new file mode 100644 index 0000000..f43c67a --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/bio/buf_nommap.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd + +package bio + +func (r *Reader) sliceOS(length uint64) ([]byte, bool) { + return nil, false +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/bio/must.go b/vendor/github.com/twitchyliquid64/golang-asm/bio/must.go new file mode 100644 index 0000000..3604b29 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/bio/must.go @@ -0,0 +1,43 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bio + +import ( + "io" + "log" +) + +// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error. +func MustClose(c io.Closer) { + if err := c.Close(); err != nil { + log.Fatal(err) + } +} + +// MustWriter returns a Writer that wraps the provided Writer, +// except that it calls log.Fatal instead of returning a non-nil error. +func MustWriter(w io.Writer) io.Writer { + return mustWriter{w} +} + +type mustWriter struct { + w io.Writer +} + +func (w mustWriter) Write(b []byte) (int, error) { + n, err := w.w.Write(b) + if err != nil { + log.Fatal(err) + } + return n, nil +} + +func (w mustWriter) WriteString(s string) (int, error) { + n, err := io.WriteString(w.w, s) + if err != nil { + log.Fatal(err) + } + return n, nil +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go new file mode 100644 index 0000000..2fee79d --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go @@ -0,0 +1,1650 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dwarf generates DWARF debugging information. +// DWARF generation is split between the compiler and the linker, +// this package contains the shared code. +package dwarf + +import ( + "bytes" + "github.com/twitchyliquid64/golang-asm/objabi" + "errors" + "fmt" + "os/exec" + "sort" + "strconv" + "strings" +) + +// InfoPrefix is the prefix for all the symbols containing DWARF info entries. +const InfoPrefix = "go.info." + +// ConstInfoPrefix is the prefix for all symbols containing DWARF info +// entries that contain constants. +const ConstInfoPrefix = "go.constinfo." + +// CUInfoPrefix is the prefix for symbols containing information to +// populate the DWARF compilation unit info entries. +const CUInfoPrefix = "go.cuinfo." + +// Used to form the symbol name assigned to the DWARF 'abstract subprogram" +// info entry for a function +const AbstractFuncSuffix = "$abstract" + +// Controls logging/debugging for selected aspects of DWARF subprogram +// generation (functions, scopes). +var logDwarf bool + +// Sym represents a symbol. +type Sym interface { + Length(dwarfContext interface{}) int64 +} + +// A Var represents a local variable or a function parameter. +type Var struct { + Name string + Abbrev int // Either DW_ABRV_AUTO[_LOCLIST] or DW_ABRV_PARAM[_LOCLIST] + IsReturnValue bool + IsInlFormal bool + StackOffset int32 + // This package can't use the ssa package, so it can't mention ssa.FuncDebug, + // so indirect through a closure. + PutLocationList func(listSym, startPC Sym) + Scope int32 + Type Sym + DeclFile string + DeclLine uint + DeclCol uint + InlIndex int32 // subtract 1 to form real index into InlTree + ChildIndex int32 // child DIE index in abstract function + IsInAbstract bool // variable exists in abstract function +} + +// A Scope represents a lexical scope. All variables declared within a +// scope will only be visible to instructions covered by the scope. +// Lexical scopes are contiguous in source files but can end up being +// compiled to discontiguous blocks of instructions in the executable. +// The Ranges field lists all the blocks of instructions that belong +// in this scope. +type Scope struct { + Parent int32 + Ranges []Range + Vars []*Var +} + +// A Range represents a half-open interval [Start, End). +type Range struct { + Start, End int64 +} + +// This container is used by the PutFunc* variants below when +// creating the DWARF subprogram DIE(s) for a function. +type FnState struct { + Name string + Importpath string + Info Sym + Filesym Sym + Loc Sym + Ranges Sym + Absfn Sym + StartPC Sym + Size int64 + External bool + Scopes []Scope + InlCalls InlCalls + UseBASEntries bool +} + +func EnableLogging(doit bool) { + logDwarf = doit +} + +// UnifyRanges merges the list of ranges of c into the list of ranges of s +func (s *Scope) UnifyRanges(c *Scope) { + out := make([]Range, 0, len(s.Ranges)+len(c.Ranges)) + + i, j := 0, 0 + for { + var cur Range + if i < len(s.Ranges) && j < len(c.Ranges) { + if s.Ranges[i].Start < c.Ranges[j].Start { + cur = s.Ranges[i] + i++ + } else { + cur = c.Ranges[j] + j++ + } + } else if i < len(s.Ranges) { + cur = s.Ranges[i] + i++ + } else if j < len(c.Ranges) { + cur = c.Ranges[j] + j++ + } else { + break + } + + if n := len(out); n > 0 && cur.Start <= out[n-1].End { + out[n-1].End = cur.End + } else { + out = append(out, cur) + } + } + + s.Ranges = out +} + +// AppendRange adds r to s, if r is non-empty. +// If possible, it extends the last Range in s.Ranges; if not, it creates a new one. +func (s *Scope) AppendRange(r Range) { + if r.End <= r.Start { + return + } + i := len(s.Ranges) + if i > 0 && s.Ranges[i-1].End == r.Start { + s.Ranges[i-1].End = r.End + return + } + s.Ranges = append(s.Ranges, r) +} + +type InlCalls struct { + Calls []InlCall +} + +type InlCall struct { + // index into ctx.InlTree describing the call inlined here + InlIndex int + + // Symbol of file containing inlined call site (really *obj.LSym). + CallFile Sym + + // Line number of inlined call site. + CallLine uint32 + + // Dwarf abstract subroutine symbol (really *obj.LSym). + AbsFunSym Sym + + // Indices of child inlines within Calls array above. + Children []int + + // entries in this list are PAUTO's created by the inliner to + // capture the promoted formals and locals of the inlined callee. + InlVars []*Var + + // PC ranges for this inlined call. + Ranges []Range + + // Root call (not a child of some other call). + Root bool +} + +// A Context specifies how to add data to a Sym. +type Context interface { + PtrSize() int + AddInt(s Sym, size int, i int64) + AddBytes(s Sym, b []byte) + AddAddress(s Sym, t interface{}, ofs int64) + AddCURelativeAddress(s Sym, t interface{}, ofs int64) + AddSectionOffset(s Sym, size int, t interface{}, ofs int64) + AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64) + CurrentOffset(s Sym) int64 + RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int) + RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32) + AddString(s Sym, v string) + AddFileRef(s Sym, f interface{}) + Logf(format string, args ...interface{}) +} + +// AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding. +func AppendUleb128(b []byte, v uint64) []byte { + for { + c := uint8(v & 0x7f) + v >>= 7 + if v != 0 { + c |= 0x80 + } + b = append(b, c) + if c&0x80 == 0 { + break + } + } + return b +} + +// AppendSleb128 appends v to b using DWARF's signed LEB128 encoding. +func AppendSleb128(b []byte, v int64) []byte { + for { + c := uint8(v & 0x7f) + s := uint8(v & 0x40) + v >>= 7 + if (v != -1 || s == 0) && (v != 0 || s != 0) { + c |= 0x80 + } + b = append(b, c) + if c&0x80 == 0 { + break + } + } + return b +} + +// sevenbits contains all unsigned seven bit numbers, indexed by their value. +var sevenbits = [...]byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, +} + +// sevenBitU returns the unsigned LEB128 encoding of v if v is seven bits and nil otherwise. +// The contents of the returned slice must not be modified. +func sevenBitU(v int64) []byte { + if uint64(v) < uint64(len(sevenbits)) { + return sevenbits[v : v+1] + } + return nil +} + +// sevenBitS returns the signed LEB128 encoding of v if v is seven bits and nil otherwise. +// The contents of the returned slice must not be modified. +func sevenBitS(v int64) []byte { + if uint64(v) <= 63 { + return sevenbits[v : v+1] + } + if uint64(-v) <= 64 { + return sevenbits[128+v : 128+v+1] + } + return nil +} + +// Uleb128put appends v to s using DWARF's unsigned LEB128 encoding. +func Uleb128put(ctxt Context, s Sym, v int64) { + b := sevenBitU(v) + if b == nil { + var encbuf [20]byte + b = AppendUleb128(encbuf[:0], uint64(v)) + } + ctxt.AddBytes(s, b) +} + +// Sleb128put appends v to s using DWARF's signed LEB128 encoding. +func Sleb128put(ctxt Context, s Sym, v int64) { + b := sevenBitS(v) + if b == nil { + var encbuf [20]byte + b = AppendSleb128(encbuf[:0], v) + } + ctxt.AddBytes(s, b) +} + +/* + * Defining Abbrevs. This is hardcoded on a per-platform basis (that is, + * each platform will see a fixed abbrev table for all objects); the number + * of abbrev entries is fairly small (compared to C++ objects). The DWARF + * spec places no restriction on the ordering of attributes in the + * Abbrevs and DIEs, and we will always write them out in the order + * of declaration in the abbrev. + */ +type dwAttrForm struct { + attr uint16 + form uint8 +} + +// Go-specific type attributes. +const ( + DW_AT_go_kind = 0x2900 + DW_AT_go_key = 0x2901 + DW_AT_go_elem = 0x2902 + // Attribute for DW_TAG_member of a struct type. + // Nonzero value indicates the struct field is an embedded field. + DW_AT_go_embedded_field = 0x2903 + DW_AT_go_runtime_type = 0x2904 + + DW_AT_go_package_name = 0x2905 // Attribute for DW_TAG_compile_unit + + DW_AT_internal_location = 253 // params and locals; not emitted +) + +// Index into the abbrevs table below. +// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go. +// ispubtype considers >= NULLTYPE public +const ( + DW_ABRV_NULL = iota + DW_ABRV_COMPUNIT + DW_ABRV_COMPUNIT_TEXTLESS + DW_ABRV_FUNCTION + DW_ABRV_FUNCTION_ABSTRACT + DW_ABRV_FUNCTION_CONCRETE + DW_ABRV_INLINED_SUBROUTINE + DW_ABRV_INLINED_SUBROUTINE_RANGES + DW_ABRV_VARIABLE + DW_ABRV_INT_CONSTANT + DW_ABRV_AUTO + DW_ABRV_AUTO_LOCLIST + DW_ABRV_AUTO_ABSTRACT + DW_ABRV_AUTO_CONCRETE + DW_ABRV_AUTO_CONCRETE_LOCLIST + DW_ABRV_PARAM + DW_ABRV_PARAM_LOCLIST + DW_ABRV_PARAM_ABSTRACT + DW_ABRV_PARAM_CONCRETE + DW_ABRV_PARAM_CONCRETE_LOCLIST + DW_ABRV_LEXICAL_BLOCK_RANGES + DW_ABRV_LEXICAL_BLOCK_SIMPLE + DW_ABRV_STRUCTFIELD + DW_ABRV_FUNCTYPEPARAM + DW_ABRV_DOTDOTDOT + DW_ABRV_ARRAYRANGE + DW_ABRV_NULLTYPE + DW_ABRV_BASETYPE + DW_ABRV_ARRAYTYPE + DW_ABRV_CHANTYPE + DW_ABRV_FUNCTYPE + DW_ABRV_IFACETYPE + DW_ABRV_MAPTYPE + DW_ABRV_PTRTYPE + DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6. + DW_ABRV_SLICETYPE + DW_ABRV_STRINGTYPE + DW_ABRV_STRUCTTYPE + DW_ABRV_TYPEDECL + DW_NABRV +) + +type dwAbbrev struct { + tag uint8 + children uint8 + attr []dwAttrForm +} + +var abbrevsFinalized bool + +// expandPseudoForm takes an input DW_FORM_xxx value and translates it +// into a platform-appropriate concrete form. Existing concrete/real +// DW_FORM values are left untouched. For the moment the only +// pseudo-form is DW_FORM_udata_pseudo, which gets expanded to +// DW_FORM_data4 on Darwin and DW_FORM_udata everywhere else. See +// issue #31459 for more context. +func expandPseudoForm(form uint8) uint8 { + // Is this a pseudo-form? + if form != DW_FORM_udata_pseudo { + return form + } + expandedForm := DW_FORM_udata + if objabi.GOOS == "darwin" { + expandedForm = DW_FORM_data4 + } + return uint8(expandedForm) +} + +// Abbrevs() returns the finalized abbrev array for the platform, +// expanding any DW_FORM pseudo-ops to real values. +func Abbrevs() []dwAbbrev { + if abbrevsFinalized { + return abbrevs[:] + } + for i := 1; i < DW_NABRV; i++ { + for j := 0; j < len(abbrevs[i].attr); j++ { + abbrevs[i].attr[j].form = expandPseudoForm(abbrevs[i].attr[j].form) + } + } + abbrevsFinalized = true + return abbrevs[:] +} + +// abbrevs is a raw table of abbrev entries; it needs to be post-processed +// by the Abbrevs() function above prior to being consumed, to expand +// the 'pseudo-form' entries below to real DWARF form values. + +var abbrevs = [DW_NABRV]dwAbbrev{ + /* The mandatory DW_ABRV_NULL entry. */ + {0, 0, []dwAttrForm{}}, + + /* COMPUNIT */ + { + DW_TAG_compile_unit, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_language, DW_FORM_data1}, + {DW_AT_stmt_list, DW_FORM_sec_offset}, + {DW_AT_low_pc, DW_FORM_addr}, + {DW_AT_ranges, DW_FORM_sec_offset}, + {DW_AT_comp_dir, DW_FORM_string}, + {DW_AT_producer, DW_FORM_string}, + {DW_AT_go_package_name, DW_FORM_string}, + }, + }, + + /* COMPUNIT_TEXTLESS */ + { + DW_TAG_compile_unit, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_language, DW_FORM_data1}, + {DW_AT_comp_dir, DW_FORM_string}, + {DW_AT_producer, DW_FORM_string}, + {DW_AT_go_package_name, DW_FORM_string}, + }, + }, + + /* FUNCTION */ + { + DW_TAG_subprogram, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_low_pc, DW_FORM_addr}, + {DW_AT_high_pc, DW_FORM_addr}, + {DW_AT_frame_base, DW_FORM_block1}, + {DW_AT_decl_file, DW_FORM_data4}, + {DW_AT_external, DW_FORM_flag}, + }, + }, + + /* FUNCTION_ABSTRACT */ + { + DW_TAG_subprogram, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_inline, DW_FORM_data1}, + {DW_AT_external, DW_FORM_flag}, + }, + }, + + /* FUNCTION_CONCRETE */ + { + DW_TAG_subprogram, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_low_pc, DW_FORM_addr}, + {DW_AT_high_pc, DW_FORM_addr}, + {DW_AT_frame_base, DW_FORM_block1}, + }, + }, + + /* INLINED_SUBROUTINE */ + { + DW_TAG_inlined_subroutine, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_low_pc, DW_FORM_addr}, + {DW_AT_high_pc, DW_FORM_addr}, + {DW_AT_call_file, DW_FORM_data4}, + {DW_AT_call_line, DW_FORM_udata_pseudo}, // pseudo-form + }, + }, + + /* INLINED_SUBROUTINE_RANGES */ + { + DW_TAG_inlined_subroutine, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_ranges, DW_FORM_sec_offset}, + {DW_AT_call_file, DW_FORM_data4}, + {DW_AT_call_line, DW_FORM_udata_pseudo}, // pseudo-form + }, + }, + + /* VARIABLE */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_location, DW_FORM_block1}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_external, DW_FORM_flag}, + }, + }, + + /* INT CONSTANT */ + { + DW_TAG_constant, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_const_value, DW_FORM_sdata}, + }, + }, + + /* AUTO */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_decl_line, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_block1}, + }, + }, + + /* AUTO_LOCLIST */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_decl_line, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_sec_offset}, + }, + }, + + /* AUTO_ABSTRACT */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_decl_line, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + }, + }, + + /* AUTO_CONCRETE */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_block1}, + }, + }, + + /* AUTO_CONCRETE_LOCLIST */ + { + DW_TAG_variable, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_sec_offset}, + }, + }, + + /* PARAM */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_variable_parameter, DW_FORM_flag}, + {DW_AT_decl_line, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_block1}, + }, + }, + + /* PARAM_LOCLIST */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_variable_parameter, DW_FORM_flag}, + {DW_AT_decl_line, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_sec_offset}, + }, + }, + + /* PARAM_ABSTRACT */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_variable_parameter, DW_FORM_flag}, + {DW_AT_type, DW_FORM_ref_addr}, + }, + }, + + /* PARAM_CONCRETE */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_block1}, + }, + }, + + /* PARAM_CONCRETE_LOCLIST */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_abstract_origin, DW_FORM_ref_addr}, + {DW_AT_location, DW_FORM_sec_offset}, + }, + }, + + /* LEXICAL_BLOCK_RANGES */ + { + DW_TAG_lexical_block, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_ranges, DW_FORM_sec_offset}, + }, + }, + + /* LEXICAL_BLOCK_SIMPLE */ + { + DW_TAG_lexical_block, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_low_pc, DW_FORM_addr}, + {DW_AT_high_pc, DW_FORM_addr}, + }, + }, + + /* STRUCTFIELD */ + { + DW_TAG_member, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_data_member_location, DW_FORM_udata}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_go_embedded_field, DW_FORM_flag}, + }, + }, + + /* FUNCTYPEPARAM */ + { + DW_TAG_formal_parameter, + DW_CHILDREN_no, + + // No name! + []dwAttrForm{ + {DW_AT_type, DW_FORM_ref_addr}, + }, + }, + + /* DOTDOTDOT */ + { + DW_TAG_unspecified_parameters, + DW_CHILDREN_no, + []dwAttrForm{}, + }, + + /* ARRAYRANGE */ + { + DW_TAG_subrange_type, + DW_CHILDREN_no, + + // No name! + []dwAttrForm{ + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_count, DW_FORM_udata}, + }, + }, + + // Below here are the types considered public by ispubtype + /* NULLTYPE */ + { + DW_TAG_unspecified_type, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + }, + }, + + /* BASETYPE */ + { + DW_TAG_base_type, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_encoding, DW_FORM_data1}, + {DW_AT_byte_size, DW_FORM_data1}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* ARRAYTYPE */ + // child is subrange with upper bound + { + DW_TAG_array_type, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_byte_size, DW_FORM_udata}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* CHANTYPE */ + { + DW_TAG_typedef, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + {DW_AT_go_elem, DW_FORM_ref_addr}, + }, + }, + + /* FUNCTYPE */ + { + DW_TAG_subroutine_type, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_byte_size, DW_FORM_udata}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* IFACETYPE */ + { + DW_TAG_typedef, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* MAPTYPE */ + { + DW_TAG_typedef, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + {DW_AT_go_key, DW_FORM_ref_addr}, + {DW_AT_go_elem, DW_FORM_ref_addr}, + }, + }, + + /* PTRTYPE */ + { + DW_TAG_pointer_type, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* BARE_PTRTYPE */ + { + DW_TAG_pointer_type, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + }, + }, + + /* SLICETYPE */ + { + DW_TAG_structure_type, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_byte_size, DW_FORM_udata}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + {DW_AT_go_elem, DW_FORM_ref_addr}, + }, + }, + + /* STRINGTYPE */ + { + DW_TAG_structure_type, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_byte_size, DW_FORM_udata}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* STRUCTTYPE */ + { + DW_TAG_structure_type, + DW_CHILDREN_yes, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_byte_size, DW_FORM_udata}, + {DW_AT_go_kind, DW_FORM_data1}, + {DW_AT_go_runtime_type, DW_FORM_addr}, + }, + }, + + /* TYPEDECL */ + { + DW_TAG_typedef, + DW_CHILDREN_no, + []dwAttrForm{ + {DW_AT_name, DW_FORM_string}, + {DW_AT_type, DW_FORM_ref_addr}, + }, + }, +} + +// GetAbbrev returns the contents of the .debug_abbrev section. +func GetAbbrev() []byte { + abbrevs := Abbrevs() + var buf []byte + for i := 1; i < DW_NABRV; i++ { + // See section 7.5.3 + buf = AppendUleb128(buf, uint64(i)) + buf = AppendUleb128(buf, uint64(abbrevs[i].tag)) + buf = append(buf, abbrevs[i].children) + for _, f := range abbrevs[i].attr { + buf = AppendUleb128(buf, uint64(f.attr)) + buf = AppendUleb128(buf, uint64(f.form)) + } + buf = append(buf, 0, 0) + } + return append(buf, 0) +} + +/* + * Debugging Information Entries and their attributes. + */ + +// DWAttr represents an attribute of a DWDie. +// +// For DW_CLS_string and _block, value should contain the length, and +// data the data, for _reference, value is 0 and data is a DWDie* to +// the referenced instance, for all others, value is the whole thing +// and data is null. +type DWAttr struct { + Link *DWAttr + Atr uint16 // DW_AT_ + Cls uint8 // DW_CLS_ + Value int64 + Data interface{} +} + +// DWDie represents a DWARF debug info entry. +type DWDie struct { + Abbrev int + Link *DWDie + Child *DWDie + Attr *DWAttr + Sym Sym +} + +func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error { + switch form { + case DW_FORM_addr: // address + // Allow nil addresses for DW_AT_go_runtime_type. + if data == nil && value == 0 { + ctxt.AddInt(s, ctxt.PtrSize(), 0) + break + } + if cls == DW_CLS_GO_TYPEREF { + ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, value) + break + } + ctxt.AddAddress(s, data, value) + + case DW_FORM_block1: // block + if cls == DW_CLS_ADDRESS { + ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize())) + ctxt.AddInt(s, 1, DW_OP_addr) + ctxt.AddAddress(s, data, 0) + break + } + + value &= 0xff + ctxt.AddInt(s, 1, value) + p := data.([]byte)[:value] + ctxt.AddBytes(s, p) + + case DW_FORM_block2: // block + value &= 0xffff + + ctxt.AddInt(s, 2, value) + p := data.([]byte)[:value] + ctxt.AddBytes(s, p) + + case DW_FORM_block4: // block + value &= 0xffffffff + + ctxt.AddInt(s, 4, value) + p := data.([]byte)[:value] + ctxt.AddBytes(s, p) + + case DW_FORM_block: // block + Uleb128put(ctxt, s, value) + + p := data.([]byte)[:value] + ctxt.AddBytes(s, p) + + case DW_FORM_data1: // constant + ctxt.AddInt(s, 1, value) + + case DW_FORM_data2: // constant + ctxt.AddInt(s, 2, value) + + case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr + if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges + ctxt.AddDWARFAddrSectionOffset(s, data, value) + break + } + ctxt.AddInt(s, 4, value) + + case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr + ctxt.AddInt(s, 8, value) + + case DW_FORM_sdata: // constant + Sleb128put(ctxt, s, value) + + case DW_FORM_udata: // constant + Uleb128put(ctxt, s, value) + + case DW_FORM_string: // string + str := data.(string) + ctxt.AddString(s, str) + // TODO(ribrdb): verify padded strings are never used and remove this + for i := int64(len(str)); i < value; i++ { + ctxt.AddInt(s, 1, 0) + } + + case DW_FORM_flag: // flag + if value != 0 { + ctxt.AddInt(s, 1, 1) + } else { + ctxt.AddInt(s, 1, 0) + } + + // As of DWARF 3 the ref_addr is always 32 bits, unless emitting a large + // (> 4 GB of debug info aka "64-bit") unit, which we don't implement. + case DW_FORM_ref_addr: // reference to a DIE in the .info section + fallthrough + case DW_FORM_sec_offset: // offset into a DWARF section other than .info + if data == nil { + return fmt.Errorf("dwarf: null reference in %d", abbrev) + } + ctxt.AddDWARFAddrSectionOffset(s, data, value) + + case DW_FORM_ref1, // reference within the compilation unit + DW_FORM_ref2, // reference + DW_FORM_ref4, // reference + DW_FORM_ref8, // reference + DW_FORM_ref_udata, // reference + + DW_FORM_strp, // string + DW_FORM_indirect: // (see Section 7.5.3) + fallthrough + default: + return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls) + } + return nil +} + +// PutAttrs writes the attributes for a DIE to symbol 's'. +// +// Note that we can (and do) add arbitrary attributes to a DIE, but +// only the ones actually listed in the Abbrev will be written out. +func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) { + abbrevs := Abbrevs() +Outer: + for _, f := range abbrevs[abbrev].attr { + for ap := attr; ap != nil; ap = ap.Link { + if ap.Atr == f.attr { + putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data) + continue Outer + } + } + + putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil) + } +} + +// HasChildren reports whether 'die' uses an abbrev that supports children. +func HasChildren(die *DWDie) bool { + abbrevs := Abbrevs() + return abbrevs[die.Abbrev].children != 0 +} + +// PutIntConst writes a DIE for an integer constant +func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) { + Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT) + putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name) + putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ) + putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil) +} + +// PutBasedRanges writes a range table to sym. All addresses in ranges are +// relative to some base address, which must be arranged by the caller +// (e.g., with a DW_AT_low_pc attribute, or in a BASE-prefixed range). +func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) { + ps := ctxt.PtrSize() + // Write ranges. + for _, r := range ranges { + ctxt.AddInt(sym, ps, r.Start) + ctxt.AddInt(sym, ps, r.End) + } + // Write trailer. + ctxt.AddInt(sym, ps, 0) + ctxt.AddInt(sym, ps, 0) +} + +// PutRanges writes a range table to s.Ranges. +// All addresses in ranges are relative to s.base. +func (s *FnState) PutRanges(ctxt Context, ranges []Range) { + ps := ctxt.PtrSize() + sym, base := s.Ranges, s.StartPC + + if s.UseBASEntries { + // Using a Base Address Selection Entry reduces the number of relocations, but + // this is not done on macOS because it is not supported by dsymutil/dwarfdump/lldb + ctxt.AddInt(sym, ps, -1) + ctxt.AddAddress(sym, base, 0) + PutBasedRanges(ctxt, sym, ranges) + return + } + + // Write ranges full of relocations + for _, r := range ranges { + ctxt.AddCURelativeAddress(sym, base, r.Start) + ctxt.AddCURelativeAddress(sym, base, r.End) + } + // Write trailer. + ctxt.AddInt(sym, ps, 0) + ctxt.AddInt(sym, ps, 0) +} + +// Return TRUE if the inlined call in the specified slot is empty, +// meaning it has a zero-length range (no instructions), and all +// of its children are empty. +func isEmptyInlinedCall(slot int, calls *InlCalls) bool { + ic := &calls.Calls[slot] + if ic.InlIndex == -2 { + return true + } + live := false + for _, k := range ic.Children { + if !isEmptyInlinedCall(k, calls) { + live = true + } + } + if len(ic.Ranges) > 0 { + live = true + } + if !live { + ic.InlIndex = -2 + } + return !live +} + +// Slot -1: return top-level inlines +// Slot >= 0: return children of that slot +func inlChildren(slot int, calls *InlCalls) []int { + var kids []int + if slot != -1 { + for _, k := range calls.Calls[slot].Children { + if !isEmptyInlinedCall(k, calls) { + kids = append(kids, k) + } + } + } else { + for k := 0; k < len(calls.Calls); k += 1 { + if calls.Calls[k].Root && !isEmptyInlinedCall(k, calls) { + kids = append(kids, k) + } + } + } + return kids +} + +func inlinedVarTable(inlcalls *InlCalls) map[*Var]bool { + vars := make(map[*Var]bool) + for _, ic := range inlcalls.Calls { + for _, v := range ic.InlVars { + vars[v] = true + } + } + return vars +} + +// The s.Scopes slice contains variables were originally part of the +// function being emitted, as well as variables that were imported +// from various callee functions during the inlining process. This +// function prunes out any variables from the latter category (since +// they will be emitted as part of DWARF inlined_subroutine DIEs) and +// then generates scopes for vars in the former category. +func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error { + if len(s.Scopes) == 0 { + return nil + } + scopes := make([]Scope, len(s.Scopes), len(s.Scopes)) + pvars := inlinedVarTable(&s.InlCalls) + for k, s := range s.Scopes { + var pruned Scope = Scope{Parent: s.Parent, Ranges: s.Ranges} + for i := 0; i < len(s.Vars); i++ { + _, found := pvars[s.Vars[i]] + if !found { + pruned.Vars = append(pruned.Vars, s.Vars[i]) + } + } + sort.Sort(byChildIndex(pruned.Vars)) + scopes[k] = pruned + } + var encbuf [20]byte + if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) { + return errors.New("multiple toplevel scopes") + } + return nil +} + +// Emit DWARF attributes and child DIEs for an 'abstract' subprogram. +// The abstract subprogram DIE for a function contains its +// location-independent attributes (name, type, etc). Other instances +// of the function (any inlined copy of it, or the single out-of-line +// 'concrete' instance) will contain a pointer back to this abstract +// DIE (as a space-saving measure, so that name/type etc doesn't have +// to be repeated for each inlined copy). +func PutAbstractFunc(ctxt Context, s *FnState) error { + + if logDwarf { + ctxt.Logf("PutAbstractFunc(%v)\n", s.Absfn) + } + + abbrev := DW_ABRV_FUNCTION_ABSTRACT + Uleb128put(ctxt, s.Absfn, int64(abbrev)) + + fullname := s.Name + if strings.HasPrefix(s.Name, "\"\".") { + // Generate a fully qualified name for the function in the + // abstract case. This is so as to avoid the need for the + // linker to process the DIE with patchDWARFName(); we can't + // allow the name attribute of an abstract subprogram DIE to + // be rewritten, since it would change the offsets of the + // child DIEs (which we're relying on in order for abstract + // origin references to work). + fullname = objabi.PathToPrefix(s.Importpath) + "." + s.Name[3:] + } + putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname) + + // DW_AT_inlined value + putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil) + + var ev int64 + if s.External { + ev = 1 + } + putattr(ctxt, s.Absfn, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0) + + // Child variables (may be empty) + var flattened []*Var + + // This slice will hold the offset in bytes for each child var DIE + // with respect to the start of the parent subprogram DIE. + var offsets []int32 + + // Scopes/vars + if len(s.Scopes) > 0 { + // For abstract subprogram DIEs we want to flatten out scope info: + // lexical scope DIEs contain range and/or hi/lo PC attributes, + // which we explicitly don't want for the abstract subprogram DIE. + pvars := inlinedVarTable(&s.InlCalls) + for _, scope := range s.Scopes { + for i := 0; i < len(scope.Vars); i++ { + _, found := pvars[scope.Vars[i]] + if found || !scope.Vars[i].IsInAbstract { + continue + } + flattened = append(flattened, scope.Vars[i]) + } + } + if len(flattened) > 0 { + sort.Sort(byChildIndex(flattened)) + + if logDwarf { + ctxt.Logf("putAbstractScope(%v): vars:", s.Info) + for i, v := range flattened { + ctxt.Logf(" %d:%s", i, v.Name) + } + ctxt.Logf("\n") + } + + // This slice will hold the offset in bytes for each child + // variable DIE with respect to the start of the parent + // subprogram DIE. + for _, v := range flattened { + offsets = append(offsets, int32(ctxt.CurrentOffset(s.Absfn))) + putAbstractVar(ctxt, s.Absfn, v) + } + } + } + ctxt.RecordChildDieOffsets(s.Absfn, flattened, offsets) + + Uleb128put(ctxt, s.Absfn, 0) + return nil +} + +// Emit DWARF attributes and child DIEs for an inlined subroutine. The +// first attribute of an inlined subroutine DIE is a reference back to +// its corresponding 'abstract' DIE (containing location-independent +// attributes such as name, type, etc). Inlined subroutine DIEs can +// have other inlined subroutine DIEs as children. +func PutInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error { + ic := s.InlCalls.Calls[callIdx] + callee := ic.AbsFunSym + + abbrev := DW_ABRV_INLINED_SUBROUTINE_RANGES + if len(ic.Ranges) == 1 { + abbrev = DW_ABRV_INLINED_SUBROUTINE + } + Uleb128put(ctxt, s.Info, int64(abbrev)) + + if logDwarf { + ctxt.Logf("PutInlinedFunc(caller=%v,callee=%v,abbrev=%d)\n", callersym, callee, abbrev) + } + + // Abstract origin. + putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee) + + if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES { + putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges) + s.PutRanges(ctxt, ic.Ranges) + } else { + st := ic.Ranges[0].Start + en := ic.Ranges[0].End + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, st, s.StartPC) + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, en, s.StartPC) + } + + // Emit call file, line attrs. + ctxt.AddFileRef(s.Info, ic.CallFile) + form := int(expandPseudoForm(DW_FORM_udata_pseudo)) + putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallLine), nil) + + // Variables associated with this inlined routine instance. + vars := ic.InlVars + sort.Sort(byChildIndex(vars)) + inlIndex := ic.InlIndex + var encbuf [20]byte + for _, v := range vars { + if !v.IsInAbstract { + continue + } + putvar(ctxt, s, v, callee, abbrev, inlIndex, encbuf[:0]) + } + + // Children of this inline. + for _, sib := range inlChildren(callIdx, &s.InlCalls) { + absfn := s.InlCalls.Calls[sib].AbsFunSym + err := PutInlinedFunc(ctxt, s, absfn, sib) + if err != nil { + return err + } + } + + Uleb128put(ctxt, s.Info, 0) + return nil +} + +// Emit DWARF attributes and child DIEs for a 'concrete' subprogram, +// meaning the out-of-line copy of a function that was inlined at some +// point during the compilation of its containing package. The first +// attribute for a concrete DIE is a reference to the 'abstract' DIE +// for the function (which holds location-independent attributes such +// as name, type), then the remainder of the attributes are specific +// to this instance (location, frame base, etc). +func PutConcreteFunc(ctxt Context, s *FnState) error { + if logDwarf { + ctxt.Logf("PutConcreteFunc(%v)\n", s.Info) + } + abbrev := DW_ABRV_FUNCTION_CONCRETE + Uleb128put(ctxt, s.Info, int64(abbrev)) + + // Abstract origin. + putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, s.Absfn) + + // Start/end PC. + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC) + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC) + + // cfa / frame base + putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa}) + + // Scopes + if err := putPrunedScopes(ctxt, s, abbrev); err != nil { + return err + } + + // Inlined subroutines. + for _, sib := range inlChildren(-1, &s.InlCalls) { + absfn := s.InlCalls.Calls[sib].AbsFunSym + err := PutInlinedFunc(ctxt, s, absfn, sib) + if err != nil { + return err + } + } + + Uleb128put(ctxt, s.Info, 0) + return nil +} + +// Emit DWARF attributes and child DIEs for a subprogram. Here +// 'default' implies that the function in question was not inlined +// when its containing package was compiled (hence there is no need to +// emit an abstract version for it to use as a base for inlined +// routine records). +func PutDefaultFunc(ctxt Context, s *FnState) error { + if logDwarf { + ctxt.Logf("PutDefaultFunc(%v)\n", s.Info) + } + abbrev := DW_ABRV_FUNCTION + Uleb128put(ctxt, s.Info, int64(abbrev)) + + // Expand '"".' to import path. + name := s.Name + if s.Importpath != "" { + name = strings.Replace(name, "\"\".", objabi.PathToPrefix(s.Importpath)+".", -1) + } + + putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name) + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC) + putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC) + putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa}) + ctxt.AddFileRef(s.Info, s.Filesym) + + var ev int64 + if s.External { + ev = 1 + } + putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0) + + // Scopes + if err := putPrunedScopes(ctxt, s, abbrev); err != nil { + return err + } + + // Inlined subroutines. + for _, sib := range inlChildren(-1, &s.InlCalls) { + absfn := s.InlCalls.Calls[sib].AbsFunSym + err := PutInlinedFunc(ctxt, s, absfn, sib) + if err != nil { + return err + } + } + + Uleb128put(ctxt, s.Info, 0) + return nil +} + +func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 { + + if logDwarf { + ctxt.Logf("putscope(%v,%d): vars:", s.Info, curscope) + for i, v := range scopes[curscope].Vars { + ctxt.Logf(" %d:%d:%s", i, v.ChildIndex, v.Name) + } + ctxt.Logf("\n") + } + + for _, v := range scopes[curscope].Vars { + putvar(ctxt, s, v, s.Absfn, fnabbrev, -1, encbuf) + } + this := curscope + curscope++ + for curscope < int32(len(scopes)) { + scope := scopes[curscope] + if scope.Parent != this { + return curscope + } + + if len(scopes[curscope].Vars) == 0 { + curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf) + continue + } + + if len(scope.Ranges) == 1 { + Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE) + putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, s.StartPC) + putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC) + } else { + Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES) + putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges) + + s.PutRanges(ctxt, scope.Ranges) + } + + curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf) + + Uleb128put(ctxt, s.Info, 0) + } + return curscope +} + +// Given a default var abbrev code, select corresponding concrete code. +func concreteVarAbbrev(varAbbrev int) int { + switch varAbbrev { + case DW_ABRV_AUTO: + return DW_ABRV_AUTO_CONCRETE + case DW_ABRV_PARAM: + return DW_ABRV_PARAM_CONCRETE + case DW_ABRV_AUTO_LOCLIST: + return DW_ABRV_AUTO_CONCRETE_LOCLIST + case DW_ABRV_PARAM_LOCLIST: + return DW_ABRV_PARAM_CONCRETE_LOCLIST + default: + panic("should never happen") + } +} + +// Pick the correct abbrev code for variable or parameter DIE. +func determineVarAbbrev(v *Var, fnabbrev int) (int, bool, bool) { + abbrev := v.Abbrev + + // If the variable was entirely optimized out, don't emit a location list; + // convert to an inline abbreviation and emit an empty location. + missing := false + switch { + case abbrev == DW_ABRV_AUTO_LOCLIST && v.PutLocationList == nil: + missing = true + abbrev = DW_ABRV_AUTO + case abbrev == DW_ABRV_PARAM_LOCLIST && v.PutLocationList == nil: + missing = true + abbrev = DW_ABRV_PARAM + } + + // Determine whether to use a concrete variable or regular variable DIE. + concrete := true + switch fnabbrev { + case DW_ABRV_FUNCTION: + concrete = false + break + case DW_ABRV_FUNCTION_CONCRETE: + // If we're emitting a concrete subprogram DIE and the variable + // in question is not part of the corresponding abstract function DIE, + // then use the default (non-concrete) abbrev for this param. + if !v.IsInAbstract { + concrete = false + } + case DW_ABRV_INLINED_SUBROUTINE, DW_ABRV_INLINED_SUBROUTINE_RANGES: + default: + panic("should never happen") + } + + // Select proper abbrev based on concrete/non-concrete + if concrete { + abbrev = concreteVarAbbrev(abbrev) + } + + return abbrev, missing, concrete +} + +func abbrevUsesLoclist(abbrev int) bool { + switch abbrev { + case DW_ABRV_AUTO_LOCLIST, DW_ABRV_AUTO_CONCRETE_LOCLIST, + DW_ABRV_PARAM_LOCLIST, DW_ABRV_PARAM_CONCRETE_LOCLIST: + return true + default: + return false + } +} + +// Emit DWARF attributes for a variable belonging to an 'abstract' subprogram. +func putAbstractVar(ctxt Context, info Sym, v *Var) { + // Remap abbrev + abbrev := v.Abbrev + switch abbrev { + case DW_ABRV_AUTO, DW_ABRV_AUTO_LOCLIST: + abbrev = DW_ABRV_AUTO_ABSTRACT + case DW_ABRV_PARAM, DW_ABRV_PARAM_LOCLIST: + abbrev = DW_ABRV_PARAM_ABSTRACT + } + + Uleb128put(ctxt, info, int64(abbrev)) + putattr(ctxt, info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(v.Name)), v.Name) + + // Isreturn attribute if this is a param + if abbrev == DW_ABRV_PARAM_ABSTRACT { + var isReturn int64 + if v.IsReturnValue { + isReturn = 1 + } + putattr(ctxt, info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil) + } + + // Line + if abbrev != DW_ABRV_PARAM_ABSTRACT { + // See issue 23374 for more on why decl line is skipped for abs params. + putattr(ctxt, info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil) + } + + // Type + putattr(ctxt, info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type) + + // Var has no children => no terminator +} + +func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, encbuf []byte) { + // Remap abbrev according to parent DIE abbrev + abbrev, missing, concrete := determineVarAbbrev(v, fnabbrev) + + Uleb128put(ctxt, s.Info, int64(abbrev)) + + // Abstract origin for concrete / inlined case + if concrete { + // Here we are making a reference to a child DIE of an abstract + // function subprogram DIE. The child DIE has no LSym, so instead + // after the call to 'putattr' below we make a call to register + // the child DIE reference. + putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, absfn) + ctxt.RecordDclReference(s.Info, absfn, int(v.ChildIndex), inlIndex) + } else { + // Var name, line for abstract and default cases + n := v.Name + putattr(ctxt, s.Info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n) + if abbrev == DW_ABRV_PARAM || abbrev == DW_ABRV_PARAM_LOCLIST || abbrev == DW_ABRV_PARAM_ABSTRACT { + var isReturn int64 + if v.IsReturnValue { + isReturn = 1 + } + putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil) + } + putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil) + putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type) + } + + if abbrevUsesLoclist(abbrev) { + putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Loc.Length(ctxt), s.Loc) + v.PutLocationList(s.Loc, s.StartPC) + } else { + loc := encbuf[:0] + switch { + case missing: + break // no location + case v.StackOffset == 0: + loc = append(loc, DW_OP_call_frame_cfa) + default: + loc = append(loc, DW_OP_fbreg) + loc = AppendSleb128(loc, int64(v.StackOffset)) + } + putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc) + } + + // Var has no children => no terminator +} + +// VarsByOffset attaches the methods of sort.Interface to []*Var, +// sorting in increasing StackOffset. +type VarsByOffset []*Var + +func (s VarsByOffset) Len() int { return len(s) } +func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset } +func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// byChildIndex implements sort.Interface for []*dwarf.Var by child index. +type byChildIndex []*Var + +func (s byChildIndex) Len() int { return len(s) } +func (s byChildIndex) Less(i, j int) bool { return s[i].ChildIndex < s[j].ChildIndex } +func (s byChildIndex) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// IsDWARFEnabledOnAIX returns true if DWARF is possible on the +// current extld. +// AIX ld doesn't support DWARF with -bnoobjreorder with version +// prior to 7.2.2. +func IsDWARFEnabledOnAIXLd(extld string) (bool, error) { + out, err := exec.Command(extld, "-Wl,-V").CombinedOutput() + if err != nil { + // The normal output should display ld version and + // then fails because ".main" is not defined: + // ld: 0711-317 ERROR: Undefined symbol: .main + if !bytes.Contains(out, []byte("0711-317")) { + return false, fmt.Errorf("%s -Wl,-V failed: %v\n%s", extld, err, out) + } + } + // gcc -Wl,-V output should be: + // /usr/bin/ld: LD X.X.X(date) + // ... + out = bytes.TrimPrefix(out, []byte("/usr/bin/ld: LD ")) + vers := string(bytes.Split(out, []byte("("))[0]) + subvers := strings.Split(vers, ".") + if len(subvers) != 3 { + return false, fmt.Errorf("cannot parse %s -Wl,-V (%s): %v\n", extld, out, err) + } + if v, err := strconv.Atoi(subvers[0]); err != nil || v < 7 { + return false, nil + } else if v > 7 { + return true, nil + } + if v, err := strconv.Atoi(subvers[1]); err != nil || v < 2 { + return false, nil + } else if v > 2 { + return true, nil + } + if v, err := strconv.Atoi(subvers[2]); err != nil || v < 2 { + return false, nil + } + return true, nil +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go new file mode 100644 index 0000000..e2716e5 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go @@ -0,0 +1,493 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dwarf + +// Cut, pasted, tr-and-awk'ed from tables in +// http://dwarfstd.org/doc/Dwarf3.pdf + +// Table 18 +const ( + DW_TAG_array_type = 0x01 + DW_TAG_class_type = 0x02 + DW_TAG_entry_point = 0x03 + DW_TAG_enumeration_type = 0x04 + DW_TAG_formal_parameter = 0x05 + DW_TAG_imported_declaration = 0x08 + DW_TAG_label = 0x0a + DW_TAG_lexical_block = 0x0b + DW_TAG_member = 0x0d + DW_TAG_pointer_type = 0x0f + DW_TAG_reference_type = 0x10 + DW_TAG_compile_unit = 0x11 + DW_TAG_string_type = 0x12 + DW_TAG_structure_type = 0x13 + DW_TAG_subroutine_type = 0x15 + DW_TAG_typedef = 0x16 + DW_TAG_union_type = 0x17 + DW_TAG_unspecified_parameters = 0x18 + DW_TAG_variant = 0x19 + DW_TAG_common_block = 0x1a + DW_TAG_common_inclusion = 0x1b + DW_TAG_inheritance = 0x1c + DW_TAG_inlined_subroutine = 0x1d + DW_TAG_module = 0x1e + DW_TAG_ptr_to_member_type = 0x1f + DW_TAG_set_type = 0x20 + DW_TAG_subrange_type = 0x21 + DW_TAG_with_stmt = 0x22 + DW_TAG_access_declaration = 0x23 + DW_TAG_base_type = 0x24 + DW_TAG_catch_block = 0x25 + DW_TAG_const_type = 0x26 + DW_TAG_constant = 0x27 + DW_TAG_enumerator = 0x28 + DW_TAG_file_type = 0x29 + DW_TAG_friend = 0x2a + DW_TAG_namelist = 0x2b + DW_TAG_namelist_item = 0x2c + DW_TAG_packed_type = 0x2d + DW_TAG_subprogram = 0x2e + DW_TAG_template_type_parameter = 0x2f + DW_TAG_template_value_parameter = 0x30 + DW_TAG_thrown_type = 0x31 + DW_TAG_try_block = 0x32 + DW_TAG_variant_part = 0x33 + DW_TAG_variable = 0x34 + DW_TAG_volatile_type = 0x35 + // Dwarf3 + DW_TAG_dwarf_procedure = 0x36 + DW_TAG_restrict_type = 0x37 + DW_TAG_interface_type = 0x38 + DW_TAG_namespace = 0x39 + DW_TAG_imported_module = 0x3a + DW_TAG_unspecified_type = 0x3b + DW_TAG_partial_unit = 0x3c + DW_TAG_imported_unit = 0x3d + DW_TAG_condition = 0x3f + DW_TAG_shared_type = 0x40 + // Dwarf4 + DW_TAG_type_unit = 0x41 + DW_TAG_rvalue_reference_type = 0x42 + DW_TAG_template_alias = 0x43 + + // User defined + DW_TAG_lo_user = 0x4080 + DW_TAG_hi_user = 0xffff +) + +// Table 19 +const ( + DW_CHILDREN_no = 0x00 + DW_CHILDREN_yes = 0x01 +) + +// Not from the spec, but logically belongs here +const ( + DW_CLS_ADDRESS = 0x01 + iota + DW_CLS_BLOCK + DW_CLS_CONSTANT + DW_CLS_FLAG + DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr + DW_CLS_REFERENCE + DW_CLS_ADDRLOC + DW_CLS_STRING + + // Go-specific internal hackery. + DW_CLS_GO_TYPEREF +) + +// Table 20 +const ( + DW_AT_sibling = 0x01 // reference + DW_AT_location = 0x02 // block, loclistptr + DW_AT_name = 0x03 // string + DW_AT_ordering = 0x09 // constant + DW_AT_byte_size = 0x0b // block, constant, reference + DW_AT_bit_offset = 0x0c // block, constant, reference + DW_AT_bit_size = 0x0d // block, constant, reference + DW_AT_stmt_list = 0x10 // lineptr + DW_AT_low_pc = 0x11 // address + DW_AT_high_pc = 0x12 // address + DW_AT_language = 0x13 // constant + DW_AT_discr = 0x15 // reference + DW_AT_discr_value = 0x16 // constant + DW_AT_visibility = 0x17 // constant + DW_AT_import = 0x18 // reference + DW_AT_string_length = 0x19 // block, loclistptr + DW_AT_common_reference = 0x1a // reference + DW_AT_comp_dir = 0x1b // string + DW_AT_const_value = 0x1c // block, constant, string + DW_AT_containing_type = 0x1d // reference + DW_AT_default_value = 0x1e // reference + DW_AT_inline = 0x20 // constant + DW_AT_is_optional = 0x21 // flag + DW_AT_lower_bound = 0x22 // block, constant, reference + DW_AT_producer = 0x25 // string + DW_AT_prototyped = 0x27 // flag + DW_AT_return_addr = 0x2a // block, loclistptr + DW_AT_start_scope = 0x2c // constant + DW_AT_bit_stride = 0x2e // constant + DW_AT_upper_bound = 0x2f // block, constant, reference + DW_AT_abstract_origin = 0x31 // reference + DW_AT_accessibility = 0x32 // constant + DW_AT_address_class = 0x33 // constant + DW_AT_artificial = 0x34 // flag + DW_AT_base_types = 0x35 // reference + DW_AT_calling_convention = 0x36 // constant + DW_AT_count = 0x37 // block, constant, reference + DW_AT_data_member_location = 0x38 // block, constant, loclistptr + DW_AT_decl_column = 0x39 // constant + DW_AT_decl_file = 0x3a // constant + DW_AT_decl_line = 0x3b // constant + DW_AT_declaration = 0x3c // flag + DW_AT_discr_list = 0x3d // block + DW_AT_encoding = 0x3e // constant + DW_AT_external = 0x3f // flag + DW_AT_frame_base = 0x40 // block, loclistptr + DW_AT_friend = 0x41 // reference + DW_AT_identifier_case = 0x42 // constant + DW_AT_macro_info = 0x43 // macptr + DW_AT_namelist_item = 0x44 // block + DW_AT_priority = 0x45 // reference + DW_AT_segment = 0x46 // block, loclistptr + DW_AT_specification = 0x47 // reference + DW_AT_static_link = 0x48 // block, loclistptr + DW_AT_type = 0x49 // reference + DW_AT_use_location = 0x4a // block, loclistptr + DW_AT_variable_parameter = 0x4b // flag + DW_AT_virtuality = 0x4c // constant + DW_AT_vtable_elem_location = 0x4d // block, loclistptr + // Dwarf3 + DW_AT_allocated = 0x4e // block, constant, reference + DW_AT_associated = 0x4f // block, constant, reference + DW_AT_data_location = 0x50 // block + DW_AT_byte_stride = 0x51 // block, constant, reference + DW_AT_entry_pc = 0x52 // address + DW_AT_use_UTF8 = 0x53 // flag + DW_AT_extension = 0x54 // reference + DW_AT_ranges = 0x55 // rangelistptr + DW_AT_trampoline = 0x56 // address, flag, reference, string + DW_AT_call_column = 0x57 // constant + DW_AT_call_file = 0x58 // constant + DW_AT_call_line = 0x59 // constant + DW_AT_description = 0x5a // string + DW_AT_binary_scale = 0x5b // constant + DW_AT_decimal_scale = 0x5c // constant + DW_AT_small = 0x5d // reference + DW_AT_decimal_sign = 0x5e // constant + DW_AT_digit_count = 0x5f // constant + DW_AT_picture_string = 0x60 // string + DW_AT_mutable = 0x61 // flag + DW_AT_threads_scaled = 0x62 // flag + DW_AT_explicit = 0x63 // flag + DW_AT_object_pointer = 0x64 // reference + DW_AT_endianity = 0x65 // constant + DW_AT_elemental = 0x66 // flag + DW_AT_pure = 0x67 // flag + DW_AT_recursive = 0x68 // flag + + DW_AT_lo_user = 0x2000 // --- + DW_AT_hi_user = 0x3fff // --- +) + +// Table 21 +const ( + DW_FORM_addr = 0x01 // address + DW_FORM_block2 = 0x03 // block + DW_FORM_block4 = 0x04 // block + DW_FORM_data2 = 0x05 // constant + DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr + DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr + DW_FORM_string = 0x08 // string + DW_FORM_block = 0x09 // block + DW_FORM_block1 = 0x0a // block + DW_FORM_data1 = 0x0b // constant + DW_FORM_flag = 0x0c // flag + DW_FORM_sdata = 0x0d // constant + DW_FORM_strp = 0x0e // string + DW_FORM_udata = 0x0f // constant + DW_FORM_ref_addr = 0x10 // reference + DW_FORM_ref1 = 0x11 // reference + DW_FORM_ref2 = 0x12 // reference + DW_FORM_ref4 = 0x13 // reference + DW_FORM_ref8 = 0x14 // reference + DW_FORM_ref_udata = 0x15 // reference + DW_FORM_indirect = 0x16 // (see Section 7.5.3) + // Dwarf4 + DW_FORM_sec_offset = 0x17 // lineptr, loclistptr, macptr, rangelistptr + DW_FORM_exprloc = 0x18 // exprloc + DW_FORM_flag_present = 0x19 // flag + DW_FORM_ref_sig8 = 0x20 // reference + // Pseudo-form: expanded to data4 on IOS, udata elsewhere. + DW_FORM_udata_pseudo = 0x99 +) + +// Table 24 (#operands, notes) +const ( + DW_OP_addr = 0x03 // 1 constant address (size target specific) + DW_OP_deref = 0x06 // 0 + DW_OP_const1u = 0x08 // 1 1-byte constant + DW_OP_const1s = 0x09 // 1 1-byte constant + DW_OP_const2u = 0x0a // 1 2-byte constant + DW_OP_const2s = 0x0b // 1 2-byte constant + DW_OP_const4u = 0x0c // 1 4-byte constant + DW_OP_const4s = 0x0d // 1 4-byte constant + DW_OP_const8u = 0x0e // 1 8-byte constant + DW_OP_const8s = 0x0f // 1 8-byte constant + DW_OP_constu = 0x10 // 1 ULEB128 constant + DW_OP_consts = 0x11 // 1 SLEB128 constant + DW_OP_dup = 0x12 // 0 + DW_OP_drop = 0x13 // 0 + DW_OP_over = 0x14 // 0 + DW_OP_pick = 0x15 // 1 1-byte stack index + DW_OP_swap = 0x16 // 0 + DW_OP_rot = 0x17 // 0 + DW_OP_xderef = 0x18 // 0 + DW_OP_abs = 0x19 // 0 + DW_OP_and = 0x1a // 0 + DW_OP_div = 0x1b // 0 + DW_OP_minus = 0x1c // 0 + DW_OP_mod = 0x1d // 0 + DW_OP_mul = 0x1e // 0 + DW_OP_neg = 0x1f // 0 + DW_OP_not = 0x20 // 0 + DW_OP_or = 0x21 // 0 + DW_OP_plus = 0x22 // 0 + DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend + DW_OP_shl = 0x24 // 0 + DW_OP_shr = 0x25 // 0 + DW_OP_shra = 0x26 // 0 + DW_OP_xor = 0x27 // 0 + DW_OP_skip = 0x2f // 1 signed 2-byte constant + DW_OP_bra = 0x28 // 1 signed 2-byte constant + DW_OP_eq = 0x29 // 0 + DW_OP_ge = 0x2a // 0 + DW_OP_gt = 0x2b // 0 + DW_OP_le = 0x2c // 0 + DW_OP_lt = 0x2d // 0 + DW_OP_ne = 0x2e // 0 + DW_OP_lit0 = 0x30 // 0 ... + DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal) + DW_OP_reg0 = 0x50 // 0 .. + DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum) + DW_OP_breg0 = 0x70 // 1 ... + DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum) + DW_OP_regx = 0x90 // 1 ULEB128 register + DW_OP_fbreg = 0x91 // 1 SLEB128 offset + DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset + DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed + DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved + DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved + DW_OP_nop = 0x96 // 0 + DW_OP_push_object_address = 0x97 // 0 + DW_OP_call2 = 0x98 // 1 2-byte offset of DIE + DW_OP_call4 = 0x99 // 1 4-byte offset of DIE + DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE + DW_OP_form_tls_address = 0x9b // 0 + DW_OP_call_frame_cfa = 0x9c // 0 + DW_OP_bit_piece = 0x9d // 2 + DW_OP_lo_user = 0xe0 + DW_OP_hi_user = 0xff +) + +// Table 25 +const ( + DW_ATE_address = 0x01 + DW_ATE_boolean = 0x02 + DW_ATE_complex_float = 0x03 + DW_ATE_float = 0x04 + DW_ATE_signed = 0x05 + DW_ATE_signed_char = 0x06 + DW_ATE_unsigned = 0x07 + DW_ATE_unsigned_char = 0x08 + DW_ATE_imaginary_float = 0x09 + DW_ATE_packed_decimal = 0x0a + DW_ATE_numeric_string = 0x0b + DW_ATE_edited = 0x0c + DW_ATE_signed_fixed = 0x0d + DW_ATE_unsigned_fixed = 0x0e + DW_ATE_decimal_float = 0x0f + DW_ATE_lo_user = 0x80 + DW_ATE_hi_user = 0xff +) + +// Table 26 +const ( + DW_DS_unsigned = 0x01 + DW_DS_leading_overpunch = 0x02 + DW_DS_trailing_overpunch = 0x03 + DW_DS_leading_separate = 0x04 + DW_DS_trailing_separate = 0x05 +) + +// Table 27 +const ( + DW_END_default = 0x00 + DW_END_big = 0x01 + DW_END_little = 0x02 + DW_END_lo_user = 0x40 + DW_END_hi_user = 0xff +) + +// Table 28 +const ( + DW_ACCESS_public = 0x01 + DW_ACCESS_protected = 0x02 + DW_ACCESS_private = 0x03 +) + +// Table 29 +const ( + DW_VIS_local = 0x01 + DW_VIS_exported = 0x02 + DW_VIS_qualified = 0x03 +) + +// Table 30 +const ( + DW_VIRTUALITY_none = 0x00 + DW_VIRTUALITY_virtual = 0x01 + DW_VIRTUALITY_pure_virtual = 0x02 +) + +// Table 31 +const ( + DW_LANG_C89 = 0x0001 + DW_LANG_C = 0x0002 + DW_LANG_Ada83 = 0x0003 + DW_LANG_C_plus_plus = 0x0004 + DW_LANG_Cobol74 = 0x0005 + DW_LANG_Cobol85 = 0x0006 + DW_LANG_Fortran77 = 0x0007 + DW_LANG_Fortran90 = 0x0008 + DW_LANG_Pascal83 = 0x0009 + DW_LANG_Modula2 = 0x000a + // Dwarf3 + DW_LANG_Java = 0x000b + DW_LANG_C99 = 0x000c + DW_LANG_Ada95 = 0x000d + DW_LANG_Fortran95 = 0x000e + DW_LANG_PLI = 0x000f + DW_LANG_ObjC = 0x0010 + DW_LANG_ObjC_plus_plus = 0x0011 + DW_LANG_UPC = 0x0012 + DW_LANG_D = 0x0013 + // Dwarf4 + DW_LANG_Python = 0x0014 + // Dwarf5 + DW_LANG_Go = 0x0016 + + DW_LANG_lo_user = 0x8000 + DW_LANG_hi_user = 0xffff +) + +// Table 32 +const ( + DW_ID_case_sensitive = 0x00 + DW_ID_up_case = 0x01 + DW_ID_down_case = 0x02 + DW_ID_case_insensitive = 0x03 +) + +// Table 33 +const ( + DW_CC_normal = 0x01 + DW_CC_program = 0x02 + DW_CC_nocall = 0x03 + DW_CC_lo_user = 0x40 + DW_CC_hi_user = 0xff +) + +// Table 34 +const ( + DW_INL_not_inlined = 0x00 + DW_INL_inlined = 0x01 + DW_INL_declared_not_inlined = 0x02 + DW_INL_declared_inlined = 0x03 +) + +// Table 35 +const ( + DW_ORD_row_major = 0x00 + DW_ORD_col_major = 0x01 +) + +// Table 36 +const ( + DW_DSC_label = 0x00 + DW_DSC_range = 0x01 +) + +// Table 37 +const ( + DW_LNS_copy = 0x01 + DW_LNS_advance_pc = 0x02 + DW_LNS_advance_line = 0x03 + DW_LNS_set_file = 0x04 + DW_LNS_set_column = 0x05 + DW_LNS_negate_stmt = 0x06 + DW_LNS_set_basic_block = 0x07 + DW_LNS_const_add_pc = 0x08 + DW_LNS_fixed_advance_pc = 0x09 + // Dwarf3 + DW_LNS_set_prologue_end = 0x0a + DW_LNS_set_epilogue_begin = 0x0b + DW_LNS_set_isa = 0x0c +) + +// Table 38 +const ( + DW_LNE_end_sequence = 0x01 + DW_LNE_set_address = 0x02 + DW_LNE_define_file = 0x03 + DW_LNE_lo_user = 0x80 + DW_LNE_hi_user = 0xff +) + +// Table 39 +const ( + DW_MACINFO_define = 0x01 + DW_MACINFO_undef = 0x02 + DW_MACINFO_start_file = 0x03 + DW_MACINFO_end_file = 0x04 + DW_MACINFO_vendor_ext = 0xff +) + +// Table 40. +const ( + // operand,... + DW_CFA_nop = 0x00 + DW_CFA_set_loc = 0x01 // address + DW_CFA_advance_loc1 = 0x02 // 1-byte delta + DW_CFA_advance_loc2 = 0x03 // 2-byte delta + DW_CFA_advance_loc4 = 0x04 // 4-byte delta + DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset + DW_CFA_restore_extended = 0x06 // ULEB128 register + DW_CFA_undefined = 0x07 // ULEB128 register + DW_CFA_same_value = 0x08 // ULEB128 register + DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register + DW_CFA_remember_state = 0x0a + DW_CFA_restore_state = 0x0b + + DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset + DW_CFA_def_cfa_register = 0x0d // ULEB128 register + DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset + DW_CFA_def_cfa_expression = 0x0f // BLOCK + DW_CFA_expression = 0x10 // ULEB128 register, BLOCK + DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset + DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset + DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset + DW_CFA_val_offset = 0x14 // ULEB128, ULEB128 + DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128 + DW_CFA_val_expression = 0x16 // ULEB128, BLOCK + + DW_CFA_lo_user = 0x1c + DW_CFA_hi_user = 0x3f + + // Opcodes that take an addend operand. + DW_CFA_advance_loc = 0x1 << 6 // +delta + DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset) + DW_CFA_restore = 0x3 << 6 // +register +) diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go new file mode 100644 index 0000000..e7d612a --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go @@ -0,0 +1,45 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goobj + +// Builtin (compiler-generated) function references appear +// frequently. We assign special indices for them, so they +// don't need to be referenced by name. + +// NBuiltin returns the number of listed builtin +// symbols. +func NBuiltin() int { + return len(builtins) +} + +// BuiltinName returns the name and ABI of the i-th +// builtin symbol. +func BuiltinName(i int) (string, int) { + return builtins[i].name, builtins[i].abi +} + +// BuiltinIdx returns the index of the builtin with the +// given name and abi, or -1 if it is not a builtin. +func BuiltinIdx(name string, abi int) int { + i, ok := builtinMap[name] + if !ok { + return -1 + } + if builtins[i].abi != abi { + return -1 + } + return i +} + +//go:generate go run mkbuiltin.go + +var builtinMap map[string]int + +func init() { + builtinMap = make(map[string]int, len(builtins)) + for i, b := range builtins { + builtinMap[b.name] = i + } +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go new file mode 100644 index 0000000..0cca752 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go @@ -0,0 +1,245 @@ +// Code generated by mkbuiltin.go. DO NOT EDIT. + +package goobj + +var builtins = [...]struct { + name string + abi int +}{ + {"runtime.newobject", 1}, + {"runtime.mallocgc", 1}, + {"runtime.panicdivide", 1}, + {"runtime.panicshift", 1}, + {"runtime.panicmakeslicelen", 1}, + {"runtime.panicmakeslicecap", 1}, + {"runtime.throwinit", 1}, + {"runtime.panicwrap", 1}, + {"runtime.gopanic", 1}, + {"runtime.gorecover", 1}, + {"runtime.goschedguarded", 1}, + {"runtime.goPanicIndex", 1}, + {"runtime.goPanicIndexU", 1}, + {"runtime.goPanicSliceAlen", 1}, + {"runtime.goPanicSliceAlenU", 1}, + {"runtime.goPanicSliceAcap", 1}, + {"runtime.goPanicSliceAcapU", 1}, + {"runtime.goPanicSliceB", 1}, + {"runtime.goPanicSliceBU", 1}, + {"runtime.goPanicSlice3Alen", 1}, + {"runtime.goPanicSlice3AlenU", 1}, + {"runtime.goPanicSlice3Acap", 1}, + {"runtime.goPanicSlice3AcapU", 1}, + {"runtime.goPanicSlice3B", 1}, + {"runtime.goPanicSlice3BU", 1}, + {"runtime.goPanicSlice3C", 1}, + {"runtime.goPanicSlice3CU", 1}, + {"runtime.printbool", 1}, + {"runtime.printfloat", 1}, + {"runtime.printint", 1}, + {"runtime.printhex", 1}, + {"runtime.printuint", 1}, + {"runtime.printcomplex", 1}, + {"runtime.printstring", 1}, + {"runtime.printpointer", 1}, + {"runtime.printiface", 1}, + {"runtime.printeface", 1}, + {"runtime.printslice", 1}, + {"runtime.printnl", 1}, + {"runtime.printsp", 1}, + {"runtime.printlock", 1}, + {"runtime.printunlock", 1}, + {"runtime.concatstring2", 1}, + {"runtime.concatstring3", 1}, + {"runtime.concatstring4", 1}, + {"runtime.concatstring5", 1}, + {"runtime.concatstrings", 1}, + {"runtime.cmpstring", 1}, + {"runtime.intstring", 1}, + {"runtime.slicebytetostring", 1}, + {"runtime.slicebytetostringtmp", 1}, + {"runtime.slicerunetostring", 1}, + {"runtime.stringtoslicebyte", 1}, + {"runtime.stringtoslicerune", 1}, + {"runtime.slicecopy", 1}, + {"runtime.slicestringcopy", 1}, + {"runtime.decoderune", 1}, + {"runtime.countrunes", 1}, + {"runtime.convI2I", 1}, + {"runtime.convT16", 1}, + {"runtime.convT32", 1}, + {"runtime.convT64", 1}, + {"runtime.convTstring", 1}, + {"runtime.convTslice", 1}, + {"runtime.convT2E", 1}, + {"runtime.convT2Enoptr", 1}, + {"runtime.convT2I", 1}, + {"runtime.convT2Inoptr", 1}, + {"runtime.assertE2I", 1}, + {"runtime.assertE2I2", 1}, + {"runtime.assertI2I", 1}, + {"runtime.assertI2I2", 1}, + {"runtime.panicdottypeE", 1}, + {"runtime.panicdottypeI", 1}, + {"runtime.panicnildottype", 1}, + {"runtime.ifaceeq", 1}, + {"runtime.efaceeq", 1}, + {"runtime.fastrand", 1}, + {"runtime.makemap64", 1}, + {"runtime.makemap", 1}, + {"runtime.makemap_small", 1}, + {"runtime.mapaccess1", 1}, + {"runtime.mapaccess1_fast32", 1}, + {"runtime.mapaccess1_fast64", 1}, + {"runtime.mapaccess1_faststr", 1}, + {"runtime.mapaccess1_fat", 1}, + {"runtime.mapaccess2", 1}, + {"runtime.mapaccess2_fast32", 1}, + {"runtime.mapaccess2_fast64", 1}, + {"runtime.mapaccess2_faststr", 1}, + {"runtime.mapaccess2_fat", 1}, + {"runtime.mapassign", 1}, + {"runtime.mapassign_fast32", 1}, + {"runtime.mapassign_fast32ptr", 1}, + {"runtime.mapassign_fast64", 1}, + {"runtime.mapassign_fast64ptr", 1}, + {"runtime.mapassign_faststr", 1}, + {"runtime.mapiterinit", 1}, + {"runtime.mapdelete", 1}, + {"runtime.mapdelete_fast32", 1}, + {"runtime.mapdelete_fast64", 1}, + {"runtime.mapdelete_faststr", 1}, + {"runtime.mapiternext", 1}, + {"runtime.mapclear", 1}, + {"runtime.makechan64", 1}, + {"runtime.makechan", 1}, + {"runtime.chanrecv1", 1}, + {"runtime.chanrecv2", 1}, + {"runtime.chansend1", 1}, + {"runtime.closechan", 1}, + {"runtime.writeBarrier", 0}, + {"runtime.typedmemmove", 1}, + {"runtime.typedmemclr", 1}, + {"runtime.typedslicecopy", 1}, + {"runtime.selectnbsend", 1}, + {"runtime.selectnbrecv", 1}, + {"runtime.selectnbrecv2", 1}, + {"runtime.selectsetpc", 1}, + {"runtime.selectgo", 1}, + {"runtime.block", 1}, + {"runtime.makeslice", 1}, + {"runtime.makeslice64", 1}, + {"runtime.makeslicecopy", 1}, + {"runtime.growslice", 1}, + {"runtime.memmove", 1}, + {"runtime.memclrNoHeapPointers", 1}, + {"runtime.memclrHasPointers", 1}, + {"runtime.memequal", 1}, + {"runtime.memequal0", 1}, + {"runtime.memequal8", 1}, + {"runtime.memequal16", 1}, + {"runtime.memequal32", 1}, + {"runtime.memequal64", 1}, + {"runtime.memequal128", 1}, + {"runtime.f32equal", 1}, + {"runtime.f64equal", 1}, + {"runtime.c64equal", 1}, + {"runtime.c128equal", 1}, + {"runtime.strequal", 1}, + {"runtime.interequal", 1}, + {"runtime.nilinterequal", 1}, + {"runtime.memhash", 1}, + {"runtime.memhash0", 1}, + {"runtime.memhash8", 1}, + {"runtime.memhash16", 1}, + {"runtime.memhash32", 1}, + {"runtime.memhash64", 1}, + {"runtime.memhash128", 1}, + {"runtime.f32hash", 1}, + {"runtime.f64hash", 1}, + {"runtime.c64hash", 1}, + {"runtime.c128hash", 1}, + {"runtime.strhash", 1}, + {"runtime.interhash", 1}, + {"runtime.nilinterhash", 1}, + {"runtime.int64div", 1}, + {"runtime.uint64div", 1}, + {"runtime.int64mod", 1}, + {"runtime.uint64mod", 1}, + {"runtime.float64toint64", 1}, + {"runtime.float64touint64", 1}, + {"runtime.float64touint32", 1}, + {"runtime.int64tofloat64", 1}, + {"runtime.uint64tofloat64", 1}, + {"runtime.uint32tofloat64", 1}, + {"runtime.complex128div", 1}, + {"runtime.racefuncenter", 1}, + {"runtime.racefuncenterfp", 1}, + {"runtime.racefuncexit", 1}, + {"runtime.raceread", 1}, + {"runtime.racewrite", 1}, + {"runtime.racereadrange", 1}, + {"runtime.racewriterange", 1}, + {"runtime.msanread", 1}, + {"runtime.msanwrite", 1}, + {"runtime.checkptrAlignment", 1}, + {"runtime.checkptrArithmetic", 1}, + {"runtime.libfuzzerTraceCmp1", 1}, + {"runtime.libfuzzerTraceCmp2", 1}, + {"runtime.libfuzzerTraceCmp4", 1}, + {"runtime.libfuzzerTraceCmp8", 1}, + {"runtime.libfuzzerTraceConstCmp1", 1}, + {"runtime.libfuzzerTraceConstCmp2", 1}, + {"runtime.libfuzzerTraceConstCmp4", 1}, + {"runtime.libfuzzerTraceConstCmp8", 1}, + {"runtime.x86HasPOPCNT", 0}, + {"runtime.x86HasSSE41", 0}, + {"runtime.x86HasFMA", 0}, + {"runtime.armHasVFPv4", 0}, + {"runtime.arm64HasATOMICS", 0}, + {"runtime.deferproc", 1}, + {"runtime.deferprocStack", 1}, + {"runtime.deferreturn", 1}, + {"runtime.newproc", 1}, + {"runtime.panicoverflow", 1}, + {"runtime.sigpanic", 1}, + {"runtime.gcWriteBarrier", 0}, + {"runtime.morestack", 0}, + {"runtime.morestackc", 0}, + {"runtime.morestack_noctxt", 0}, + {"type.int8", 0}, + {"type.*int8", 0}, + {"type.uint8", 0}, + {"type.*uint8", 0}, + {"type.int16", 0}, + {"type.*int16", 0}, + {"type.uint16", 0}, + {"type.*uint16", 0}, + {"type.int32", 0}, + {"type.*int32", 0}, + {"type.uint32", 0}, + {"type.*uint32", 0}, + {"type.int64", 0}, + {"type.*int64", 0}, + {"type.uint64", 0}, + {"type.*uint64", 0}, + {"type.float32", 0}, + {"type.*float32", 0}, + {"type.float64", 0}, + {"type.*float64", 0}, + {"type.complex64", 0}, + {"type.*complex64", 0}, + {"type.complex128", 0}, + {"type.*complex128", 0}, + {"type.unsafe.Pointer", 0}, + {"type.*unsafe.Pointer", 0}, + {"type.uintptr", 0}, + {"type.*uintptr", 0}, + {"type.bool", 0}, + {"type.*bool", 0}, + {"type.string", 0}, + {"type.*string", 0}, + {"type.error", 0}, + {"type.*error", 0}, + {"type.func(error) string", 0}, + {"type.*func(error) string", 0}, +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go new file mode 100644 index 0000000..9e19233 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go @@ -0,0 +1,233 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goobj + +import ( + "bytes" + "github.com/twitchyliquid64/golang-asm/objabi" + "encoding/binary" +) + +// CUFileIndex is used to index the filenames that are stored in the +// per-package/per-CU FileList. +type CUFileIndex uint32 + +// FuncInfo is serialized as a symbol (aux symbol). The symbol data is +// the binary encoding of the struct below. +// +// TODO: make each pcdata a separate symbol? +type FuncInfo struct { + Args uint32 + Locals uint32 + FuncID objabi.FuncID + + Pcsp uint32 + Pcfile uint32 + Pcline uint32 + Pcinline uint32 + Pcdata []uint32 + PcdataEnd uint32 + Funcdataoff []uint32 + File []CUFileIndex + + InlTree []InlTreeNode +} + +func (a *FuncInfo) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + + writeUint32(a.Args) + writeUint32(a.Locals) + writeUint32(uint32(a.FuncID)) + + writeUint32(a.Pcsp) + writeUint32(a.Pcfile) + writeUint32(a.Pcline) + writeUint32(a.Pcinline) + writeUint32(uint32(len(a.Pcdata))) + for _, x := range a.Pcdata { + writeUint32(x) + } + writeUint32(a.PcdataEnd) + writeUint32(uint32(len(a.Funcdataoff))) + for _, x := range a.Funcdataoff { + writeUint32(x) + } + writeUint32(uint32(len(a.File))) + for _, f := range a.File { + writeUint32(uint32(f)) + } + writeUint32(uint32(len(a.InlTree))) + for i := range a.InlTree { + a.InlTree[i].Write(w) + } +} + +func (a *FuncInfo) Read(b []byte) { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + + a.Args = readUint32() + a.Locals = readUint32() + a.FuncID = objabi.FuncID(readUint32()) + + a.Pcsp = readUint32() + a.Pcfile = readUint32() + a.Pcline = readUint32() + a.Pcinline = readUint32() + pcdatalen := readUint32() + a.Pcdata = make([]uint32, pcdatalen) + for i := range a.Pcdata { + a.Pcdata[i] = readUint32() + } + a.PcdataEnd = readUint32() + funcdataofflen := readUint32() + a.Funcdataoff = make([]uint32, funcdataofflen) + for i := range a.Funcdataoff { + a.Funcdataoff[i] = readUint32() + } + filelen := readUint32() + a.File = make([]CUFileIndex, filelen) + for i := range a.File { + a.File[i] = CUFileIndex(readUint32()) + } + inltreelen := readUint32() + a.InlTree = make([]InlTreeNode, inltreelen) + for i := range a.InlTree { + b = a.InlTree[i].Read(b) + } +} + +// FuncInfoLengths is a cache containing a roadmap of offsets and +// lengths for things within a serialized FuncInfo. Each length field +// stores the number of items (e.g. files, inltree nodes, etc), and the +// corresponding "off" field stores the byte offset of the start of +// the items in question. +type FuncInfoLengths struct { + NumPcdata uint32 + PcdataOff uint32 + NumFuncdataoff uint32 + FuncdataoffOff uint32 + NumFile uint32 + FileOff uint32 + NumInlTree uint32 + InlTreeOff uint32 + Initialized bool +} + +func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths { + var result FuncInfoLengths + + const numpcdataOff = 28 + result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:]) + result.PcdataOff = numpcdataOff + 4 + + numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1) + result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:]) + result.FuncdataoffOff = numfuncdataoffOff + 4 + + numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff + result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:]) + result.FileOff = numfileOff + 4 + + numinltreeOff := result.FileOff + 4*result.NumFile + result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:]) + result.InlTreeOff = numinltreeOff + 4 + + result.Initialized = true + + return result +} + +func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) } + +func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) } + +// return start and end offsets. +func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) { + return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) { + return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) { + return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) { + return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) { + return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:]) +} + +func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 { + return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:])) +} + +func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex { + return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:])) +} + +func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode { + const inlTreeNodeSize = 4 * 6 + var result InlTreeNode + result.Read(b[inltreeoff+k*inlTreeNodeSize:]) + return result +} + +// InlTreeNode is the serialized form of FileInfo.InlTree. +type InlTreeNode struct { + Parent int32 + File CUFileIndex + Line int32 + Func SymRef + ParentPC int32 +} + +func (inl *InlTreeNode) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + writeUint32(uint32(inl.Parent)) + writeUint32(uint32(inl.File)) + writeUint32(uint32(inl.Line)) + writeUint32(inl.Func.PkgIdx) + writeUint32(inl.Func.SymIdx) + writeUint32(uint32(inl.ParentPC)) +} + +// Read an InlTreeNode from b, return the remaining bytes. +func (inl *InlTreeNode) Read(b []byte) []byte { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + inl.Parent = int32(readUint32()) + inl.File = CUFileIndex(readUint32()) + inl.Line = int32(readUint32()) + inl.Func = SymRef{readUint32(), readUint32()} + inl.ParentPC = int32(readUint32()) + return b +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go new file mode 100644 index 0000000..3303549 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go @@ -0,0 +1,871 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This package defines the Go object file format, and provide "low-level" functions +// for reading and writing object files. + +// The object file is understood by the compiler, assembler, linker, and tools. They +// have "high level" code that operates on object files, handling application-specific +// logics, and use this package for the actual reading and writing. Specifically, the +// code below: +// +// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile) +// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump) +// - cmd/link/internal/loader package (used by cmd/link) +// +// If the object file format changes, they may (or may not) need to change. + +package goobj + +import ( + "bytes" + "github.com/twitchyliquid64/golang-asm/bio" + "crypto/sha1" + "encoding/binary" + "errors" + "fmt" + "github.com/twitchyliquid64/golang-asm/unsafeheader" + "io" + "unsafe" +) + +// New object file format. +// +// Header struct { +// Magic [...]byte // "\x00go116ld" +// Fingerprint [8]byte +// Flags uint32 +// Offsets [...]uint32 // byte offset of each block below +// } +// +// Strings [...]struct { +// Data [...]byte +// } +// +// Autolib [...]struct { // imported packages (for file loading) +// Pkg string +// Fingerprint [8]byte +// } +// +// PkgIndex [...]string // referenced packages by index +// +// Files [...]string +// +// SymbolDefs [...]struct { +// Name string +// ABI uint16 +// Type uint8 +// Flag uint8 +// Flag2 uint8 +// Size uint32 +// } +// Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions +// ... // same as SymbolDefs +// } +// HashedDefs [...]struct { // hashed (content-addressable) symbol definitions +// ... // same as SymbolDefs +// } +// NonPkgDefs [...]struct { // non-pkg symbol definitions +// ... // same as SymbolDefs +// } +// NonPkgRefs [...]struct { // non-pkg symbol references +// ... // same as SymbolDefs +// } +// +// RefFlags [...]struct { // referenced symbol flags +// Sym symRef +// Flag uint8 +// Flag2 uint8 +// } +// +// Hash64 [...][8]byte +// Hash [...][N]byte +// +// RelocIndex [...]uint32 // index to Relocs +// AuxIndex [...]uint32 // index to Aux +// DataIndex [...]uint32 // offset to Data +// +// Relocs [...]struct { +// Off int32 +// Size uint8 +// Type uint8 +// Add int64 +// Sym symRef +// } +// +// Aux [...]struct { +// Type uint8 +// Sym symRef +// } +// +// Data [...]byte +// Pcdata [...]byte +// +// // blocks only used by tools (objdump, nm) +// +// RefNames [...]struct { // referenced symbol names +// Sym symRef +// Name string +// // TODO: include ABI version as well? +// } +// +// string is encoded as is a uint32 length followed by a uint32 offset +// that points to the corresponding string bytes. +// +// symRef is struct { PkgIdx, SymIdx uint32 }. +// +// Slice type (e.g. []symRef) is encoded as a length prefix (uint32) +// followed by that number of elements. +// +// The types below correspond to the encoded data structure in the +// object file. + +// Symbol indexing. +// +// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx }, +// as the symRef struct above. +// +// PkgIdx is either a predeclared index (see PkgIdxNone below) or +// an index of an imported package. For the latter case, PkgIdx is the +// index of the package in the PkgIndex array. 0 is an invalid index. +// +// SymIdx is the index of the symbol in the given package. +// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the +// SymbolDefs array. +// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the +// Hashed64Defs array. +// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the +// HashedDefs array. +// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the +// NonPkgDefs array (could natually overflow to NonPkgRefs array). +// - Otherwise, SymIdx is the index of the symbol in some other package's +// SymbolDefs array. +// +// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0. +// +// Hash contains the content hashes of content-addressable symbols, of +// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array. +// Hash64 is similar, for PkgIdxHashed64 symbols. +// +// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to +// Relocs/Aux/Data blocks, one element per symbol, first for all the +// defined symbols, then all the defined hashed and non-package symbols, +// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs +// arrays. For N total defined symbols, the array is of length N+1. The +// last element is the total number of relocations (aux symbols, data +// blocks, etc.). +// +// They can be accessed by index. For the i-th symbol, its relocations +// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive) +// elements in the Relocs array. Aux/Data are likewise. (The index is +// 0-based.) + +// Auxiliary symbols. +// +// Each symbol may (or may not) be associated with a number of auxiliary +// symbols. They are described in the Aux block. See Aux struct below. +// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols +// are auxiliary symbols. + +const stringRefSize = 8 // two uint32s + +type FingerprintType [8]byte + +func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} } + +// Package Index. +const ( + PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols + PkgIdxHashed64 // Short hashed (content-addressable) symbols + PkgIdxHashed // Hashed (content-addressable) symbols + PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject) + PkgIdxSelf // Symbols defined in the current package + PkgIdxInvalid = 0 + // The index of other referenced packages starts from 1. +) + +// Blocks +const ( + BlkAutolib = iota + BlkPkgIdx + BlkFile + BlkSymdef + BlkHashed64def + BlkHasheddef + BlkNonpkgdef + BlkNonpkgref + BlkRefFlags + BlkHash64 + BlkHash + BlkRelocIdx + BlkAuxIdx + BlkDataIdx + BlkReloc + BlkAux + BlkData + BlkPcdata + BlkRefName + BlkEnd + NBlk +) + +// File header. +// TODO: probably no need to export this. +type Header struct { + Magic string + Fingerprint FingerprintType + Flags uint32 + Offsets [NBlk]uint32 +} + +const Magic = "\x00go116ld" + +func (h *Header) Write(w *Writer) { + w.RawString(h.Magic) + w.Bytes(h.Fingerprint[:]) + w.Uint32(h.Flags) + for _, x := range h.Offsets { + w.Uint32(x) + } +} + +func (h *Header) Read(r *Reader) error { + b := r.BytesAt(0, len(Magic)) + h.Magic = string(b) + if h.Magic != Magic { + return errors.New("wrong magic, not a Go object file") + } + off := uint32(len(h.Magic)) + copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint))) + off += 8 + h.Flags = r.uint32At(off) + off += 4 + for i := range h.Offsets { + h.Offsets[i] = r.uint32At(off) + off += 4 + } + return nil +} + +func (h *Header) Size() int { + return len(h.Magic) + 4 + 4*len(h.Offsets) +} + +// Autolib +type ImportedPkg struct { + Pkg string + Fingerprint FingerprintType +} + +const importedPkgSize = stringRefSize + 8 + +func (p *ImportedPkg) Write(w *Writer) { + w.StringRef(p.Pkg) + w.Bytes(p.Fingerprint[:]) +} + +// Symbol definition. +// +// Serialized format: +// Sym struct { +// Name string +// ABI uint16 +// Type uint8 +// Flag uint8 +// Flag2 uint8 +// Siz uint32 +// Align uint32 +// } +type Sym [SymSize]byte + +const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4 + +const SymABIstatic = ^uint16(0) + +const ( + ObjFlagShared = 1 << iota // this object is built with -shared + ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names + ObjFlagFromAssembly // object is from asm src, not go +) + +// Sym.Flag +const ( + SymFlagDupok = 1 << iota + SymFlagLocal + SymFlagTypelink + SymFlagLeaf + SymFlagNoSplit + SymFlagReflectMethod + SymFlagGoType + SymFlagTopFrame +) + +// Sym.Flag2 +const ( + SymFlagUsedInIface = 1 << iota + SymFlagItab +) + +// Returns the length of the name of the symbol. +func (s *Sym) NameLen(r *Reader) int { + return int(binary.LittleEndian.Uint32(s[:])) +} + +func (s *Sym) Name(r *Reader) string { + len := binary.LittleEndian.Uint32(s[:]) + off := binary.LittleEndian.Uint32(s[4:]) + return r.StringAt(off, len) +} + +func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) } +func (s *Sym) Type() uint8 { return s[10] } +func (s *Sym) Flag() uint8 { return s[11] } +func (s *Sym) Flag2() uint8 { return s[12] } +func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) } +func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) } + +func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 } +func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 } +func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 } +func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 } +func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 } +func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 } +func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 } +func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 } +func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 } +func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 } + +func (s *Sym) SetName(x string, w *Writer) { + binary.LittleEndian.PutUint32(s[:], uint32(len(x))) + binary.LittleEndian.PutUint32(s[4:], w.stringOff(x)) +} + +func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) } +func (s *Sym) SetType(x uint8) { s[10] = x } +func (s *Sym) SetFlag(x uint8) { s[11] = x } +func (s *Sym) SetFlag2(x uint8) { s[12] = x } +func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) } +func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) } + +func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) } + +// for testing +func (s *Sym) fromBytes(b []byte) { copy(s[:], b) } + +// Symbol reference. +type SymRef struct { + PkgIdx uint32 + SymIdx uint32 +} + +// Hash64 +type Hash64Type [Hash64Size]byte + +const Hash64Size = 8 + +// Hash +type HashType [HashSize]byte + +const HashSize = sha1.Size + +// Relocation. +// +// Serialized format: +// Reloc struct { +// Off int32 +// Siz uint8 +// Type uint8 +// Add int64 +// Sym SymRef +// } +type Reloc [RelocSize]byte + +const RelocSize = 4 + 1 + 1 + 8 + 8 + +func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } +func (r *Reloc) Siz() uint8 { return r[4] } +func (r *Reloc) Type() uint8 { return r[5] } +func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) } +func (r *Reloc) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])} +} + +func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } +func (r *Reloc) SetSiz(x uint8) { r[4] = x } +func (r *Reloc) SetType(x uint8) { r[5] = x } +func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) } +func (r *Reloc) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(r[14:], x.PkgIdx) + binary.LittleEndian.PutUint32(r[18:], x.SymIdx) +} + +func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) { + r.SetOff(off) + r.SetSiz(size) + r.SetType(typ) + r.SetAdd(add) + r.SetSym(sym) +} + +func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) } + +// for testing +func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) } + +// Aux symbol info. +// +// Serialized format: +// Aux struct { +// Type uint8 +// Sym SymRef +// } +type Aux [AuxSize]byte + +const AuxSize = 1 + 8 + +// Aux Type +const ( + AuxGotype = iota + AuxFuncInfo + AuxFuncdata + AuxDwarfInfo + AuxDwarfLoc + AuxDwarfRanges + AuxDwarfLines + + // TODO: more. Pcdata? +) + +func (a *Aux) Type() uint8 { return a[0] } +func (a *Aux) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])} +} + +func (a *Aux) SetType(x uint8) { a[0] = x } +func (a *Aux) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(a[1:], x.PkgIdx) + binary.LittleEndian.PutUint32(a[5:], x.SymIdx) +} + +func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) } + +// for testing +func (a *Aux) fromBytes(b []byte) { copy(a[:], b) } + +// Referenced symbol flags. +// +// Serialized format: +// RefFlags struct { +// Sym symRef +// Flag uint8 +// Flag2 uint8 +// } +type RefFlags [RefFlagsSize]byte + +const RefFlagsSize = 8 + 1 + 1 + +func (r *RefFlags) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])} +} +func (r *RefFlags) Flag() uint8 { return r[8] } +func (r *RefFlags) Flag2() uint8 { return r[9] } + +func (r *RefFlags) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(r[:], x.PkgIdx) + binary.LittleEndian.PutUint32(r[4:], x.SymIdx) +} +func (r *RefFlags) SetFlag(x uint8) { r[8] = x } +func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } + +func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } + +// Referenced symbol name. +// +// Serialized format: +// RefName struct { +// Sym symRef +// Name string +// } +type RefName [RefNameSize]byte + +const RefNameSize = 8 + stringRefSize + +func (n *RefName) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])} +} +func (n *RefName) Name(r *Reader) string { + len := binary.LittleEndian.Uint32(n[8:]) + off := binary.LittleEndian.Uint32(n[12:]) + return r.StringAt(off, len) +} + +func (n *RefName) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(n[:], x.PkgIdx) + binary.LittleEndian.PutUint32(n[4:], x.SymIdx) +} +func (n *RefName) SetName(x string, w *Writer) { + binary.LittleEndian.PutUint32(n[8:], uint32(len(x))) + binary.LittleEndian.PutUint32(n[12:], w.stringOff(x)) +} + +func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) } + +type Writer struct { + wr *bio.Writer + stringMap map[string]uint32 + off uint32 // running offset +} + +func NewWriter(wr *bio.Writer) *Writer { + return &Writer{wr: wr, stringMap: make(map[string]uint32)} +} + +func (w *Writer) AddString(s string) { + if _, ok := w.stringMap[s]; ok { + return + } + w.stringMap[s] = w.off + w.RawString(s) +} + +func (w *Writer) stringOff(s string) uint32 { + off, ok := w.stringMap[s] + if !ok { + panic(fmt.Sprintf("writeStringRef: string not added: %q", s)) + } + return off +} + +func (w *Writer) StringRef(s string) { + w.Uint32(uint32(len(s))) + w.Uint32(w.stringOff(s)) +} + +func (w *Writer) RawString(s string) { + w.wr.WriteString(s) + w.off += uint32(len(s)) +} + +func (w *Writer) Bytes(s []byte) { + w.wr.Write(s) + w.off += uint32(len(s)) +} + +func (w *Writer) Uint64(x uint64) { + var b [8]byte + binary.LittleEndian.PutUint64(b[:], x) + w.wr.Write(b[:]) + w.off += 8 +} + +func (w *Writer) Uint32(x uint32) { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], x) + w.wr.Write(b[:]) + w.off += 4 +} + +func (w *Writer) Uint16(x uint16) { + var b [2]byte + binary.LittleEndian.PutUint16(b[:], x) + w.wr.Write(b[:]) + w.off += 2 +} + +func (w *Writer) Uint8(x uint8) { + w.wr.WriteByte(x) + w.off++ +} + +func (w *Writer) Offset() uint32 { + return w.off +} + +type Reader struct { + b []byte // mmapped bytes, if not nil + readonly bool // whether b is backed with read-only memory + + rd io.ReaderAt + start uint32 + h Header // keep block offsets +} + +func NewReaderFromBytes(b []byte, readonly bool) *Reader { + r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0} + err := r.h.Read(r) + if err != nil { + return nil + } + return r +} + +func (r *Reader) BytesAt(off uint32, len int) []byte { + if len == 0 { + return nil + } + end := int(off) + len + return r.b[int(off):end:end] +} + +func (r *Reader) uint64At(off uint32) uint64 { + b := r.BytesAt(off, 8) + return binary.LittleEndian.Uint64(b) +} + +func (r *Reader) int64At(off uint32) int64 { + return int64(r.uint64At(off)) +} + +func (r *Reader) uint32At(off uint32) uint32 { + b := r.BytesAt(off, 4) + return binary.LittleEndian.Uint32(b) +} + +func (r *Reader) int32At(off uint32) int32 { + return int32(r.uint32At(off)) +} + +func (r *Reader) uint16At(off uint32) uint16 { + b := r.BytesAt(off, 2) + return binary.LittleEndian.Uint16(b) +} + +func (r *Reader) uint8At(off uint32) uint8 { + b := r.BytesAt(off, 1) + return b[0] +} + +func (r *Reader) StringAt(off uint32, len uint32) string { + b := r.b[off : off+len] + if r.readonly { + return toString(b) // backed by RO memory, ok to make unsafe string + } + return string(b) +} + +func toString(b []byte) string { + if len(b) == 0 { + return "" + } + + var s string + hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) + hdr.Data = unsafe.Pointer(&b[0]) + hdr.Len = len(b) + + return s +} + +func (r *Reader) StringRef(off uint32) string { + l := r.uint32At(off) + return r.StringAt(r.uint32At(off+4), l) +} + +func (r *Reader) Fingerprint() FingerprintType { + return r.h.Fingerprint +} + +func (r *Reader) Autolib() []ImportedPkg { + n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize + s := make([]ImportedPkg, n) + off := r.h.Offsets[BlkAutolib] + for i := range s { + s[i].Pkg = r.StringRef(off) + copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint))) + off += importedPkgSize + } + return s +} + +func (r *Reader) Pkglist() []string { + n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize + s := make([]string, n) + off := r.h.Offsets[BlkPkgIdx] + for i := range s { + s[i] = r.StringRef(off) + off += stringRefSize + } + return s +} + +func (r *Reader) NPkg() int { + return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize +} + +func (r *Reader) Pkg(i int) string { + off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize + return r.StringRef(off) +} + +func (r *Reader) NFile() int { + return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize +} + +func (r *Reader) File(i int) string { + off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize + return r.StringRef(off) +} + +func (r *Reader) NSym() int { + return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize +} + +func (r *Reader) NHashed64def() int { + return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize +} + +func (r *Reader) NHasheddef() int { + return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize +} + +func (r *Reader) NNonpkgdef() int { + return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize +} + +func (r *Reader) NNonpkgref() int { + return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize +} + +// SymOff returns the offset of the i-th symbol. +func (r *Reader) SymOff(i uint32) uint32 { + return r.h.Offsets[BlkSymdef] + uint32(i*SymSize) +} + +// Sym returns a pointer to the i-th symbol. +func (r *Reader) Sym(i uint32) *Sym { + off := r.SymOff(i) + return (*Sym)(unsafe.Pointer(&r.b[off])) +} + +// NRefFlags returns the number of referenced symbol flags. +func (r *Reader) NRefFlags() int { + return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize +} + +// RefFlags returns a pointer to the i-th referenced symbol flags. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefFlags(i int) *RefFlags { + off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize) + return (*RefFlags)(unsafe.Pointer(&r.b[off])) +} + +// Hash64 returns the i-th short hashed symbol's hash. +// Note: here i is the index of short hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash64(i uint32) uint64 { + off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size) + return r.uint64At(off) +} + +// Hash returns a pointer to the i-th hashed symbol's hash. +// Note: here i is the index of hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash(i uint32) *HashType { + off := r.h.Offsets[BlkHash] + uint32(i*HashSize) + return (*HashType)(unsafe.Pointer(&r.b[off])) +} + +// NReloc returns the number of relocations of the i-th symbol. +func (r *Reader) NReloc(i uint32) int { + relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) + return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff)) +} + +// RelocOff returns the offset of the j-th relocation of the i-th symbol. +func (r *Reader) RelocOff(i uint32, j int) uint32 { + relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) + relocIdx := r.uint32At(relocIdxOff) + return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize) +} + +// Reloc returns a pointer to the j-th relocation of the i-th symbol. +func (r *Reader) Reloc(i uint32, j int) *Reloc { + off := r.RelocOff(i, j) + return (*Reloc)(unsafe.Pointer(&r.b[off])) +} + +// Relocs returns a pointer to the relocations of the i-th symbol. +func (r *Reader) Relocs(i uint32) []Reloc { + off := r.RelocOff(i, 0) + n := r.NReloc(i) + return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// NAux returns the number of aux symbols of the i-th symbol. +func (r *Reader) NAux(i uint32) int { + auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 + return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff)) +} + +// AuxOff returns the offset of the j-th aux symbol of the i-th symbol. +func (r *Reader) AuxOff(i uint32, j int) uint32 { + auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 + auxIdx := r.uint32At(auxIdxOff) + return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize) +} + +// Aux returns a pointer to the j-th aux symbol of the i-th symbol. +func (r *Reader) Aux(i uint32, j int) *Aux { + off := r.AuxOff(i, j) + return (*Aux)(unsafe.Pointer(&r.b[off])) +} + +// Auxs returns the aux symbols of the i-th symbol. +func (r *Reader) Auxs(i uint32) []Aux { + off := r.AuxOff(i, 0) + n := r.NAux(i) + return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// DataOff returns the offset of the i-th symbol's data. +func (r *Reader) DataOff(i uint32) uint32 { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff) +} + +// DataSize returns the size of the i-th symbol's data. +func (r *Reader) DataSize(i uint32) int { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff)) +} + +// Data returns the i-th symbol's data. +func (r *Reader) Data(i uint32) []byte { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + base := r.h.Offsets[BlkData] + off := r.uint32At(dataIdxOff) + end := r.uint32At(dataIdxOff + 4) + return r.BytesAt(base+off, int(end-off)) +} + +// AuxDataBase returns the base offset of the aux data block. +func (r *Reader) PcdataBase() uint32 { + return r.h.Offsets[BlkPcdata] +} + +// NRefName returns the number of referenced symbol names. +func (r *Reader) NRefName() int { + return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize +} + +// RefName returns a pointer to the i-th referenced symbol name. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefName(i int) *RefName { + off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize) + return (*RefName)(unsafe.Pointer(&r.b[off])) +} + +// ReadOnly returns whether r.BytesAt returns read-only bytes. +func (r *Reader) ReadOnly() bool { + return r.readonly +} + +// Flags returns the flag bits read from the object file header. +func (r *Reader) Flags() uint32 { + return r.h.Flags +} + +func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 } +func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 } +func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 } diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/abi_string.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/abi_string.go new file mode 100644 index 0000000..a439da3 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/abi_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type ABI"; DO NOT EDIT. + +package obj + +import "strconv" + +const _ABI_name = "ABI0ABIInternalABICount" + +var _ABI_index = [...]uint8{0, 4, 15, 23} + +func (i ABI) String() string { + if i >= ABI(len(_ABI_index)-1) { + return "ABI(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _ABI_name[_ABI_index[i]:_ABI_index[i+1]] +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/addrtype_string.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/addrtype_string.go new file mode 100644 index 0000000..71f0dd9 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/addrtype_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type AddrType"; DO NOT EDIT. + +package obj + +import "strconv" + +const _AddrType_name = "TYPE_NONETYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST" + +var _AddrType_index = [...]uint8{0, 9, 20, 33, 41, 51, 62, 73, 81, 90, 100, 111, 123, 133, 145} + +func (i AddrType) String() string { + if i >= AddrType(len(_AddrType_index)-1) { + return "AddrType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _AddrType_name[_AddrType_index[i]:_AddrType_index[i+1]] +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/a.out.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/a.out.go new file mode 100644 index 0000000..8f8b8db --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/a.out.go @@ -0,0 +1,410 @@ +// Inferno utils/5c/5.out.h +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/5.out.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm + +import "github.com/twitchyliquid64/golang-asm/obj" + +//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm + +const ( + NSNAME = 8 + NSYM = 50 + NREG = 16 +) + +/* -1 disables use of REGARG */ +const ( + REGARG = -1 +) + +const ( + REG_R0 = obj.RBaseARM + iota // must be 16-aligned + REG_R1 + REG_R2 + REG_R3 + REG_R4 + REG_R5 + REG_R6 + REG_R7 + REG_R8 + REG_R9 + REG_R10 + REG_R11 + REG_R12 + REG_R13 + REG_R14 + REG_R15 + + REG_F0 // must be 16-aligned + REG_F1 + REG_F2 + REG_F3 + REG_F4 + REG_F5 + REG_F6 + REG_F7 + REG_F8 + REG_F9 + REG_F10 + REG_F11 + REG_F12 + REG_F13 + REG_F14 + REG_F15 + + REG_FPSR // must be 2-aligned + REG_FPCR + + REG_CPSR // must be 2-aligned + REG_SPSR + + REGRET = REG_R0 + /* compiler allocates R1 up as temps */ + /* compiler allocates register variables R3 up */ + /* compiler allocates external registers R10 down */ + REGEXT = REG_R10 + /* these two registers are declared in runtime.h */ + REGG = REGEXT - 0 + REGM = REGEXT - 1 + + REGCTXT = REG_R7 + REGTMP = REG_R11 + REGSP = REG_R13 + REGLINK = REG_R14 + REGPC = REG_R15 + + NFREG = 16 + /* compiler allocates register variables F0 up */ + /* compiler allocates external registers F7 down */ + FREGRET = REG_F0 + FREGEXT = REG_F7 + FREGTMP = REG_F15 +) + +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf +var ARMDWARFRegisters = map[int16]int16{} + +func init() { + // f assigns dwarfregisters[from:to] = (base):(step*(to-from)+base) + f := func(from, to, base, step int16) { + for r := int16(from); r <= to; r++ { + ARMDWARFRegisters[r] = step*(r-from) + base + } + } + f(REG_R0, REG_R15, 0, 1) + f(REG_F0, REG_F15, 64, 2) // Use d0 through D15, aka S0, S2, ..., S30 +} + +// Special registers, after subtracting obj.RBaseARM, bit 9 indicates +// a special register and the low bits select the register. +const ( + REG_SPECIAL = obj.RBaseARM + 1<<9 + iota + REG_MB_SY + REG_MB_ST + REG_MB_ISH + REG_MB_ISHST + REG_MB_NSH + REG_MB_NSHST + REG_MB_OSH + REG_MB_OSHST + + MAXREG +) + +const ( + C_NONE = iota + C_REG + C_REGREG + C_REGREG2 + C_REGLIST + C_SHIFT /* register shift R>>x */ + C_SHIFTADDR /* memory address with shifted offset R>>x(R) */ + C_FREG + C_PSR + C_FCR + C_SPR /* REG_MB_SY */ + + C_RCON /* 0xff rotated */ + C_NCON /* ~RCON */ + C_RCON2A /* OR of two disjoint C_RCON constants */ + C_RCON2S /* subtraction of two disjoint C_RCON constants */ + C_SCON /* 0xffff */ + C_LCON + C_LCONADDR + C_ZFCON + C_SFCON + C_LFCON + + C_RACON + C_LACON + + C_SBRA + C_LBRA + + C_HAUTO /* halfword insn offset (-0xff to 0xff) */ + C_FAUTO /* float insn offset (0 to 0x3fc, word aligned) */ + C_HFAUTO /* both H and F */ + C_SAUTO /* -0xfff to 0xfff */ + C_LAUTO + + C_HOREG + C_FOREG + C_HFOREG + C_SOREG + C_ROREG + C_SROREG /* both nil and R */ + C_LOREG + + C_PC + C_SP + C_HREG + + C_ADDR /* reference to relocatable address */ + + // TLS "var" in local exec mode: will become a constant offset from + // thread local base that is ultimately chosen by the program linker. + C_TLS_LE + + // TLS "var" in initial exec mode: will become a memory address (chosen + // by the program linker) that the dynamic linker will fill with the + // offset from the thread local base. + C_TLS_IE + + C_TEXTSIZE + + C_GOK + + C_NCLASS /* must be the last */ +) + +const ( + AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota + AEOR + ASUB + ARSB + AADD + AADC + ASBC + ARSC + ATST + ATEQ + ACMP + ACMN + AORR + ABIC + + AMVN + + /* + * Do not reorder or fragment the conditional branch + * opcodes, or the predication code will break + */ + ABEQ + ABNE + ABCS + ABHS + ABCC + ABLO + ABMI + ABPL + ABVS + ABVC + ABHI + ABLS + ABGE + ABLT + ABGT + ABLE + + AMOVWD + AMOVWF + AMOVDW + AMOVFW + AMOVFD + AMOVDF + AMOVF + AMOVD + + ACMPF + ACMPD + AADDF + AADDD + ASUBF + ASUBD + AMULF + AMULD + ANMULF + ANMULD + AMULAF + AMULAD + ANMULAF + ANMULAD + AMULSF + AMULSD + ANMULSF + ANMULSD + AFMULAF + AFMULAD + AFNMULAF + AFNMULAD + AFMULSF + AFMULSD + AFNMULSF + AFNMULSD + ADIVF + ADIVD + ASQRTF + ASQRTD + AABSF + AABSD + ANEGF + ANEGD + + ASRL + ASRA + ASLL + AMULU + ADIVU + AMUL + AMMUL + ADIV + AMOD + AMODU + ADIVHW + ADIVUHW + + AMOVB + AMOVBS + AMOVBU + AMOVH + AMOVHS + AMOVHU + AMOVW + AMOVM + ASWPBU + ASWPW + + ARFE + ASWI + AMULA + AMULS + AMMULA + AMMULS + + AWORD + + AMULL + AMULAL + AMULLU + AMULALU + + ABX + ABXRET + ADWORD + + ALDREX + ASTREX + ALDREXD + ASTREXD + + ADMB + + APLD + + ACLZ + AREV + AREV16 + AREVSH + ARBIT + + AXTAB + AXTAH + AXTABU + AXTAHU + + ABFX + ABFXU + ABFC + ABFI + + AMULWT + AMULWB + AMULBB + AMULAWT + AMULAWB + AMULABB + + AMRC // MRC/MCR + + ALAST + + // aliases + AB = obj.AJMP + ABL = obj.ACALL +) + +/* scond byte */ +const ( + C_SCOND = (1 << 4) - 1 + C_SBIT = 1 << 4 + C_PBIT = 1 << 5 + C_WBIT = 1 << 6 + C_FBIT = 1 << 7 /* psr flags-only */ + C_UBIT = 1 << 7 /* up bit, unsigned bit */ + + // These constants are the ARM condition codes encodings, + // XORed with 14 so that C_SCOND_NONE has value 0, + // so that a zeroed Prog.scond means "always execute". + C_SCOND_XOR = 14 + + C_SCOND_EQ = 0 ^ C_SCOND_XOR + C_SCOND_NE = 1 ^ C_SCOND_XOR + C_SCOND_HS = 2 ^ C_SCOND_XOR + C_SCOND_LO = 3 ^ C_SCOND_XOR + C_SCOND_MI = 4 ^ C_SCOND_XOR + C_SCOND_PL = 5 ^ C_SCOND_XOR + C_SCOND_VS = 6 ^ C_SCOND_XOR + C_SCOND_VC = 7 ^ C_SCOND_XOR + C_SCOND_HI = 8 ^ C_SCOND_XOR + C_SCOND_LS = 9 ^ C_SCOND_XOR + C_SCOND_GE = 10 ^ C_SCOND_XOR + C_SCOND_LT = 11 ^ C_SCOND_XOR + C_SCOND_GT = 12 ^ C_SCOND_XOR + C_SCOND_LE = 13 ^ C_SCOND_XOR + C_SCOND_NONE = 14 ^ C_SCOND_XOR + C_SCOND_NV = 15 ^ C_SCOND_XOR + + /* D_SHIFT type */ + SHIFT_LL = 0 << 5 + SHIFT_LR = 1 << 5 + SHIFT_AR = 2 << 5 + SHIFT_RR = 3 << 5 +) diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames.go new file mode 100644 index 0000000..8a05133 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames.go @@ -0,0 +1,144 @@ +// Code generated by stringer -i a.out.go -o anames.go -p arm; DO NOT EDIT. + +package arm + +import "github.com/twitchyliquid64/golang-asm/obj" + +var Anames = []string{ + obj.A_ARCHSPECIFIC: "AND", + "EOR", + "SUB", + "RSB", + "ADD", + "ADC", + "SBC", + "RSC", + "TST", + "TEQ", + "CMP", + "CMN", + "ORR", + "BIC", + "MVN", + "BEQ", + "BNE", + "BCS", + "BHS", + "BCC", + "BLO", + "BMI", + "BPL", + "BVS", + "BVC", + "BHI", + "BLS", + "BGE", + "BLT", + "BGT", + "BLE", + "MOVWD", + "MOVWF", + "MOVDW", + "MOVFW", + "MOVFD", + "MOVDF", + "MOVF", + "MOVD", + "CMPF", + "CMPD", + "ADDF", + "ADDD", + "SUBF", + "SUBD", + "MULF", + "MULD", + "NMULF", + "NMULD", + "MULAF", + "MULAD", + "NMULAF", + "NMULAD", + "MULSF", + "MULSD", + "NMULSF", + "NMULSD", + "FMULAF", + "FMULAD", + "FNMULAF", + "FNMULAD", + "FMULSF", + "FMULSD", + "FNMULSF", + "FNMULSD", + "DIVF", + "DIVD", + "SQRTF", + "SQRTD", + "ABSF", + "ABSD", + "NEGF", + "NEGD", + "SRL", + "SRA", + "SLL", + "MULU", + "DIVU", + "MUL", + "MMUL", + "DIV", + "MOD", + "MODU", + "DIVHW", + "DIVUHW", + "MOVB", + "MOVBS", + "MOVBU", + "MOVH", + "MOVHS", + "MOVHU", + "MOVW", + "MOVM", + "SWPBU", + "SWPW", + "RFE", + "SWI", + "MULA", + "MULS", + "MMULA", + "MMULS", + "WORD", + "MULL", + "MULAL", + "MULLU", + "MULALU", + "BX", + "BXRET", + "DWORD", + "LDREX", + "STREX", + "LDREXD", + "STREXD", + "DMB", + "PLD", + "CLZ", + "REV", + "REV16", + "REVSH", + "RBIT", + "XTAB", + "XTAH", + "XTABU", + "XTAHU", + "BFX", + "BFXU", + "BFC", + "BFI", + "MULWT", + "MULWB", + "MULBB", + "MULAWT", + "MULAWB", + "MULABB", + "MRC", + "LAST", +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames5.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames5.go new file mode 100644 index 0000000..78fcd55 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/anames5.go @@ -0,0 +1,77 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arm + +var cnames5 = []string{ + "NONE", + "REG", + "REGREG", + "REGREG2", + "REGLIST", + "SHIFT", + "SHIFTADDR", + "FREG", + "PSR", + "FCR", + "SPR", + "RCON", + "NCON", + "RCON2A", + "RCON2S", + "SCON", + "LCON", + "LCONADDR", + "ZFCON", + "SFCON", + "LFCON", + "RACON", + "LACON", + "SBRA", + "LBRA", + "HAUTO", + "FAUTO", + "HFAUTO", + "SAUTO", + "LAUTO", + "HOREG", + "FOREG", + "HFOREG", + "SOREG", + "ROREG", + "SROREG", + "LOREG", + "PC", + "SP", + "HREG", + "ADDR", + "C_TLS_LE", + "C_TLS_IE", + "TEXTSIZE", + "GOK", + "NCLASS", + "SCOND = (1<<4)-1", + "SBIT = 1<<4", + "PBIT = 1<<5", + "WBIT = 1<<6", + "FBIT = 1<<7", + "UBIT = 1<<7", + "SCOND_XOR = 14", + "SCOND_EQ = 0 ^ C_SCOND_XOR", + "SCOND_NE = 1 ^ C_SCOND_XOR", + "SCOND_HS = 2 ^ C_SCOND_XOR", + "SCOND_LO = 3 ^ C_SCOND_XOR", + "SCOND_MI = 4 ^ C_SCOND_XOR", + "SCOND_PL = 5 ^ C_SCOND_XOR", + "SCOND_VS = 6 ^ C_SCOND_XOR", + "SCOND_VC = 7 ^ C_SCOND_XOR", + "SCOND_HI = 8 ^ C_SCOND_XOR", + "SCOND_LS = 9 ^ C_SCOND_XOR", + "SCOND_GE = 10 ^ C_SCOND_XOR", + "SCOND_LT = 11 ^ C_SCOND_XOR", + "SCOND_GT = 12 ^ C_SCOND_XOR", + "SCOND_LE = 13 ^ C_SCOND_XOR", + "SCOND_NONE = 14 ^ C_SCOND_XOR", + "SCOND_NV = 15 ^ C_SCOND_XOR", +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go new file mode 100644 index 0000000..924657f --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go @@ -0,0 +1,3096 @@ +// Inferno utils/5l/span.c +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/span.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/objabi" + "fmt" + "log" + "math" + "sort" +) + +// ctxt5 holds state while assembling a single function. +// Each function gets a fresh ctxt5. +// This allows for multiple functions to be safely concurrently assembled. +type ctxt5 struct { + ctxt *obj.Link + newprog obj.ProgAlloc + cursym *obj.LSym + printp *obj.Prog + blitrl *obj.Prog + elitrl *obj.Prog + autosize int64 + instoffset int64 + pc int64 + pool struct { + start uint32 + size uint32 + extra uint32 + } +} + +type Optab struct { + as obj.As + a1 uint8 + a2 int8 + a3 uint8 + type_ uint8 + size int8 + param int16 + flag int8 + pcrelsiz uint8 + scond uint8 // optional flags accepted by the instruction +} + +type Opcross [32][2][32]uint8 + +const ( + LFROM = 1 << 0 + LTO = 1 << 1 + LPOOL = 1 << 2 + LPCREL = 1 << 3 +) + +var optab = []Optab{ + /* struct Optab: + OPCODE, from, prog->reg, to, type, size, param, flag, extra data size, optional suffix */ + {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0, 0}, + {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, + {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0, 0}, + {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, + {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, + {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, + {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0, 0}, + {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, + {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0, 0}, + {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0, C_SBIT}, + {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0, 0}, + {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, + {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0, 0}, + {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, + {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // prediction hinted form, hint ignored + {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0, 0}, + {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, + {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, + {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0, 0}, + {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0, 0}, + {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0, C_SBIT}, + {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0, C_SBIT}, + {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0, C_SBIT}, + {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0, C_SBIT}, + {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0, 0}, + {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0, 0}, + {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, + {AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, + {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0, 0}, + {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4, 0}, + {AMVN, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, + {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, + {AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, + {AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, 0}, + {ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, + {AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, + {AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, + {AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, + {AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, + {AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0, 0}, + {AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0, 0}, + {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, + {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, 0}, + {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0, 0}, + {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, + {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, + {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, + {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, + {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0, C_SBIT}, + {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0, C_SBIT}, + {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0, 0}, + {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0, 0}, + {ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0, 0}, + {ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0, 0}, + {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0, C_SBIT}, + {ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 + {ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 + {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AXTAB, C_SHIFT, C_REG, C_REG, 22, 4, 0, 0, 0, 0}, + {AXTAB, C_SHIFT, C_NONE, C_REG, 22, 4, 0, 0, 0, 0}, + {AMOVW, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, C_SBIT}, + {AMOVB, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVBS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVBU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVH, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVHS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVHU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0, 0}, + {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0, 0}, + {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0, C_SBIT}, + {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0, 0}, + {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0, 0}, + {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0, 0}, + {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0, 0}, + {AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, + {ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0, 0}, + {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0, 0}, + {AMOVW, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVW, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBU, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, + {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, + {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0, 0}, + {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0, 0}, + {ADMB, C_NONE, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, + {ADMB, C_LCON, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, + {ADMB, C_SPR, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, + {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0, 0}, + {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0, 0}, + {ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0, 0}, + {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0, 0}, + {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0, C_UBIT}, + {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0, C_UBIT}, + {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0, C_UBIT}, + {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0, C_UBIT}, + {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0, 0}, + {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0, 0}, + {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0, 0}, + {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0, 0}, + {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0, 0}, + {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0, 0}, + {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0, 0}, + {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0, 0}, + {AMULA, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, C_SBIT}, + {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, 0}, + {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0, 0}, + {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0, 0}, + {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, + {obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, // nop variants, see #40689 + {obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, + {obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, + {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL + {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL + {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0, 0}, +} + +var mbOp = []struct { + reg int16 + enc uint32 +}{ + {REG_MB_SY, 15}, + {REG_MB_ST, 14}, + {REG_MB_ISH, 11}, + {REG_MB_ISHST, 10}, + {REG_MB_NSH, 7}, + {REG_MB_NSHST, 6}, + {REG_MB_OSH, 3}, + {REG_MB_OSHST, 2}, +} + +var oprange [ALAST & obj.AMask][]Optab + +var xcmp [C_GOK + 1][C_GOK + 1]bool + +var ( + deferreturn *obj.LSym + symdiv *obj.LSym + symdivu *obj.LSym + symmod *obj.LSym + symmodu *obj.LSym +) + +// Note about encoding: Prog.scond holds the condition encoding, +// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0. +// The code that shifts the value << 28 has the responsibility +// for XORing with C_SCOND_XOR too. + +func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) { + if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 { + c.ctxt.Diag("invalid .S suffix: %v", p) + } + if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 { + c.ctxt.Diag("invalid .P suffix: %v", p) + } + if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 { + c.ctxt.Diag("invalid .W suffix: %v", p) + } + if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 { + c.ctxt.Diag("invalid .U suffix: %v", p) + } +} + +func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { + if ctxt.Retpoline { + ctxt.Diag("-spectre=ret not supported on arm") + ctxt.Retpoline = false // don't keep printing + } + + var p *obj.Prog + var op *obj.Prog + + p = cursym.Func.Text + if p == nil || p.Link == nil { // handle external functions and ELF section symbols + return + } + + if oprange[AAND&obj.AMask] == nil { + ctxt.Diag("arm ops not initialized, call arm.buildop first") + } + + c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4} + pc := int32(0) + + op = p + p = p.Link + var m int + var o *Optab + for ; p != nil || c.blitrl != nil; op, p = p, p.Link { + if p == nil { + if c.checkpool(op, pc) { + p = op + continue + } + + // can't happen: blitrl is not nil, but checkpool didn't flushpool + ctxt.Diag("internal inconsistency") + + break + } + + p.Pc = int64(pc) + o = c.oplook(p) + m = int(o.size) + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("!pc invalid: %v size=%d", p, m) + } + + // must check literal pool here in case p generates many instructions + if c.blitrl != nil { + // Emit the constant pool just before p if p + // would push us over the immediate size limit. + if c.checkpool(op, pc+int32(m)) { + // Back up to the instruction just + // before the pool and continue with + // the first instruction of the pool. + p = op + continue + } + } + + if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { + ctxt.Diag("zero-width instruction\n%v", p) + continue + } + + switch o.flag & (LFROM | LTO | LPOOL) { + case LFROM: + c.addpool(p, &p.From) + + case LTO: + c.addpool(p, &p.To) + + case LPOOL: + if p.Scond&C_SCOND == C_SCOND_NONE { + c.flushpool(p, 0, 0) + } + } + + if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { + c.flushpool(p, 0, 0) + } + + pc += int32(m) + } + + c.cursym.Size = int64(pc) + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + times := 0 + + var bflag int + var opc int32 + var out [6 + 3]uint32 + for { + bflag = 0 + pc = 0 + times++ + c.cursym.Func.Text.Pc = 0 // force re-layout the code. + for p = c.cursym.Func.Text; p != nil; p = p.Link { + o = c.oplook(p) + if int64(pc) > p.Pc { + p.Pc = int64(pc) + } + + /* very large branches + if(o->type == 6 && p->pcond) { + otxt = p->pcond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = emallocz(sizeof(Prog)); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = TYPE_BRANCH; + q->pcond = p->pcond; + p->pcond = q; + q = emallocz(sizeof(Prog)); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = TYPE_BRANCH; + q->pcond = q->link->link; + bflag = 1; + } + } + */ + opc = int32(p.Pc) + m = int(o.size) + if p.Pc != int64(opc) { + bflag = 1 + } + + //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); + pc = int32(p.Pc + int64(m)) + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("pc invalid: %v size=%d", p, m) + } + + if m/4 > len(out) { + ctxt.Diag("instruction size too large: %d > %d", m/4, len(out)) + } + if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { + if p.As == obj.ATEXT { + c.autosize = p.To.Offset + 4 + continue + } + + ctxt.Diag("zero-width instruction\n%v", p) + continue + } + } + + c.cursym.Size = int64(pc) + if bflag == 0 { + break + } + } + + if pc%4 != 0 { + ctxt.Diag("sym->size=%d, invalid", pc) + } + + /* + * lay out the code. all the pc-relative code references, + * even cross-function, are resolved now; + * only data references need to be relocated. + * with more work we could leave cross-function + * code references to be relocated too, and then + * perhaps we'd be able to parallelize the span loop above. + */ + + p = c.cursym.Func.Text + c.autosize = p.To.Offset + 4 + c.cursym.Grow(c.cursym.Size) + + bp := c.cursym.P + pc = int32(p.Pc) // even p->link might need extra padding + var v int + for p = p.Link; p != nil; p = p.Link { + c.pc = p.Pc + o = c.oplook(p) + opc = int32(p.Pc) + c.asmout(p, o, out[:]) + m = int(o.size) + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) + } + + if int64(pc) > p.Pc { + ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p) + } + for int64(pc) != p.Pc { + // emit 0xe1a00000 (MOVW R0, R0) + bp[0] = 0x00 + bp = bp[1:] + + bp[0] = 0x00 + bp = bp[1:] + bp[0] = 0xa0 + bp = bp[1:] + bp[0] = 0xe1 + bp = bp[1:] + pc += 4 + } + + for i := 0; i < m/4; i++ { + v = int(out[i]) + bp[0] = byte(v) + bp = bp[1:] + bp[0] = byte(v >> 8) + bp = bp[1:] + bp[0] = byte(v >> 16) + bp = bp[1:] + bp[0] = byte(v >> 24) + bp = bp[1:] + } + + pc += int32(m) + } +} + +// checkpool flushes the literal pool when the first reference to +// it threatens to go out of range of a 12-bit PC-relative offset. +// +// nextpc is the tentative next PC at which the pool could be emitted. +// checkpool should be called *before* emitting the instruction that +// would cause the PC to reach nextpc. +// If nextpc is too far from the first pool reference, checkpool will +// flush the pool immediately after p. +// The caller should resume processing a p.Link. +func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool { + poolLast := nextpc + poolLast += 4 // the AB instruction to jump around the pool + poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry + + refPC := int32(c.pool.start) // PC of the first pool reference + + v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl) + + if c.pool.size >= 0xff0 || immaddr(v) == 0 { + return c.flushpool(p, 1, 0) + } else if p.Link == nil { + return c.flushpool(p, 2, 0) + } + return false +} + +func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool { + if c.blitrl != nil { + if skip != 0 { + if false && skip == 1 { + fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start) + } + q := c.newprog() + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.To.SetTarget(p.Link) + q.Link = c.blitrl + q.Pos = p.Pos + c.blitrl = q + } else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) { + return false + } + + // The line number for constant pool entries doesn't really matter. + // We set it to the line number of the preceding instruction so that + // there are no deltas to encode in the pc-line tables. + for q := c.blitrl; q != nil; q = q.Link { + q.Pos = p.Pos + } + + c.elitrl.Link = p.Link + p.Link = c.blitrl + + c.blitrl = nil /* BUG: should refer back to values until out-of-range */ + c.elitrl = nil + c.pool.size = 0 + c.pool.start = 0 + c.pool.extra = 0 + return true + } + + return false +} + +func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) { + t := c.newprog() + t.As = AWORD + + switch c.aclass(a) { + default: + t.To.Offset = a.Offset + t.To.Sym = a.Sym + t.To.Type = a.Type + t.To.Name = a.Name + + if c.ctxt.Flag_shared && t.To.Sym != nil { + t.Rel = p + } + + case C_SROREG, + C_LOREG, + C_ROREG, + C_FOREG, + C_SOREG, + C_HOREG, + C_FAUTO, + C_SAUTO, + C_LAUTO, + C_LACON: + t.To.Type = obj.TYPE_CONST + t.To.Offset = c.instoffset + } + + if t.Rel == nil { + for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ + if q.Rel == nil && q.To == t.To { + p.Pool = q + return + } + } + } + + q := c.newprog() + *q = *t + q.Pc = int64(c.pool.size) + + if c.blitrl == nil { + c.blitrl = q + c.pool.start = uint32(p.Pc) + } else { + c.elitrl.Link = q + } + c.elitrl = q + c.pool.size += 4 + + // Store the link to the pool entry in Pool. + p.Pool = q +} + +func (c *ctxt5) regoff(a *obj.Addr) int32 { + c.instoffset = 0 + c.aclass(a) + return int32(c.instoffset) +} + +func immrot(v uint32) int32 { + for i := 0; i < 16; i++ { + if v&^0xff == 0 { + return int32(uint32(int32(i)<<8) | v | 1<<25) + } + v = v<<2 | v>>30 + } + + return 0 +} + +// immrot2a returns bits encoding the immediate constant fields of two instructions, +// such that the encoded constants x, y satisfy x|y==v, x&y==0. +// Returns 0,0 if no such decomposition of v exists. +func immrot2a(v uint32) (uint32, uint32) { + for i := uint(1); i < 32; i++ { + m := uint32(1<= 0 && v <= 0xfff { + return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ + } + if v >= -0xfff && v < 0 { + return -v&0xfff | 1<<24 /* pre indexing */ + } + return 0 +} + +func immfloat(v int32) bool { + return v&0xC03 == 0 /* offset will fit in floating-point load/store */ +} + +func immhalf(v int32) bool { + if v >= 0 && v <= 0xff { + return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ + } + if v >= -0xff && v < 0 { + return -v&0xff|1<<24 != 0 /* pre indexing */ + } + return false +} + +func (c *ctxt5) aclass(a *obj.Addr) int { + switch a.Type { + case obj.TYPE_NONE: + return C_NONE + + case obj.TYPE_REG: + c.instoffset = 0 + if REG_R0 <= a.Reg && a.Reg <= REG_R15 { + return C_REG + } + if REG_F0 <= a.Reg && a.Reg <= REG_F15 { + return C_FREG + } + if a.Reg == REG_FPSR || a.Reg == REG_FPCR { + return C_FCR + } + if a.Reg == REG_CPSR || a.Reg == REG_SPSR { + return C_PSR + } + if a.Reg >= REG_SPECIAL { + return C_SPR + } + return C_GOK + + case obj.TYPE_REGREG: + return C_REGREG + + case obj.TYPE_REGREG2: + return C_REGREG2 + + case obj.TYPE_REGLIST: + return C_REGLIST + + case obj.TYPE_SHIFT: + if a.Reg == 0 { + // register shift R>>i + return C_SHIFT + } else { + // memory address with shifted offset R>>i(R) + return C_SHIFTADDR + } + + case obj.TYPE_MEM: + switch a.Name { + case obj.NAME_EXTERN, + obj.NAME_GOTREF, + obj.NAME_STATIC: + if a.Sym == nil || a.Sym.Name == "" { + fmt.Printf("null sym external\n") + return C_GOK + } + + c.instoffset = 0 // s.b. unused but just in case + if a.Sym.Type == objabi.STLSBSS { + if c.ctxt.Flag_shared { + return C_TLS_IE + } else { + return C_TLS_LE + } + } + + return C_ADDR + + case obj.NAME_AUTO: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-SP. + a.Reg = obj.REG_NONE + } + c.instoffset = c.autosize + a.Offset + if t := immaddr(int32(c.instoffset)); t != 0 { + if immhalf(int32(c.instoffset)) { + if immfloat(t) { + return C_HFAUTO + } + return C_HAUTO + } + + if immfloat(t) { + return C_FAUTO + } + return C_SAUTO + } + + return C_LAUTO + + case obj.NAME_PARAM: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-FP. + a.Reg = obj.REG_NONE + } + c.instoffset = c.autosize + a.Offset + 4 + if t := immaddr(int32(c.instoffset)); t != 0 { + if immhalf(int32(c.instoffset)) { + if immfloat(t) { + return C_HFAUTO + } + return C_HAUTO + } + + if immfloat(t) { + return C_FAUTO + } + return C_SAUTO + } + + return C_LAUTO + + case obj.NAME_NONE: + c.instoffset = a.Offset + if t := immaddr(int32(c.instoffset)); t != 0 { + if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */ + if immfloat(t) { + return C_HFOREG + } + return C_HOREG + } + + if immfloat(t) { + return C_FOREG /* n.b. that it will also satisfy immrot */ + } + if immrot(uint32(c.instoffset)) != 0 { + return C_SROREG + } + if immhalf(int32(c.instoffset)) { + return C_HOREG + } + return C_SOREG + } + + if immrot(uint32(c.instoffset)) != 0 { + return C_ROREG + } + return C_LOREG + } + + return C_GOK + + case obj.TYPE_FCONST: + if c.chipzero5(a.Val.(float64)) >= 0 { + return C_ZFCON + } + if c.chipfloat5(a.Val.(float64)) >= 0 { + return C_SFCON + } + return C_LFCON + + case obj.TYPE_TEXTSIZE: + return C_TEXTSIZE + + case obj.TYPE_CONST, + obj.TYPE_ADDR: + switch a.Name { + case obj.NAME_NONE: + c.instoffset = a.Offset + if a.Reg != 0 { + return c.aconsize() + } + + if immrot(uint32(c.instoffset)) != 0 { + return C_RCON + } + if immrot(^uint32(c.instoffset)) != 0 { + return C_NCON + } + if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 { + return C_SCON + } + if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 { + return C_RCON2A + } + if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 { + return C_RCON2S + } + return C_LCON + + case obj.NAME_EXTERN, + obj.NAME_GOTREF, + obj.NAME_STATIC: + s := a.Sym + if s == nil { + break + } + c.instoffset = 0 // s.b. unused but just in case + return C_LCONADDR + + case obj.NAME_AUTO: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-SP. + a.Reg = obj.REG_NONE + } + c.instoffset = c.autosize + a.Offset + return c.aconsize() + + case obj.NAME_PARAM: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-FP. + a.Reg = obj.REG_NONE + } + c.instoffset = c.autosize + a.Offset + 4 + return c.aconsize() + } + + return C_GOK + + case obj.TYPE_BRANCH: + return C_SBRA + } + + return C_GOK +} + +func (c *ctxt5) aconsize() int { + if immrot(uint32(c.instoffset)) != 0 { + return C_RACON + } + if immrot(uint32(-c.instoffset)) != 0 { + return C_RACON + } + return C_LACON +} + +func (c *ctxt5) oplook(p *obj.Prog) *Optab { + a1 := int(p.Optab) + if a1 != 0 { + return &optab[a1-1] + } + a1 = int(p.From.Class) + if a1 == 0 { + a1 = c.aclass(&p.From) + 1 + p.From.Class = int8(a1) + } + + a1-- + a3 := int(p.To.Class) + if a3 == 0 { + a3 = c.aclass(&p.To) + 1 + p.To.Class = int8(a3) + } + + a3-- + a2 := C_NONE + if p.Reg != 0 { + switch { + case REG_F0 <= p.Reg && p.Reg <= REG_F15: + a2 = C_FREG + case REG_R0 <= p.Reg && p.Reg <= REG_R15: + a2 = C_REG + default: + c.ctxt.Diag("invalid register in %v", p) + } + } + + // check illegal base register + switch a1 { + case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: + if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg { + c.ctxt.Diag("illegal base register: %v", p) + } + default: + } + switch a3 { + case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: + if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg { + c.ctxt.Diag("illegal base register: %v", p) + } + default: + } + + // If current instruction has a .S suffix (flags update), + // we must use the constant pool instead of splitting it. + if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 { + a1 = C_LCON + } + if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 { + a3 = C_LCON + } + + if false { /*debug['O']*/ + fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) + fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) + } + + ops := oprange[p.As&obj.AMask] + c1 := &xcmp[a1] + c3 := &xcmp[a3] + for i := range ops { + op := &ops[i] + if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { + p.Optab = uint16(cap(optab) - cap(ops) + i + 1) + checkSuffix(c, p, op) + return op + } + } + + c.ctxt.Diag("illegal combination %v; %v %v %v; from %d %d; to %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.From.Name, p.To.Type, p.To.Name) + if ops == nil { + ops = optab + } + return &ops[0] +} + +func cmp(a int, b int) bool { + if a == b { + return true + } + switch a { + case C_LCON: + if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S { + return true + } + + case C_LACON: + if b == C_RACON { + return true + } + + case C_LFCON: + if b == C_ZFCON || b == C_SFCON { + return true + } + + case C_HFAUTO: + return b == C_HAUTO || b == C_FAUTO + + case C_FAUTO, C_HAUTO: + return b == C_HFAUTO + + case C_SAUTO: + return cmp(C_HFAUTO, b) + + case C_LAUTO: + return cmp(C_SAUTO, b) + + case C_HFOREG: + return b == C_HOREG || b == C_FOREG + + case C_FOREG, C_HOREG: + return b == C_HFOREG + + case C_SROREG: + return cmp(C_SOREG, b) || cmp(C_ROREG, b) + + case C_SOREG, C_ROREG: + return b == C_SROREG || cmp(C_HFOREG, b) + + case C_LOREG: + return cmp(C_SROREG, b) + + case C_LBRA: + if b == C_SBRA { + return true + } + + case C_HREG: + return cmp(C_SP, b) || cmp(C_PC, b) + } + + return false +} + +type ocmp []Optab + +func (x ocmp) Len() int { + return len(x) +} + +func (x ocmp) Swap(i, j int) { + x[i], x[j] = x[j], x[i] +} + +func (x ocmp) Less(i, j int) bool { + p1 := &x[i] + p2 := &x[j] + n := int(p1.as) - int(p2.as) + if n != 0 { + return n < 0 + } + n = int(p1.a1) - int(p2.a1) + if n != 0 { + return n < 0 + } + n = int(p1.a2) - int(p2.a2) + if n != 0 { + return n < 0 + } + n = int(p1.a3) - int(p2.a3) + if n != 0 { + return n < 0 + } + return false +} + +func opset(a, b0 obj.As) { + oprange[a&obj.AMask] = oprange[b0] +} + +func buildop(ctxt *obj.Link) { + if oprange[AAND&obj.AMask] != nil { + // Already initialized; stop now. + // This happens in the cmd/asm tests, + // each of which re-initializes the arch. + return + } + + deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) + + symdiv = ctxt.Lookup("runtime._div") + symdivu = ctxt.Lookup("runtime._divu") + symmod = ctxt.Lookup("runtime._mod") + symmodu = ctxt.Lookup("runtime._modu") + + var n int + + for i := 0; i < C_GOK; i++ { + for n = 0; n < C_GOK; n++ { + if cmp(n, i) { + xcmp[i][n] = true + } + } + } + for n = 0; optab[n].as != obj.AXXX; n++ { + if optab[n].flag&LPCREL != 0 { + if ctxt.Flag_shared { + optab[n].size += int8(optab[n].pcrelsiz) + } else { + optab[n].flag &^= LPCREL + } + } + } + + sort.Sort(ocmp(optab[:n])) + for i := 0; i < n; i++ { + r := optab[i].as + r0 := r & obj.AMask + start := i + for optab[i].as == r { + i++ + } + oprange[r0] = optab[start:i] + i-- + + switch r { + default: + ctxt.Diag("unknown op in build: %v", r) + ctxt.DiagFlush() + log.Fatalf("bad code") + + case AADD: + opset(ASUB, r0) + opset(ARSB, r0) + opset(AADC, r0) + opset(ASBC, r0) + opset(ARSC, r0) + + case AORR: + opset(AEOR, r0) + opset(ABIC, r0) + + case ACMP: + opset(ATEQ, r0) + opset(ACMN, r0) + opset(ATST, r0) + + case AMVN: + break + + case ABEQ: + opset(ABNE, r0) + opset(ABCS, r0) + opset(ABHS, r0) + opset(ABCC, r0) + opset(ABLO, r0) + opset(ABMI, r0) + opset(ABPL, r0) + opset(ABVS, r0) + opset(ABVC, r0) + opset(ABHI, r0) + opset(ABLS, r0) + opset(ABGE, r0) + opset(ABLT, r0) + opset(ABGT, r0) + opset(ABLE, r0) + + case ASLL: + opset(ASRL, r0) + opset(ASRA, r0) + + case AMUL: + opset(AMULU, r0) + + case ADIV: + opset(AMOD, r0) + opset(AMODU, r0) + opset(ADIVU, r0) + + case ADIVHW: + opset(ADIVUHW, r0) + + case AMOVW, + AMOVB, + AMOVBS, + AMOVBU, + AMOVH, + AMOVHS, + AMOVHU: + break + + case ASWPW: + opset(ASWPBU, r0) + + case AB, + ABL, + ABX, + ABXRET, + obj.ADUFFZERO, + obj.ADUFFCOPY, + ASWI, + AWORD, + AMOVM, + ARFE, + obj.ATEXT: + break + + case AADDF: + opset(AADDD, r0) + opset(ASUBF, r0) + opset(ASUBD, r0) + opset(AMULF, r0) + opset(AMULD, r0) + opset(ANMULF, r0) + opset(ANMULD, r0) + opset(AMULAF, r0) + opset(AMULAD, r0) + opset(AMULSF, r0) + opset(AMULSD, r0) + opset(ANMULAF, r0) + opset(ANMULAD, r0) + opset(ANMULSF, r0) + opset(ANMULSD, r0) + opset(AFMULAF, r0) + opset(AFMULAD, r0) + opset(AFMULSF, r0) + opset(AFMULSD, r0) + opset(AFNMULAF, r0) + opset(AFNMULAD, r0) + opset(AFNMULSF, r0) + opset(AFNMULSD, r0) + opset(ADIVF, r0) + opset(ADIVD, r0) + + case ANEGF: + opset(ANEGD, r0) + opset(ASQRTF, r0) + opset(ASQRTD, r0) + opset(AMOVFD, r0) + opset(AMOVDF, r0) + opset(AABSF, r0) + opset(AABSD, r0) + + case ACMPF: + opset(ACMPD, r0) + + case AMOVF: + opset(AMOVD, r0) + + case AMOVFW: + opset(AMOVDW, r0) + + case AMOVWF: + opset(AMOVWD, r0) + + case AMULL: + opset(AMULAL, r0) + opset(AMULLU, r0) + opset(AMULALU, r0) + + case AMULWT: + opset(AMULWB, r0) + opset(AMULBB, r0) + opset(AMMUL, r0) + + case AMULAWT: + opset(AMULAWB, r0) + opset(AMULABB, r0) + opset(AMULS, r0) + opset(AMMULA, r0) + opset(AMMULS, r0) + + case ABFX: + opset(ABFXU, r0) + opset(ABFC, r0) + opset(ABFI, r0) + + case ACLZ: + opset(AREV, r0) + opset(AREV16, r0) + opset(AREVSH, r0) + opset(ARBIT, r0) + + case AXTAB: + opset(AXTAH, r0) + opset(AXTABU, r0) + opset(AXTAHU, r0) + + case ALDREX, + ASTREX, + ALDREXD, + ASTREXD, + ADMB, + APLD, + AAND, + AMULA, + obj.AUNDEF, + obj.AFUNCDATA, + obj.APCDATA, + obj.ANOP: + break + } + } +} + +func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { + c.printp = p + o1 := uint32(0) + o2 := uint32(0) + o3 := uint32(0) + o4 := uint32(0) + o5 := uint32(0) + o6 := uint32(0) + if false { /*debug['P']*/ + fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) + } + switch o.type_ { + default: + c.ctxt.Diag("%v: unknown asm %d", p, o.type_) + + case 0: /* pseudo ops */ + if false { /*debug['G']*/ + fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) + } + + case 1: /* op R,[R],R */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { + r = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 2: /* movbu $I,[R],R */ + c.aclass(&p.From) + + o1 = c.oprrr(p, p.As, int(p.Scond)) + o1 |= uint32(immrot(uint32(c.instoffset))) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + if p.As == AMOVW || p.As == AMVN { + r = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 106: /* op $I,R,R where I can be decomposed into 2 immediates */ + c.aclass(&p.From) + r := int(p.Reg) + rt := int(p.To.Reg) + if r == 0 { + r = rt + } + x, y := immrot2a(uint32(c.instoffset)) + var as2 obj.As + switch p.As { + case AADD, ASUB, AORR, AEOR, ABIC: + as2 = p.As // ADD, SUB, ORR, EOR, BIC + case ARSB: + as2 = AADD // RSB -> RSB/ADD pair + case AADC: + as2 = AADD // ADC -> ADC/ADD pair + case ASBC: + as2 = ASUB // SBC -> SBC/SUB pair + case ARSC: + as2 = AADD // RSC -> RSC/ADD pair + default: + c.ctxt.Diag("unknown second op for %v", p) + } + o1 = c.oprrr(p, p.As, int(p.Scond)) + o2 = c.oprrr(p, as2, int(p.Scond)) + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 + o1 |= x + o2 |= y + + case 107: /* op $I,R,R where I can be decomposed into 2 immediates */ + c.aclass(&p.From) + r := int(p.Reg) + rt := int(p.To.Reg) + if r == 0 { + r = rt + } + y, x := immrot2s(uint32(c.instoffset)) + var as2 obj.As + switch p.As { + case AADD: + as2 = ASUB // ADD -> ADD/SUB pair + case ASUB: + as2 = AADD // SUB -> SUB/ADD pair + case ARSB: + as2 = ASUB // RSB -> RSB/SUB pair + case AADC: + as2 = ASUB // ADC -> ADC/SUB pair + case ASBC: + as2 = AADD // SBC -> SBC/ADD pair + case ARSC: + as2 = ASUB // RSC -> RSC/SUB pair + default: + c.ctxt.Diag("unknown second op for %v", p) + } + o1 = c.oprrr(p, p.As, int(p.Scond)) + o2 = c.oprrr(p, as2, int(p.Scond)) + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 + o1 |= y + o2 |= x + + case 3: /* add R<<[IR],[R],R */ + o1 = c.mov(p) + + case 4: /* MOVW $off(R), R -> add $off,[R],R */ + c.aclass(&p.From) + if c.instoffset < 0 { + o1 = c.oprrr(p, ASUB, int(p.Scond)) + o1 |= uint32(immrot(uint32(-c.instoffset))) + } else { + o1 = c.oprrr(p, AADD, int(p.Scond)) + o1 |= uint32(immrot(uint32(c.instoffset))) + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 |= (uint32(r) & 15) << 16 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 5: /* bra s */ + o1 = c.opbra(p, p.As, int(p.Scond)) + + v := int32(-8) + if p.To.Sym != nil { + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + v += int32(p.To.Offset) + rel.Add = int64(o1) | (int64(v)>>2)&0xffffff + rel.Type = objabi.R_CALLARM + break + } + + if p.To.Target() != nil { + v = int32((p.To.Target().Pc - c.pc) - 8) + } + o1 |= (uint32(v) >> 2) & 0xffffff + + case 6: /* b ,O(R) -> add $O,R,PC */ + c.aclass(&p.To) + + o1 = c.oprrr(p, AADD, int(p.Scond)) + o1 |= uint32(immrot(uint32(c.instoffset))) + o1 |= (uint32(p.To.Reg) & 15) << 16 + o1 |= (REGPC & 15) << 12 + + case 7: /* bl (R) -> blx R */ + c.aclass(&p.To) + + if c.instoffset != 0 { + c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset) + } + o1 = c.oprrr(p, ABL, int(p.Scond)) + o1 |= (uint32(p.To.Reg) & 15) << 0 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 0 + rel.Type = objabi.R_CALLIND + + case 8: /* sll $c,[R],R -> mov (R<<$c),R */ + c.aclass(&p.From) + + o1 = c.oprrr(p, p.As, int(p.Scond)) + r := int(p.Reg) + if r == 0 { + r = int(p.To.Reg) + } + o1 |= (uint32(r) & 15) << 0 + o1 |= uint32((c.instoffset & 31) << 7) + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 9: /* sll R,[R],R -> mov (R< 31 || width <= 0 || (lsb+width) > 32 { + c.ctxt.Diag("%v: wrong width or LSB", p) + } + switch p.As { + case ABFX, ABFXU: // (width-1) is encoded + o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16 + case ABFC, ABFI: // MSB is encoded + o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16 + default: + c.ctxt.Diag("illegal combination: %v", p) + } + + case 20: /* mov/movb/movbu R,O(R) */ + c.aclass(&p.To) + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) + + case 21: /* mov/movbu O(R),R -> lr */ + c.aclass(&p.From) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) + if p.As != AMOVW { + o1 |= 1 << 22 + } + + case 22: /* XTAB R@>i, [R], R */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + switch p.From.Offset &^ 0xf { + // only 0/8/16/24 bits rotation is accepted + case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: + o1 |= uint32(p.From.Offset) & 0xc0f + default: + c.ctxt.Diag("illegal shift: %v", p) + } + rt := p.To.Reg + r := p.Reg + if r == 0 { + r = rt + } + o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16 + + case 23: /* MOVW/MOVB/MOVH R@>i, R */ + switch p.As { + case AMOVW: + o1 = c.mov(p) + case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH: + o1 = c.movxt(p) + default: + c.ctxt.Diag("illegal combination: %v", p) + } + + case 30: /* mov/movb/movbu R,L(R) */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) + if p.As != AMOVW { + o2 |= 1 << 22 + } + + case 31: /* mov/movbu L(R),R -> lr[b] */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { + o2 |= 1 << 22 + } + + case 34: /* mov $lacon,R */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + + o2 = c.oprrr(p, AADD, int(p.Scond)) + o2 |= REGTMP & 15 + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 |= (uint32(r) & 15) << 16 + if p.To.Type != obj.TYPE_NONE { + o2 |= (uint32(p.To.Reg) & 15) << 12 + } + + case 35: /* mov PSR,R */ + o1 = 2<<23 | 0xf<<16 | 0<<0 + + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + o1 |= (uint32(p.From.Reg) & 1) << 22 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 36: /* mov R,PSR */ + o1 = 2<<23 | 0x2cf<<12 | 0<<4 + + if p.Scond&C_FBIT != 0 { + o1 ^= 0x010 << 12 + } + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + o1 |= (uint32(p.To.Reg) & 1) << 22 + o1 |= (uint32(p.From.Reg) & 15) << 0 + + case 37: /* mov $con,PSR */ + c.aclass(&p.From) + + o1 = 2<<23 | 0x2cf<<12 | 0<<4 + if p.Scond&C_FBIT != 0 { + o1 ^= 0x010 << 12 + } + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + o1 |= uint32(immrot(uint32(c.instoffset))) + o1 |= (uint32(p.To.Reg) & 1) << 22 + o1 |= (uint32(p.From.Reg) & 15) << 0 + + case 38, 39: + switch o.type_ { + case 38: /* movm $con,oreg -> stm */ + o1 = 0x4 << 25 + + o1 |= uint32(p.From.Offset & 0xffff) + o1 |= (uint32(p.To.Reg) & 15) << 16 + c.aclass(&p.To) + + case 39: /* movm oreg,$con -> ldm */ + o1 = 0x4<<25 | 1<<20 + + o1 |= uint32(p.To.Offset & 0xffff) + o1 |= (uint32(p.From.Reg) & 15) << 16 + c.aclass(&p.From) + } + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in MOVM; %v", p) + } + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + if p.Scond&C_PBIT != 0 { + o1 |= 1 << 24 + } + if p.Scond&C_UBIT != 0 { + o1 |= 1 << 23 + } + if p.Scond&C_WBIT != 0 { + o1 |= 1 << 21 + } + + case 40: /* swp oreg,reg,reg */ + c.aclass(&p.From) + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in SWP") + } + o1 = 0x2<<23 | 0x9<<4 + if p.As != ASWPW { + o1 |= 1 << 22 + } + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.Reg) & 15) << 0 + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ + o1 = 0xe8fd8000 + + case 50: /* floating point store */ + v := c.regoff(&p.To) + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p) + + case 51: /* floating point load */ + v := c.regoff(&p.From) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 + + case 52: /* floating point store, int32 offset UGLY */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 + o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) + + case 53: /* floating point load, int32 offset UGLY */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 + o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 + + case 54: /* floating point arith */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + switch p.As { + case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD, + AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD: + c.ctxt.Diag("illegal combination: %v", p) + default: + r = rt + } + } + + o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 55: /* negf freg, freg */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + + o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12 + + case 56: /* move to FP[CS]R */ + o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4 + + o1 |= (uint32(p.From.Reg) & 15) << 12 + + case 57: /* move from FP[CS]R */ + o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4 + + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 58: /* movbu R,R */ + o1 = c.oprrr(p, AAND, int(p.Scond)) + + o1 |= uint32(immrot(0xff)) + rt := int(p.To.Reg) + r := int(p.From.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + if r == 0 { + r = rt + } + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 59: /* movw/bu R< ldr indexed */ + if p.From.Reg == 0 { + c.ctxt.Diag("source operand is not a memory address: %v", p) + break + } + if p.From.Offset&(1<<4) != 0 { + c.ctxt.Diag("bad shift in LDR") + break + } + o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) + if p.As == AMOVBU { + o1 |= 1 << 22 + } + + case 60: /* movb R(R),R -> ldrsb indexed */ + if p.From.Reg == 0 { + c.ctxt.Diag("source operand is not a memory address: %v", p) + break + } + if p.From.Offset&(^0xf) != 0 { + c.ctxt.Diag("bad shift: %v", p) + break + } + o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) + switch p.As { + case AMOVB, AMOVBS: + o1 ^= 1<<5 | 1<<6 + case AMOVH, AMOVHS: + o1 ^= 1 << 6 + default: + } + if p.Scond&C_UBIT != 0 { + o1 &^= 1 << 23 + } + + case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ + if p.To.Reg == 0 { + c.ctxt.Diag("MOV to shifter operand") + } + o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) + if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { + o1 |= 1 << 22 + } + + case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */ + if p.To.Reg == 0 { + c.ctxt.Diag("MOV to shifter operand") + } + if p.To.Offset&(^0xf) != 0 { + c.ctxt.Diag("bad shift: %v", p) + } + o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond)) + o1 ^= 1 << 20 + if p.Scond&C_UBIT != 0 { + o1 &^= 1 << 23 + } + + /* reloc ops */ + case 64: /* mov/movb/movbu R,addr */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond)) + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + case 65: /* mov/movbu addr,R */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { + o2 |= 1 << 22 + } + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + case 101: /* movw tlsvar,R, local exec*/ + o1 = c.omvl(p, &p.From, int(p.To.Reg)) + + case 102: /* movw tlsvar,R, initial exec*/ + o1 = c.omvl(p, &p.From, int(p.To.Reg)) + o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond)) + + case 103: /* word tlsvar, local exec */ + if p.To.Sym == nil { + c.ctxt.Diag("nil sym in tls %v", p) + } + if p.To.Offset != 0 { + c.ctxt.Diag("offset against tls var in %v", p) + } + // This case happens with words generated in the PC stream as part of + // the literal c.pool. + rel := obj.Addrel(c.cursym) + + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Type = objabi.R_TLS_LE + o1 = 0 + + case 104: /* word tlsvar, initial exec */ + if p.To.Sym == nil { + c.ctxt.Diag("nil sym in tls %v", p) + } + if p.To.Offset != 0 { + c.ctxt.Diag("offset against tls var in %v", p) + } + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Type = objabi.R_TLS_IE + rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz) + + case 68: /* floating point store -> ADDR */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + case 69: /* floating point load <- ADDR */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + /* ArmV4 ops: */ + case 70: /* movh/movhu R,O(R) -> strh */ + c.aclass(&p.To) + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) + + case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ + c.aclass(&p.From) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVB || p.As == AMOVBS { + o1 ^= 1<<5 | 1<<6 + } else if p.As == AMOVH || p.As == AMOVHS { + o1 ^= (1 << 6) + } + + case 72: /* movh/movhu R,L(R) -> strh */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) + + case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVB || p.As == AMOVBS { + o2 ^= 1<<5 | 1<<6 + } else if p.As == AMOVH || p.As == AMOVHS { + o2 ^= (1 << 6) + } + + case 74: /* bx $I */ + c.ctxt.Diag("ABX $I") + + case 75: /* bx O(R) */ + c.aclass(&p.To) + + if c.instoffset != 0 { + c.ctxt.Diag("non-zero offset in ABX") + } + + /* + o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR + o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R + */ + // p->to.reg may be REGLINK + o1 = c.oprrr(p, AADD, int(p.Scond)) + + o1 |= uint32(immrot(uint32(c.instoffset))) + o1 |= (uint32(p.To.Reg) & 15) << 16 + o1 |= (REGTMP & 15) << 12 + o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR + o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp + + case 76: /* bx O(R) when returning from fn*/ + c.ctxt.Diag("ABXRET") + + case 77: /* ldrex oreg,reg */ + c.aclass(&p.From) + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in LDREX") + } + o1 = 0x19<<20 | 0xf9f + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 78: /* strex reg,oreg,reg */ + c.aclass(&p.From) + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in STREX") + } + if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg { + c.ctxt.Diag("cannot use same register as both source and destination: %v", p) + } + o1 = 0x18<<20 | 0xf90 + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.Reg) & 15) << 0 + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 80: /* fmov zfcon,freg */ + if p.As == AMOVD { + o1 = 0xeeb00b00 // VMOV imm 64 + o2 = c.oprrr(p, ASUBD, int(p.Scond)) + } else { + o1 = 0x0eb00a00 // VMOV imm 32 + o2 = c.oprrr(p, ASUBF, int(p.Scond)) + } + + v := int32(0x70) // 1.0 + r := (int(p.To.Reg) & 15) << 0 + + // movf $1.0, r + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + o1 |= (uint32(r) & 15) << 12 + o1 |= (uint32(v) & 0xf) << 0 + o1 |= (uint32(v) & 0xf0) << 12 + + // subf r,r,r + o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 + + case 81: /* fmov sfcon,freg */ + o1 = 0x0eb00a00 // VMOV imm 32 + if p.As == AMOVD { + o1 = 0xeeb00b00 // VMOV imm 64 + } + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + o1 |= (uint32(p.To.Reg) & 15) << 12 + v := int32(c.chipfloat5(p.From.Val.(float64))) + o1 |= (uint32(v) & 0xf) << 0 + o1 |= (uint32(v) & 0xf0) << 12 + + case 82: /* fcmp freg,freg, */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 + o2 = 0x0ef1fa10 // VMRS R15 + o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 83: /* fcmp freg,, */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 + o2 = 0x0ef1fa10 // VMRS R15 + o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 84: /* movfw freg,freg - truncate float-to-fix */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 0 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 85: /* movwf freg,freg - fix-to-float */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 0 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + // macro for movfw freg,FTMP; movw FTMP,reg + case 86: /* movfw freg,reg - truncate float-to-fix */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 0 + o1 |= (FREGTMP & 15) << 12 + o2 = c.oprrr(p, -AMOVFW, int(p.Scond)) + o2 |= (FREGTMP & 15) << 16 + o2 |= (uint32(p.To.Reg) & 15) << 12 + + // macro for movw reg,FTMP; movwf FTMP,freg + case 87: /* movwf reg,freg - fix-to-float */ + o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 12 + o1 |= (FREGTMP & 15) << 16 + o2 = c.oprrr(p, p.As, int(p.Scond)) + o2 |= (FREGTMP & 15) << 0 + o2 |= (uint32(p.To.Reg) & 15) << 12 + + case 88: /* movw reg,freg */ + o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 12 + o1 |= (uint32(p.To.Reg) & 15) << 16 + + case 89: /* movw freg,reg */ + o1 = c.oprrr(p, -AMOVFW, int(p.Scond)) + + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 91: /* ldrexd oreg,reg */ + c.aclass(&p.From) + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in LDREX") + } + o1 = 0x1b<<20 | 0xf9f + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 92: /* strexd reg,oreg,reg */ + c.aclass(&p.From) + + if c.instoffset != 0 { + c.ctxt.Diag("offset must be zero in STREX") + } + if p.Reg&1 != 0 { + c.ctxt.Diag("source register must be even in STREXD: %v", p) + } + if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 { + c.ctxt.Diag("cannot use same register as both source and destination: %v", p) + } + o1 = 0x1a<<20 | 0xf90 + o1 |= (uint32(p.From.Reg) & 15) << 16 + o1 |= (uint32(p.Reg) & 15) << 0 + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + + case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ + o1 = c.omvl(p, &p.From, REGTMP) + + if o1 == 0 { + break + } + o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVB || p.As == AMOVBS { + o2 ^= 1<<5 | 1<<6 + } else if p.As == AMOVH || p.As == AMOVHS { + o2 ^= (1 << 6) + } + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + case 94: /* movh/movhu R,addr -> strh */ + o1 = c.omvl(p, &p.To, REGTMP) + + if o1 == 0 { + break + } + o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond)) + if o.flag&LPCREL != 0 { + o3 = o2 + o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 + } + + case 95: /* PLD off(reg) */ + o1 = 0xf5d0f000 + + o1 |= (uint32(p.From.Reg) & 15) << 16 + if p.From.Offset < 0 { + o1 &^= (1 << 23) + o1 |= uint32((-p.From.Offset) & 0xfff) + } else { + o1 |= uint32(p.From.Offset & 0xfff) + } + + // This is supposed to be something that stops execution. + // It's not supposed to be reached, ever, but if it is, we'd + // like to be able to tell how we got there. Assemble as + // 0xf7fabcfd which is guaranteed to raise undefined instruction + // exception. + case 96: /* UNDEF */ + o1 = 0xf7fabcfd + + case 97: /* CLZ Rm, Rd */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.To.Reg) & 15) << 12 + o1 |= (uint32(p.From.Reg) & 15) << 0 + + case 98: /* MULW{T,B} Rs, Rm, Rd */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.To.Reg) & 15) << 16 + o1 |= (uint32(p.From.Reg) & 15) << 8 + o1 |= (uint32(p.Reg) & 15) << 0 + + case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + + o1 |= (uint32(p.To.Reg) & 15) << 16 + o1 |= (uint32(p.From.Reg) & 15) << 8 + o1 |= (uint32(p.Reg) & 15) << 0 + o1 |= uint32((p.To.Offset & 15) << 12) + + case 105: /* divhw r,[r,]r */ + o1 = c.oprrr(p, p.As, int(p.Scond)) + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 + + case 110: /* dmb [mbop | $con] */ + o1 = 0xf57ff050 + mbop := uint32(0) + + switch c.aclass(&p.From) { + case C_SPR: + for _, f := range mbOp { + if f.reg == p.From.Reg { + mbop = f.enc + break + } + } + case C_RCON: + for _, f := range mbOp { + enc := uint32(c.instoffset) + if f.enc == enc { + mbop = enc + break + } + } + case C_NONE: + mbop = 0xf + } + + if mbop == 0 { + c.ctxt.Diag("illegal mb option:\n%v", p) + } + o1 |= mbop + } + + out[0] = o1 + out[1] = o2 + out[2] = o3 + out[3] = o4 + out[4] = o5 + out[5] = o6 +} + +func (c *ctxt5) movxt(p *obj.Prog) uint32 { + o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + switch p.As { + case AMOVB, AMOVBS: + o1 |= 0x6af<<16 | 0x7<<4 + case AMOVH, AMOVHS: + o1 |= 0x6bf<<16 | 0x7<<4 + case AMOVBU: + o1 |= 0x6ef<<16 | 0x7<<4 + case AMOVHU: + o1 |= 0x6ff<<16 | 0x7<<4 + default: + c.ctxt.Diag("illegal combination: %v", p) + } + switch p.From.Offset &^ 0xf { + // only 0/8/16/24 bits rotation is accepted + case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: + o1 |= uint32(p.From.Offset) & 0xc0f + default: + c.ctxt.Diag("illegal shift: %v", p) + } + o1 |= (uint32(p.To.Reg) & 15) << 12 + return o1 +} + +func (c *ctxt5) mov(p *obj.Prog) uint32 { + c.aclass(&p.From) + o1 := c.oprrr(p, p.As, int(p.Scond)) + o1 |= uint32(p.From.Offset) + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + r := int(p.Reg) + if p.As == AMOVW || p.As == AMVN { + r = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + return o1 +} + +func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 { + o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 + if sc&C_SBIT != 0 { + o |= 1 << 20 + } + switch a { + case ADIVHW: + return o | 0x71<<20 | 0xf<<12 | 0x1<<4 + case ADIVUHW: + return o | 0x73<<20 | 0xf<<12 | 0x1<<4 + case AMMUL: + return o | 0x75<<20 | 0xf<<12 | 0x1<<4 + case AMULS: + return o | 0x6<<20 | 0x9<<4 + case AMMULA: + return o | 0x75<<20 | 0x1<<4 + case AMMULS: + return o | 0x75<<20 | 0xd<<4 + case AMULU, AMUL: + return o | 0x0<<21 | 0x9<<4 + case AMULA: + return o | 0x1<<21 | 0x9<<4 + case AMULLU: + return o | 0x4<<21 | 0x9<<4 + case AMULL: + return o | 0x6<<21 | 0x9<<4 + case AMULALU: + return o | 0x5<<21 | 0x9<<4 + case AMULAL: + return o | 0x7<<21 | 0x9<<4 + case AAND: + return o | 0x0<<21 + case AEOR: + return o | 0x1<<21 + case ASUB: + return o | 0x2<<21 + case ARSB: + return o | 0x3<<21 + case AADD: + return o | 0x4<<21 + case AADC: + return o | 0x5<<21 + case ASBC: + return o | 0x6<<21 + case ARSC: + return o | 0x7<<21 + case ATST: + return o | 0x8<<21 | 1<<20 + case ATEQ: + return o | 0x9<<21 | 1<<20 + case ACMP: + return o | 0xa<<21 | 1<<20 + case ACMN: + return o | 0xb<<21 | 1<<20 + case AORR: + return o | 0xc<<21 + + case AMOVB, AMOVH, AMOVW: + if sc&(C_PBIT|C_WBIT) != 0 { + c.ctxt.Diag("invalid .P/.W suffix: %v", p) + } + return o | 0xd<<21 + case ABIC: + return o | 0xe<<21 + case AMVN: + return o | 0xf<<21 + case ASLL: + return o | 0xd<<21 | 0<<5 + case ASRL: + return o | 0xd<<21 | 1<<5 + case ASRA: + return o | 0xd<<21 | 2<<5 + case ASWI: + return o | 0xf<<24 + + case AADDD: + return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 + case AADDF: + return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 + case ASUBD: + return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 + case ASUBF: + return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 + case AMULD: + return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 + case AMULF: + return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 + case ANMULD: + return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4 + case ANMULF: + return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4 + case AMULAD: + return o | 0xe<<24 | 0xb<<8 + case AMULAF: + return o | 0xe<<24 | 0xa<<8 + case AMULSD: + return o | 0xe<<24 | 0xb<<8 | 0x4<<4 + case AMULSF: + return o | 0xe<<24 | 0xa<<8 | 0x4<<4 + case ANMULAD: + return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4 + case ANMULAF: + return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4 + case ANMULSD: + return o | 0xe<<24 | 0x1<<20 | 0xb<<8 + case ANMULSF: + return o | 0xe<<24 | 0x1<<20 | 0xa<<8 + case AFMULAD: + return o | 0xe<<24 | 0xa<<20 | 0xb<<8 + case AFMULAF: + return o | 0xe<<24 | 0xa<<20 | 0xa<<8 + case AFMULSD: + return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4 + case AFMULSF: + return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4 + case AFNMULAD: + return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4 + case AFNMULAF: + return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4 + case AFNMULSD: + return o | 0xe<<24 | 0x9<<20 | 0xb<<8 + case AFNMULSF: + return o | 0xe<<24 | 0x9<<20 | 0xa<<8 + case ADIVD: + return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 + case ADIVF: + return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 + case ASQRTD: + return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 + case ASQRTF: + return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 + case AABSD: + return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 + case AABSF: + return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 + case ANEGD: + return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4 + case ANEGF: + return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4 + case ACMPD: + return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 + case ACMPF: + return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 + + case AMOVF: + return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 + case AMOVD: + return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 + + case AMOVDF: + return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof + case AMOVFD: + return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof + + case AMOVWF: + if sc&C_UBIT == 0 { + o |= 1 << 7 /* signed */ + } + return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double + + case AMOVWD: + if sc&C_UBIT == 0 { + o |= 1 << 7 /* signed */ + } + return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double + + case AMOVFW: + if sc&C_UBIT == 0 { + o |= 1 << 16 /* signed */ + } + return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc + + case AMOVDW: + if sc&C_UBIT == 0 { + o |= 1 << 16 /* signed */ + } + return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc + + case -AMOVWF: // copy WtoF + return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 + + case -AMOVFW: // copy FtoW + return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 + + case -ACMP: // cmp imm + return o | 0x3<<24 | 0x5<<20 + + case ABFX: + return o | 0x3d<<21 | 0x5<<4 + + case ABFXU: + return o | 0x3f<<21 | 0x5<<4 + + case ABFC: + return o | 0x3e<<21 | 0x1f + + case ABFI: + return o | 0x3e<<21 | 0x1<<4 + + case AXTAB: + return o | 0x6a<<20 | 0x7<<4 + + case AXTAH: + return o | 0x6b<<20 | 0x7<<4 + + case AXTABU: + return o | 0x6e<<20 | 0x7<<4 + + case AXTAHU: + return o | 0x6f<<20 | 0x7<<4 + + // CLZ doesn't support .nil + case ACLZ: + return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 + + case AREV: + return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4 + + case AREV16: + return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4 + + case AREVSH: + return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4 + + case ARBIT: + return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4 + + case AMULWT: + return o&(0xf<<28) | 0x12<<20 | 0xe<<4 + + case AMULWB: + return o&(0xf<<28) | 0x12<<20 | 0xa<<4 + + case AMULBB: + return o&(0xf<<28) | 0x16<<20 | 0x8<<4 + + case AMULAWT: + return o&(0xf<<28) | 0x12<<20 | 0xc<<4 + + case AMULAWB: + return o&(0xf<<28) | 0x12<<20 | 0x8<<4 + + case AMULABB: + return o&(0xf<<28) | 0x10<<20 | 0x8<<4 + + case ABL: // BLX REG + return o&(0xf<<28) | 0x12fff3<<4 + } + + c.ctxt.Diag("%v: bad rrr %d", p, a) + return 0 +} + +func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 { + sc &= C_SCOND + sc ^= C_SCOND_XOR + if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { + return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 + } + if sc != 0xe { + c.ctxt.Diag("%v: .COND on bcond instruction", p) + } + switch a { + case ABEQ: + return 0x0<<28 | 0x5<<25 + case ABNE: + return 0x1<<28 | 0x5<<25 + case ABCS: + return 0x2<<28 | 0x5<<25 + case ABHS: + return 0x2<<28 | 0x5<<25 + case ABCC: + return 0x3<<28 | 0x5<<25 + case ABLO: + return 0x3<<28 | 0x5<<25 + case ABMI: + return 0x4<<28 | 0x5<<25 + case ABPL: + return 0x5<<28 | 0x5<<25 + case ABVS: + return 0x6<<28 | 0x5<<25 + case ABVC: + return 0x7<<28 | 0x5<<25 + case ABHI: + return 0x8<<28 | 0x5<<25 + case ABLS: + return 0x9<<28 | 0x5<<25 + case ABGE: + return 0xa<<28 | 0x5<<25 + case ABLT: + return 0xb<<28 | 0x5<<25 + case ABGT: + return 0xc<<28 | 0x5<<25 + case ABLE: + return 0xd<<28 | 0x5<<25 + case AB: + return 0xe<<28 | 0x5<<25 + } + + c.ctxt.Diag("%v: bad bra %v", p, a) + return 0 +} + +func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 { + o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 + if sc&C_PBIT == 0 { + o |= 1 << 24 + } + if sc&C_UBIT == 0 { + o |= 1 << 23 + } + if sc&C_WBIT != 0 { + o |= 1 << 21 + } + o |= 1<<26 | 1<<20 + if v < 0 { + if sc&C_UBIT != 0 { + c.ctxt.Diag(".U on neg offset") + } + v = -v + o ^= 1 << 23 + } + + if v >= 1<<12 || v < 0 { + c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) + } + o |= uint32(v) + o |= (uint32(b) & 15) << 16 + o |= (uint32(r) & 15) << 12 + return o +} + +func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 { + o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 + if sc&C_PBIT == 0 { + o |= 1 << 24 + } + if sc&C_WBIT != 0 { + o |= 1 << 21 + } + o |= 1<<23 | 1<<20 | 0xb<<4 + if v < 0 { + v = -v + o ^= 1 << 23 + } + + if v >= 1<<8 || v < 0 { + c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) + } + o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 + o |= (uint32(b) & 15) << 16 + o |= (uint32(r) & 15) << 12 + return o +} + +func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 { + o := c.olr(v, b, r, sc) ^ (1 << 20) + if a != AMOVW { + o |= 1 << 22 + } + return o +} + +func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 { + o := c.olhr(v, b, r, sc) ^ (1 << 20) + return o +} + +func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 { + return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20) +} + +func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 { + return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20) +} + +func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 { + return c.olr(int32(i), b, r, sc) ^ (1 << 25) +} + +func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 { + return c.olhr(int32(i), b, r, sc) ^ (1 << 22) +} + +func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 { + o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 + if sc&C_PBIT == 0 { + o |= 1 << 24 + } + if sc&C_WBIT != 0 { + o |= 1 << 21 + } + o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 + if v < 0 { + v = -v + o ^= 1 << 23 + } + + if v&3 != 0 { + c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) + } else if v >= 1<<10 || v < 0 { + c.ctxt.Diag("literal span too large: %d\n%v", v, p) + } + o |= (uint32(v) >> 2) & 0xFF + o |= (uint32(b) & 15) << 16 + o |= (uint32(r) & 15) << 12 + + switch a { + default: + c.ctxt.Diag("bad fst %v", a) + fallthrough + + case AMOVD: + o |= 1 << 8 + fallthrough + + case AMOVF: + break + } + + return o +} + +// MOVW $"lower 16-bit", Reg +func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 { + o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 + o1 |= 0x30 << 20 + o1 |= (uint32(dr) & 15) << 12 + o1 |= uint32(a.Offset) & 0x0fff + o1 |= (uint32(a.Offset) & 0xf000) << 4 + return o1 +} + +// MVN $C_NCON, Reg -> MOVW $C_RCON, Reg +func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 { + o1 := c.oprrr(p, AMOVW, int(p.Scond)) + o1 |= (uint32(dr) & 15) << 12 + v := immrot(^uint32(a.Offset)) + if v == 0 { + c.ctxt.Diag("%v: missing literal", p) + return 0 + } + o1 |= uint32(v) + return o1 +} + +func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 { + var o1 uint32 + if p.Pool == nil { + c.aclass(a) + v := immrot(^uint32(c.instoffset)) + if v == 0 { + c.ctxt.Diag("%v: missing literal", p) + return 0 + } + + o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND) + o1 |= uint32(v) + o1 |= (uint32(dr) & 15) << 12 + } else { + v := int32(p.Pool.Pc - p.Pc - 8) + o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND) + } + + return o1 +} + +func (c *ctxt5) chipzero5(e float64) int { + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if objabi.GOARM < 7 || math.Float64bits(e) != 0 { + return -1 + } + return 0 +} + +func (c *ctxt5) chipfloat5(e float64) int { + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if objabi.GOARM < 7 { + return -1 + } + + ei := math.Float64bits(e) + l := uint32(ei) + h := uint32(ei >> 32) + + if l != 0 || h&0xffff != 0 { + return -1 + } + h1 := h & 0x7fc00000 + if h1 != 0x40000000 && h1 != 0x3fc00000 { + return -1 + } + n := 0 + + // sign bit (a) + if h&0x80000000 != 0 { + n |= 1 << 7 + } + + // exp sign bit (b) + if h1 == 0x3fc00000 { + n |= 1 << 6 + } + + // rest of exp and mantissa (cd-efgh) + n |= int((h >> 16) & 0x3f) + + //print("match %.8lux %.8lux %d\n", l, h, n); + return n +} + +func nocache(p *obj.Prog) { + p.Optab = 0 + p.From.Class = 0 + if p.GetFrom3() != nil { + p.GetFrom3().Class = 0 + } + p.To.Class = 0 +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/list5.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/list5.go new file mode 100644 index 0000000..30e0300 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/list5.go @@ -0,0 +1,124 @@ +// Inferno utils/5c/list.c +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/list.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "fmt" +) + +func init() { + obj.RegisterRegister(obj.RBaseARM, MAXREG, rconv) + obj.RegisterOpcode(obj.ABaseARM, Anames) + obj.RegisterRegisterList(obj.RegListARMLo, obj.RegListARMHi, rlconv) + obj.RegisterOpSuffix("arm", obj.CConvARM) +} + +func rconv(r int) string { + if r == 0 { + return "NONE" + } + if r == REGG { + // Special case. + return "g" + } + if REG_R0 <= r && r <= REG_R15 { + return fmt.Sprintf("R%d", r-REG_R0) + } + if REG_F0 <= r && r <= REG_F15 { + return fmt.Sprintf("F%d", r-REG_F0) + } + + switch r { + case REG_FPSR: + return "FPSR" + + case REG_FPCR: + return "FPCR" + + case REG_CPSR: + return "CPSR" + + case REG_SPSR: + return "SPSR" + + case REG_MB_SY: + return "MB_SY" + case REG_MB_ST: + return "MB_ST" + case REG_MB_ISH: + return "MB_ISH" + case REG_MB_ISHST: + return "MB_ISHST" + case REG_MB_NSH: + return "MB_NSH" + case REG_MB_NSHST: + return "MB_NSHST" + case REG_MB_OSH: + return "MB_OSH" + case REG_MB_OSHST: + return "MB_OSHST" + } + + return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM) +} + +func DRconv(a int) string { + s := "C_??" + if a >= C_NONE && a <= C_NCLASS { + s = cnames5[a] + } + var fp string + fp += s + return fp +} + +func rlconv(list int64) string { + str := "" + for i := 0; i < 16; i++ { + if list&(1<, C13, C0, 3 specially. + case AMRC: + if p.To.Offset&0xffff0fff == 0xee1d0f70 { + // Because the instruction might be rewritten to a BL which returns in R0 + // the register must be zero. + if p.To.Offset&0xf000 != 0 { + ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line()) + } + + if objabi.GOARM < 7 { + // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension. + if progedit_tlsfallback == nil { + progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback") + } + + // MOVW LR, R11 + p.As = AMOVW + + p.From.Type = obj.TYPE_REG + p.From.Reg = REGLINK + p.To.Type = obj.TYPE_REG + p.To.Reg = REGTMP + + // BL runtime.read_tls_fallback(SB) + p = obj.Appendp(p, newprog) + + p.As = ABL + p.To.Type = obj.TYPE_BRANCH + p.To.Sym = progedit_tlsfallback + p.To.Offset = 0 + + // MOVW R11, LR + p = obj.Appendp(p, newprog) + + p.As = AMOVW + p.From.Type = obj.TYPE_REG + p.From.Reg = REGTMP + p.To.Type = obj.TYPE_REG + p.To.Reg = REGLINK + break + } + } + + // Otherwise, MRC/MCR instructions need no further treatment. + p.As = AWORD + } + + // Rewrite float constants to values stored in memory. + switch p.As { + case AMOVF: + if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { + f32 := float32(p.From.Val.(float64)) + p.From.Type = obj.TYPE_MEM + p.From.Sym = ctxt.Float32Sym(f32) + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } + + case AMOVD: + if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { + p.From.Type = obj.TYPE_MEM + p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64)) + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } + } + + if ctxt.Flag_dynlink { + c.rewriteToUseGot(p) + } +} + +// Rewrite p, if necessary, to access global data via the global offset table. +func (c *ctxt5) rewriteToUseGot(p *obj.Prog) { + if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { + // ADUFFxxx $offset + // becomes + // MOVW runtime.duffxxx@GOT, R9 + // ADD $offset, R9 + // CALL (R9) + var sym *obj.LSym + if p.As == obj.ADUFFZERO { + sym = c.ctxt.Lookup("runtime.duffzero") + } else { + sym = c.ctxt.Lookup("runtime.duffcopy") + } + offset := p.To.Offset + p.As = AMOVW + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_GOTREF + p.From.Sym = sym + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R9 + p.To.Name = obj.NAME_NONE + p.To.Offset = 0 + p.To.Sym = nil + p1 := obj.Appendp(p, c.newprog) + p1.As = AADD + p1.From.Type = obj.TYPE_CONST + p1.From.Offset = offset + p1.To.Type = obj.TYPE_REG + p1.To.Reg = REG_R9 + p2 := obj.Appendp(p1, c.newprog) + p2.As = obj.ACALL + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = REG_R9 + return + } + + // We only care about global data: NAME_EXTERN means a global + // symbol in the Go sense, and p.Sym.Local is true for a few + // internally defined symbols. + if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { + // MOVW $sym, Rx becomes MOVW sym@GOT, Rx + // MOVW $sym+, Rx becomes MOVW sym@GOT, Rx; ADD , Rx + if p.As != AMOVW { + c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) + } + if p.To.Type != obj.TYPE_REG { + c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) + } + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_GOTREF + if p.From.Offset != 0 { + q := obj.Appendp(p, c.newprog) + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = p.From.Offset + q.To = p.To + p.From.Offset = 0 + } + } + if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN { + c.ctxt.Diag("don't know how to handle %v with -dynlink", p) + } + var source *obj.Addr + // MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry + // MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9) + // An addition may be inserted between the two MOVs if there is an offset. + if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { + if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { + c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) + } + source = &p.From + } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { + source = &p.To + } else { + return + } + if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { + return + } + if source.Sym.Type == objabi.STLSBSS { + return + } + if source.Type != obj.TYPE_MEM { + c.ctxt.Diag("don't know how to handle %v with -dynlink", p) + } + p1 := obj.Appendp(p, c.newprog) + p2 := obj.Appendp(p1, c.newprog) + + p1.As = AMOVW + p1.From.Type = obj.TYPE_MEM + p1.From.Sym = source.Sym + p1.From.Name = obj.NAME_GOTREF + p1.To.Type = obj.TYPE_REG + p1.To.Reg = REG_R9 + + p2.As = p.As + p2.From = p.From + p2.To = p.To + if p.From.Name == obj.NAME_EXTERN { + p2.From.Reg = REG_R9 + p2.From.Name = obj.NAME_NONE + p2.From.Sym = nil + } else if p.To.Name == obj.NAME_EXTERN { + p2.To.Reg = REG_R9 + p2.To.Name = obj.NAME_NONE + p2.To.Sym = nil + } else { + return + } + obj.Nopout(p) +} + +// Prog.mark +const ( + FOLL = 1 << 0 + LABEL = 1 << 1 + LEAF = 1 << 2 +) + +func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { + autosize := int32(0) + + if cursym.Func.Text == nil || cursym.Func.Text.Link == nil { + return + } + + c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog} + + p := c.cursym.Func.Text + autoffset := int32(p.To.Offset) + if autoffset == -4 { + // Historical way to mark NOFRAME. + p.From.Sym.Set(obj.AttrNoFrame, true) + autoffset = 0 + } + if autoffset < 0 || autoffset%4 != 0 { + c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset) + } + if p.From.Sym.NoFrame() { + if autoffset != 0 { + c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset) + } + } + + cursym.Func.Locals = autoffset + cursym.Func.Args = p.To.Val.(int32) + + /* + * find leaf subroutines + */ + for p := cursym.Func.Text; p != nil; p = p.Link { + switch p.As { + case obj.ATEXT: + p.Mark |= LEAF + + case ADIV, ADIVU, AMOD, AMODU: + cursym.Func.Text.Mark &^= LEAF + + case ABL, + ABX, + obj.ADUFFZERO, + obj.ADUFFCOPY: + cursym.Func.Text.Mark &^= LEAF + } + } + + var q2 *obj.Prog + for p := cursym.Func.Text; p != nil; p = p.Link { + o := p.As + switch o { + case obj.ATEXT: + autosize = autoffset + + if p.Mark&LEAF != 0 && autosize == 0 { + // A leaf function with no locals has no frame. + p.From.Sym.Set(obj.AttrNoFrame, true) + } + + if !p.From.Sym.NoFrame() { + // If there is a stack frame at all, it includes + // space to save the LR. + autosize += 4 + } + + if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 { + // A very few functions that do not return to their caller + // are not identified as leaves but still have no frame. + if ctxt.Debugvlog { + ctxt.Logf("save suppressed in: %s\n", cursym.Name) + } + + cursym.Func.Text.Mark |= LEAF + } + + // FP offsets need an updated p.To.Offset. + p.To.Offset = int64(autosize) - 4 + + if cursym.Func.Text.Mark&LEAF != 0 { + cursym.Set(obj.AttrLeaf, true) + if p.From.Sym.NoFrame() { + break + } + } + + if !p.From.Sym.NoSplit() { + p = c.stacksplit(p, autosize) // emit split check + } + + // MOVW.W R14,$-autosize(SP) + p = obj.Appendp(p, c.newprog) + + p.As = AMOVW + p.Scond |= C_WBIT + p.From.Type = obj.TYPE_REG + p.From.Reg = REGLINK + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(-autosize) + p.To.Reg = REGSP + p.Spadj = autosize + + if cursym.Func.Text.From.Sym.Wrapper() { + // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame + // + // MOVW g_panic(g), R1 + // CMP $0, R1 + // B.NE checkargp + // end: + // NOP + // ... function ... + // checkargp: + // MOVW panic_argp(R1), R2 + // ADD $(autosize+4), R13, R3 + // CMP R2, R3 + // B.NE end + // ADD $4, R13, R4 + // MOVW R4, panic_argp(R1) + // B end + // + // The NOP is needed to give the jumps somewhere to land. + // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes. + + p = obj.Appendp(p, newprog) + p.As = AMOVW + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGG + p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R1 + + p = obj.Appendp(p, newprog) + p.As = ACMP + p.From.Type = obj.TYPE_CONST + p.From.Offset = 0 + p.Reg = REG_R1 + + // B.NE checkargp + bne := obj.Appendp(p, newprog) + bne.As = ABNE + bne.To.Type = obj.TYPE_BRANCH + + // end: NOP + end := obj.Appendp(bne, newprog) + end.As = obj.ANOP + + // find end of function + var last *obj.Prog + for last = end; last.Link != nil; last = last.Link { + } + + // MOVW panic_argp(R1), R2 + mov := obj.Appendp(last, newprog) + mov.As = AMOVW + mov.From.Type = obj.TYPE_MEM + mov.From.Reg = REG_R1 + mov.From.Offset = 0 // Panic.argp + mov.To.Type = obj.TYPE_REG + mov.To.Reg = REG_R2 + + // B.NE branch target is MOVW above + bne.To.SetTarget(mov) + + // ADD $(autosize+4), R13, R3 + p = obj.Appendp(mov, newprog) + p.As = AADD + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(autosize) + 4 + p.Reg = REG_R13 + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R3 + + // CMP R2, R3 + p = obj.Appendp(p, newprog) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R2 + p.Reg = REG_R3 + + // B.NE end + p = obj.Appendp(p, newprog) + p.As = ABNE + p.To.Type = obj.TYPE_BRANCH + p.To.SetTarget(end) + + // ADD $4, R13, R4 + p = obj.Appendp(p, newprog) + p.As = AADD + p.From.Type = obj.TYPE_CONST + p.From.Offset = 4 + p.Reg = REG_R13 + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R4 + + // MOVW R4, panic_argp(R1) + p = obj.Appendp(p, newprog) + p.As = AMOVW + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R4 + p.To.Type = obj.TYPE_MEM + p.To.Reg = REG_R1 + p.To.Offset = 0 // Panic.argp + + // B end + p = obj.Appendp(p, newprog) + p.As = AB + p.To.Type = obj.TYPE_BRANCH + p.To.SetTarget(end) + + // reset for subsequent passes + p = end + } + + case obj.ARET: + nocache(p) + if cursym.Func.Text.Mark&LEAF != 0 { + if autosize == 0 { + p.As = AB + p.From = obj.Addr{} + if p.To.Sym != nil { // retjmp + p.To.Type = obj.TYPE_BRANCH + } else { + p.To.Type = obj.TYPE_MEM + p.To.Offset = 0 + p.To.Reg = REGLINK + } + + break + } + } + + p.As = AMOVW + p.Scond |= C_PBIT + p.From.Type = obj.TYPE_MEM + p.From.Offset = int64(autosize) + p.From.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REGPC + + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so no spadj. + if p.To.Sym != nil { // retjmp + p.To.Reg = REGLINK + q2 = obj.Appendp(p, newprog) + q2.As = AB + q2.To.Type = obj.TYPE_BRANCH + q2.To.Sym = p.To.Sym + p.To.Sym = nil + p = q2 + } + + case AADD: + if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { + p.Spadj = int32(-p.From.Offset) + } + + case ASUB: + if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { + p.Spadj = int32(p.From.Offset) + } + + case ADIV, ADIVU, AMOD, AMODU: + if cursym.Func.Text.From.Sym.NoSplit() { + ctxt.Diag("cannot divide in NOSPLIT function") + } + const debugdivmod = false + if debugdivmod { + break + } + if p.From.Type != obj.TYPE_REG { + break + } + if p.To.Type != obj.TYPE_REG { + break + } + + // Make copy because we overwrite p below. + q1 := *p + if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP { + ctxt.Diag("div already using REGTMP: %v", p) + } + + /* MOV m(g),REGTMP */ + p.As = AMOVW + p.Pos = q1.Pos + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGG + p.From.Offset = 6 * 4 // offset of g.m + p.Reg = 0 + p.To.Type = obj.TYPE_REG + p.To.Reg = REGTMP + + /* MOV a,m_divmod(REGTMP) */ + p = obj.Appendp(p, newprog) + p.As = AMOVW + p.Pos = q1.Pos + p.From.Type = obj.TYPE_REG + p.From.Reg = q1.From.Reg + p.To.Type = obj.TYPE_MEM + p.To.Reg = REGTMP + p.To.Offset = 8 * 4 // offset of m.divmod + + /* MOV b, R8 */ + p = obj.Appendp(p, newprog) + p.As = AMOVW + p.Pos = q1.Pos + p.From.Type = obj.TYPE_REG + p.From.Reg = q1.Reg + if q1.Reg == 0 { + p.From.Reg = q1.To.Reg + } + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R8 + p.To.Offset = 0 + + /* CALL appropriate */ + p = obj.Appendp(p, newprog) + p.As = ABL + p.Pos = q1.Pos + p.To.Type = obj.TYPE_BRANCH + switch o { + case ADIV: + p.To.Sym = symdiv + case ADIVU: + p.To.Sym = symdivu + case AMOD: + p.To.Sym = symmod + case AMODU: + p.To.Sym = symmodu + } + + /* MOV REGTMP, b */ + p = obj.Appendp(p, newprog) + p.As = AMOVW + p.Pos = q1.Pos + p.From.Type = obj.TYPE_REG + p.From.Reg = REGTMP + p.From.Offset = 0 + p.To.Type = obj.TYPE_REG + p.To.Reg = q1.To.Reg + + case AMOVW: + if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP { + p.Spadj = int32(-p.To.Offset) + } + if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC { + p.Spadj = int32(-p.From.Offset) + } + if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { + p.Spadj = int32(-p.From.Offset) + } + + case obj.AGETCALLERPC: + if cursym.Leaf() { + /* MOVW LR, Rd */ + p.As = AMOVW + p.From.Type = obj.TYPE_REG + p.From.Reg = REGLINK + } else { + /* MOVW (RSP), Rd */ + p.As = AMOVW + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGSP + } + } + } +} + +func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { + // MOVW g_stackguard(g), R1 + p = obj.Appendp(p, c.newprog) + + p.As = AMOVW + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGG + p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 + if c.cursym.CFunc() { + p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 + } + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R1 + + // Mark the stack bound check and morestack call async nonpreemptible. + // If we get preempted here, when resumed the preemption request is + // cleared, but we'll still call morestack, which will double the stack + // unnecessarily. See issue #35470. + p = c.ctxt.StartUnsafePoint(p, c.newprog) + + if framesize <= objabi.StackSmall { + // small stack: SP < stackguard + // CMP stackguard, SP + p = obj.Appendp(p, c.newprog) + + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.Reg = REGSP + } else if framesize <= objabi.StackBig { + // large stack: SP-framesize < stackguard-StackSmall + // MOVW $-(framesize-StackSmall)(SP), R2 + // CMP stackguard, R2 + p = obj.Appendp(p, c.newprog) + + p.As = AMOVW + p.From.Type = obj.TYPE_ADDR + p.From.Reg = REGSP + p.From.Offset = -(int64(framesize) - objabi.StackSmall) + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + + p = obj.Appendp(p, c.newprog) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.Reg = REG_R2 + } else { + // Such a large stack we need to protect against wraparound + // if SP is close to zero. + // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) + // The +StackGuard on both sides is required to keep the left side positive: + // SP is allowed to be slightly below stackguard. See stack.h. + // CMP $StackPreempt, R1 + // MOVW.NE $StackGuard(SP), R2 + // SUB.NE R1, R2 + // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 + // CMP.NE R3, R2 + p = obj.Appendp(p, c.newprog) + + p.As = ACMP + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1))) + p.Reg = REG_R1 + + p = obj.Appendp(p, c.newprog) + p.As = AMOVW + p.From.Type = obj.TYPE_ADDR + p.From.Reg = REGSP + p.From.Offset = int64(objabi.StackGuard) + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + p.Scond = C_SCOND_NE + + p = obj.Appendp(p, c.newprog) + p.As = ASUB + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + p.Scond = C_SCOND_NE + + p = obj.Appendp(p, c.newprog) + p.As = AMOVW + p.From.Type = obj.TYPE_ADDR + p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall) + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R3 + p.Scond = C_SCOND_NE + + p = obj.Appendp(p, c.newprog) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R3 + p.Reg = REG_R2 + p.Scond = C_SCOND_NE + } + + // BLS call-to-morestack + bls := obj.Appendp(p, c.newprog) + bls.As = ABLS + bls.To.Type = obj.TYPE_BRANCH + + end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1) + + var last *obj.Prog + for last = c.cursym.Func.Text; last.Link != nil; last = last.Link { + } + + // Now we are at the end of the function, but logically + // we are still in function prologue. We need to fix the + // SP data and PCDATA. + spfix := obj.Appendp(last, c.newprog) + spfix.As = obj.ANOP + spfix.Spadj = -framesize + + pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog) + pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog) + + // MOVW LR, R3 + movw := obj.Appendp(pcdata, c.newprog) + movw.As = AMOVW + movw.From.Type = obj.TYPE_REG + movw.From.Reg = REGLINK + movw.To.Type = obj.TYPE_REG + movw.To.Reg = REG_R3 + + bls.To.SetTarget(movw) + + // BL runtime.morestack + call := obj.Appendp(movw, c.newprog) + call.As = obj.ACALL + call.To.Type = obj.TYPE_BRANCH + morestack := "runtime.morestack" + switch { + case c.cursym.CFunc(): + morestack = "runtime.morestackc" + case !c.cursym.Func.Text.From.Sym.NeedCtxt(): + morestack = "runtime.morestack_noctxt" + } + call.To.Sym = c.ctxt.Lookup(morestack) + + pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1) + + // B start + b := obj.Appendp(pcdata, c.newprog) + b.As = obj.AJMP + b.To.Type = obj.TYPE_BRANCH + b.To.SetTarget(c.cursym.Func.Text.Link) + b.Spadj = +framesize + + return end +} + +var unaryDst = map[obj.As]bool{ + ASWI: true, + AWORD: true, +} + +var Linkarm = obj.LinkArch{ + Arch: sys.ArchARM, + Init: buildop, + Preprocess: preprocess, + Assemble: span5, + Progedit: progedit, + UnaryDst: unaryDst, + DWARFRegisters: ARMDWARFRegisters, +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/a.out.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/a.out.go new file mode 100644 index 0000000..04c084e --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/a.out.go @@ -0,0 +1,1033 @@ +// cmd/7c/7.out.h from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/src/cmd/7c/7.out.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import "github.com/twitchyliquid64/golang-asm/obj" + +const ( + NSNAME = 8 + NSYM = 50 + NREG = 32 /* number of general registers */ + NFREG = 32 /* number of floating point registers */ +) + +// General purpose registers, kept in the low bits of Prog.Reg. +const ( + // integer + REG_R0 = obj.RBaseARM64 + iota + REG_R1 + REG_R2 + REG_R3 + REG_R4 + REG_R5 + REG_R6 + REG_R7 + REG_R8 + REG_R9 + REG_R10 + REG_R11 + REG_R12 + REG_R13 + REG_R14 + REG_R15 + REG_R16 + REG_R17 + REG_R18 + REG_R19 + REG_R20 + REG_R21 + REG_R22 + REG_R23 + REG_R24 + REG_R25 + REG_R26 + REG_R27 + REG_R28 + REG_R29 + REG_R30 + REG_R31 + + // scalar floating point + REG_F0 + REG_F1 + REG_F2 + REG_F3 + REG_F4 + REG_F5 + REG_F6 + REG_F7 + REG_F8 + REG_F9 + REG_F10 + REG_F11 + REG_F12 + REG_F13 + REG_F14 + REG_F15 + REG_F16 + REG_F17 + REG_F18 + REG_F19 + REG_F20 + REG_F21 + REG_F22 + REG_F23 + REG_F24 + REG_F25 + REG_F26 + REG_F27 + REG_F28 + REG_F29 + REG_F30 + REG_F31 + + // SIMD + REG_V0 + REG_V1 + REG_V2 + REG_V3 + REG_V4 + REG_V5 + REG_V6 + REG_V7 + REG_V8 + REG_V9 + REG_V10 + REG_V11 + REG_V12 + REG_V13 + REG_V14 + REG_V15 + REG_V16 + REG_V17 + REG_V18 + REG_V19 + REG_V20 + REG_V21 + REG_V22 + REG_V23 + REG_V24 + REG_V25 + REG_V26 + REG_V27 + REG_V28 + REG_V29 + REG_V30 + REG_V31 + + // The EQ in + // CSET EQ, R0 + // is encoded as TYPE_REG, even though it's not really a register. + COND_EQ + COND_NE + COND_HS + COND_LO + COND_MI + COND_PL + COND_VS + COND_VC + COND_HI + COND_LS + COND_GE + COND_LT + COND_GT + COND_LE + COND_AL + COND_NV + + REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31 +) + +// bits 0-4 indicates register: Vn +// bits 5-8 indicates arrangement: +const ( + REG_ARNG = obj.RBaseARM64 + 1<<10 + iota<<9 // Vn. + REG_ELEM // Vn.[index] + REG_ELEM_END +) + +// Not registers, but flags that can be combined with regular register +// constants to indicate extended register conversion. When checking, +// you should subtract obj.RBaseARM64 first. From this difference, bit 11 +// indicates extended register, bits 8-10 select the conversion mode. +// REG_LSL is the index shift specifier, bit 9 indicates shifted offset register. +const REG_LSL = obj.RBaseARM64 + 1<<9 +const REG_EXT = obj.RBaseARM64 + 1<<11 + +const ( + REG_UXTB = REG_EXT + iota<<8 + REG_UXTH + REG_UXTW + REG_UXTX + REG_SXTB + REG_SXTH + REG_SXTW + REG_SXTX +) + +// Special registers, after subtracting obj.RBaseARM64, bit 12 indicates +// a special register and the low bits select the register. +// SYSREG_END is the last item in the automatically generated system register +// declaration, and it is defined in the sysRegEnc.go file. +const ( + REG_SPECIAL = obj.RBaseARM64 + 1<<12 + REG_DAIFSet = SYSREG_END + iota + REG_DAIFClr + REG_PLDL1KEEP + REG_PLDL1STRM + REG_PLDL2KEEP + REG_PLDL2STRM + REG_PLDL3KEEP + REG_PLDL3STRM + REG_PLIL1KEEP + REG_PLIL1STRM + REG_PLIL2KEEP + REG_PLIL2STRM + REG_PLIL3KEEP + REG_PLIL3STRM + REG_PSTL1KEEP + REG_PSTL1STRM + REG_PSTL2KEEP + REG_PSTL2STRM + REG_PSTL3KEEP + REG_PSTL3STRM +) + +// Register assignments: +// +// compiler allocates R0 up as temps +// compiler allocates register variables R7-R25 +// compiler allocates external registers R26 down +// +// compiler allocates register variables F7-F26 +// compiler allocates external registers F26 down +const ( + REGMIN = REG_R7 // register variables allocated from here to REGMAX + REGRT1 = REG_R16 // ARM64 IP0, external linker may use as a scrach register in trampoline + REGRT2 = REG_R17 // ARM64 IP1, external linker may use as a scrach register in trampoline + REGPR = REG_R18 // ARM64 platform register, unused in the Go toolchain + REGMAX = REG_R25 + + REGCTXT = REG_R26 // environment for closures + REGTMP = REG_R27 // reserved for liblink + REGG = REG_R28 // G + REGFP = REG_R29 // frame pointer, unused in the Go toolchain + REGLINK = REG_R30 + + // ARM64 uses R31 as both stack pointer and zero register, + // depending on the instruction. To differentiate RSP from ZR, + // we use a different numeric value for REGZERO and REGSP. + REGZERO = REG_R31 + REGSP = REG_RSP + + FREGRET = REG_F0 + FREGMIN = REG_F7 // first register variable + FREGMAX = REG_F26 // last register variable for 7g only + FREGEXT = REG_F26 // first external register +) + +// http://infocenter.arm.com/help/topic/com.arm.doc.ecm0665627/abi_sve_aadwarf_100985_0000_00_en.pdf +var ARM64DWARFRegisters = map[int16]int16{ + REG_R0: 0, + REG_R1: 1, + REG_R2: 2, + REG_R3: 3, + REG_R4: 4, + REG_R5: 5, + REG_R6: 6, + REG_R7: 7, + REG_R8: 8, + REG_R9: 9, + REG_R10: 10, + REG_R11: 11, + REG_R12: 12, + REG_R13: 13, + REG_R14: 14, + REG_R15: 15, + REG_R16: 16, + REG_R17: 17, + REG_R18: 18, + REG_R19: 19, + REG_R20: 20, + REG_R21: 21, + REG_R22: 22, + REG_R23: 23, + REG_R24: 24, + REG_R25: 25, + REG_R26: 26, + REG_R27: 27, + REG_R28: 28, + REG_R29: 29, + REG_R30: 30, + + // floating point + REG_F0: 64, + REG_F1: 65, + REG_F2: 66, + REG_F3: 67, + REG_F4: 68, + REG_F5: 69, + REG_F6: 70, + REG_F7: 71, + REG_F8: 72, + REG_F9: 73, + REG_F10: 74, + REG_F11: 75, + REG_F12: 76, + REG_F13: 77, + REG_F14: 78, + REG_F15: 79, + REG_F16: 80, + REG_F17: 81, + REG_F18: 82, + REG_F19: 83, + REG_F20: 84, + REG_F21: 85, + REG_F22: 86, + REG_F23: 87, + REG_F24: 88, + REG_F25: 89, + REG_F26: 90, + REG_F27: 91, + REG_F28: 92, + REG_F29: 93, + REG_F30: 94, + REG_F31: 95, + + // SIMD + REG_V0: 64, + REG_V1: 65, + REG_V2: 66, + REG_V3: 67, + REG_V4: 68, + REG_V5: 69, + REG_V6: 70, + REG_V7: 71, + REG_V8: 72, + REG_V9: 73, + REG_V10: 74, + REG_V11: 75, + REG_V12: 76, + REG_V13: 77, + REG_V14: 78, + REG_V15: 79, + REG_V16: 80, + REG_V17: 81, + REG_V18: 82, + REG_V19: 83, + REG_V20: 84, + REG_V21: 85, + REG_V22: 86, + REG_V23: 87, + REG_V24: 88, + REG_V25: 89, + REG_V26: 90, + REG_V27: 91, + REG_V28: 92, + REG_V29: 93, + REG_V30: 94, + REG_V31: 95, +} + +const ( + BIG = 2048 - 8 +) + +const ( + /* mark flags */ + LABEL = 1 << iota + LEAF + FLOAT + BRANCH + LOAD + FCMP + SYNC + LIST + FOLL + NOSCHED +) + +const ( + // optab is sorted based on the order of these constants + // and the first match is chosen. + // The more specific class needs to come earlier. + C_NONE = iota + C_REG // R0..R30 + C_RSP // R0..R30, RSP + C_FREG // F0..F31 + C_VREG // V0..V31 + C_PAIR // (Rn, Rm) + C_SHIFT // Rn<<2 + C_EXTREG // Rn.UXTB[<<3] + C_SPR // REG_NZCV + C_COND // EQ, NE, etc + C_ARNG // Vn. + C_ELEM // Vn.[index] + C_LIST // [V1, V2, V3] + + C_ZCON // $0 or ZR + C_ABCON0 // could be C_ADDCON0 or C_BITCON + C_ADDCON0 // 12-bit unsigned, unshifted + C_ABCON // could be C_ADDCON or C_BITCON + C_AMCON // could be C_ADDCON or C_MOVCON + C_ADDCON // 12-bit unsigned, shifted left by 0 or 12 + C_MBCON // could be C_MOVCON or C_BITCON + C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16 + C_BITCON // bitfield and logical immediate masks + C_ADDCON2 // 24-bit constant + C_LCON // 32-bit constant + C_MOVCON2 // a constant that can be loaded with one MOVZ/MOVN and one MOVK + C_MOVCON3 // a constant that can be loaded with one MOVZ/MOVN and two MOVKs + C_VCON // 64-bit constant + C_FCON // floating-point constant + C_VCONADDR // 64-bit memory address + + C_AACON // ADDCON offset in auto constant $a(FP) + C_AACON2 // 24-bit offset in auto constant $a(FP) + C_LACON // 32-bit offset in auto constant $a(FP) + C_AECON // ADDCON offset in extern constant $e(SB) + + // TODO(aram): only one branch class should be enough + C_SBRA // for TYPE_BRANCH + C_LBRA + + C_ZAUTO // 0(RSP) + C_NSAUTO_8 // -256 <= x < 0, 0 mod 8 + C_NSAUTO_4 // -256 <= x < 0, 0 mod 4 + C_NSAUTO // -256 <= x < 0 + C_NPAUTO // -512 <= x < 0, 0 mod 8 + C_NAUTO4K // -4095 <= x < 0 + C_PSAUTO_8 // 0 to 255, 0 mod 8 + C_PSAUTO_4 // 0 to 255, 0 mod 4 + C_PSAUTO // 0 to 255 + C_PPAUTO // 0 to 504, 0 mod 8 + C_UAUTO4K_8 // 0 to 4095, 0 mod 8 + C_UAUTO4K_4 // 0 to 4095, 0 mod 4 + C_UAUTO4K_2 // 0 to 4095, 0 mod 2 + C_UAUTO4K // 0 to 4095 + C_UAUTO8K_8 // 0 to 8190, 0 mod 8 + C_UAUTO8K_4 // 0 to 8190, 0 mod 4 + C_UAUTO8K // 0 to 8190, 0 mod 2 + C_UAUTO16K_8 // 0 to 16380, 0 mod 8 + C_UAUTO16K // 0 to 16380, 0 mod 4 + C_UAUTO32K // 0 to 32760, 0 mod 8 + C_LAUTO // any other 32-bit constant + + C_SEXT1 // 0 to 4095, direct + C_SEXT2 // 0 to 8190 + C_SEXT4 // 0 to 16380 + C_SEXT8 // 0 to 32760 + C_SEXT16 // 0 to 65520 + C_LEXT + + C_ZOREG // 0(R) + C_NSOREG_8 // must mirror C_NSAUTO_8, etc + C_NSOREG_4 + C_NSOREG + C_NPOREG + C_NOREG4K + C_PSOREG_8 + C_PSOREG_4 + C_PSOREG + C_PPOREG + C_UOREG4K_8 + C_UOREG4K_4 + C_UOREG4K_2 + C_UOREG4K + C_UOREG8K_8 + C_UOREG8K_4 + C_UOREG8K + C_UOREG16K_8 + C_UOREG16K + C_UOREG32K + C_LOREG + + C_ADDR // TODO(aram): explain difference from C_VCONADDR + + // The GOT slot for a symbol in -dynlink mode. + C_GOTADDR + + // TLS "var" in local exec mode: will become a constant offset from + // thread local base that is ultimately chosen by the program linker. + C_TLS_LE + + // TLS "var" in initial exec mode: will become a memory address (chosen + // by the program linker) that the dynamic linker will fill with the + // offset from the thread local base. + C_TLS_IE + + C_ROFF // register offset (including register extended) + + C_GOK + C_TEXTSIZE + C_NCLASS // must be last +) + +const ( + C_XPRE = 1 << 6 // match arm.C_WBIT, so Prog.String know how to print it + C_XPOST = 1 << 5 // match arm.C_PBIT, so Prog.String know how to print it +) + +//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm64 + +const ( + AADC = obj.ABaseARM64 + obj.A_ARCHSPECIFIC + iota + AADCS + AADCSW + AADCW + AADD + AADDS + AADDSW + AADDW + AADR + AADRP + AAND + AANDS + AANDSW + AANDW + AASR + AASRW + AAT + ABFI + ABFIW + ABFM + ABFMW + ABFXIL + ABFXILW + ABIC + ABICS + ABICSW + ABICW + ABRK + ACBNZ + ACBNZW + ACBZ + ACBZW + ACCMN + ACCMNW + ACCMP + ACCMPW + ACINC + ACINCW + ACINV + ACINVW + ACLREX + ACLS + ACLSW + ACLZ + ACLZW + ACMN + ACMNW + ACMP + ACMPW + ACNEG + ACNEGW + ACRC32B + ACRC32CB + ACRC32CH + ACRC32CW + ACRC32CX + ACRC32H + ACRC32W + ACRC32X + ACSEL + ACSELW + ACSET + ACSETM + ACSETMW + ACSETW + ACSINC + ACSINCW + ACSINV + ACSINVW + ACSNEG + ACSNEGW + ADC + ADCPS1 + ADCPS2 + ADCPS3 + ADMB + ADRPS + ADSB + AEON + AEONW + AEOR + AEORW + AERET + AEXTR + AEXTRW + AHINT + AHLT + AHVC + AIC + AISB + ALDADDAB + ALDADDAD + ALDADDAH + ALDADDAW + ALDADDALB + ALDADDALD + ALDADDALH + ALDADDALW + ALDADDB + ALDADDD + ALDADDH + ALDADDW + ALDADDLB + ALDADDLD + ALDADDLH + ALDADDLW + ALDANDAB + ALDANDAD + ALDANDAH + ALDANDAW + ALDANDALB + ALDANDALD + ALDANDALH + ALDANDALW + ALDANDB + ALDANDD + ALDANDH + ALDANDW + ALDANDLB + ALDANDLD + ALDANDLH + ALDANDLW + ALDAR + ALDARB + ALDARH + ALDARW + ALDAXP + ALDAXPW + ALDAXR + ALDAXRB + ALDAXRH + ALDAXRW + ALDEORAB + ALDEORAD + ALDEORAH + ALDEORAW + ALDEORALB + ALDEORALD + ALDEORALH + ALDEORALW + ALDEORB + ALDEORD + ALDEORH + ALDEORW + ALDEORLB + ALDEORLD + ALDEORLH + ALDEORLW + ALDORAB + ALDORAD + ALDORAH + ALDORAW + ALDORALB + ALDORALD + ALDORALH + ALDORALW + ALDORB + ALDORD + ALDORH + ALDORW + ALDORLB + ALDORLD + ALDORLH + ALDORLW + ALDP + ALDPW + ALDPSW + ALDXR + ALDXRB + ALDXRH + ALDXRW + ALDXP + ALDXPW + ALSL + ALSLW + ALSR + ALSRW + AMADD + AMADDW + AMNEG + AMNEGW + AMOVK + AMOVKW + AMOVN + AMOVNW + AMOVZ + AMOVZW + AMRS + AMSR + AMSUB + AMSUBW + AMUL + AMULW + AMVN + AMVNW + ANEG + ANEGS + ANEGSW + ANEGW + ANGC + ANGCS + ANGCSW + ANGCW + ANOOP + AORN + AORNW + AORR + AORRW + APRFM + APRFUM + ARBIT + ARBITW + AREM + AREMW + AREV + AREV16 + AREV16W + AREV32 + AREVW + AROR + ARORW + ASBC + ASBCS + ASBCSW + ASBCW + ASBFIZ + ASBFIZW + ASBFM + ASBFMW + ASBFX + ASBFXW + ASDIV + ASDIVW + ASEV + ASEVL + ASMADDL + ASMC + ASMNEGL + ASMSUBL + ASMULH + ASMULL + ASTXR + ASTXRB + ASTXRH + ASTXP + ASTXPW + ASTXRW + ASTLP + ASTLPW + ASTLR + ASTLRB + ASTLRH + ASTLRW + ASTLXP + ASTLXPW + ASTLXR + ASTLXRB + ASTLXRH + ASTLXRW + ASTP + ASTPW + ASUB + ASUBS + ASUBSW + ASUBW + ASVC + ASXTB + ASXTBW + ASXTH + ASXTHW + ASXTW + ASYS + ASYSL + ATBNZ + ATBZ + ATLBI + ATST + ATSTW + AUBFIZ + AUBFIZW + AUBFM + AUBFMW + AUBFX + AUBFXW + AUDIV + AUDIVW + AUMADDL + AUMNEGL + AUMSUBL + AUMULH + AUMULL + AUREM + AUREMW + AUXTB + AUXTH + AUXTW + AUXTBW + AUXTHW + AWFE + AWFI + AYIELD + AMOVB + AMOVBU + AMOVH + AMOVHU + AMOVW + AMOVWU + AMOVD + AMOVNP + AMOVNPW + AMOVP + AMOVPD + AMOVPQ + AMOVPS + AMOVPSW + AMOVPW + ASWPAD + ASWPAW + ASWPAH + ASWPAB + ASWPALD + ASWPALW + ASWPALH + ASWPALB + ASWPD + ASWPW + ASWPH + ASWPB + ASWPLD + ASWPLW + ASWPLH + ASWPLB + ABEQ + ABNE + ABCS + ABHS + ABCC + ABLO + ABMI + ABPL + ABVS + ABVC + ABHI + ABLS + ABGE + ABLT + ABGT + ABLE + AFABSD + AFABSS + AFADDD + AFADDS + AFCCMPD + AFCCMPED + AFCCMPS + AFCCMPES + AFCMPD + AFCMPED + AFCMPES + AFCMPS + AFCVTSD + AFCVTDS + AFCVTZSD + AFCVTZSDW + AFCVTZSS + AFCVTZSSW + AFCVTZUD + AFCVTZUDW + AFCVTZUS + AFCVTZUSW + AFDIVD + AFDIVS + AFLDPD + AFLDPS + AFMOVD + AFMOVS + AFMOVQ + AFMULD + AFMULS + AFNEGD + AFNEGS + AFSQRTD + AFSQRTS + AFSTPD + AFSTPS + AFSUBD + AFSUBS + ASCVTFD + ASCVTFS + ASCVTFWD + ASCVTFWS + AUCVTFD + AUCVTFS + AUCVTFWD + AUCVTFWS + AWORD + ADWORD + AFCSELS + AFCSELD + AFMAXS + AFMINS + AFMAXD + AFMIND + AFMAXNMS + AFMAXNMD + AFNMULS + AFNMULD + AFRINTNS + AFRINTND + AFRINTPS + AFRINTPD + AFRINTMS + AFRINTMD + AFRINTZS + AFRINTZD + AFRINTAS + AFRINTAD + AFRINTXS + AFRINTXD + AFRINTIS + AFRINTID + AFMADDS + AFMADDD + AFMSUBS + AFMSUBD + AFNMADDS + AFNMADDD + AFNMSUBS + AFNMSUBD + AFMINNMS + AFMINNMD + AFCVTDH + AFCVTHS + AFCVTHD + AFCVTSH + AAESD + AAESE + AAESIMC + AAESMC + ASHA1C + ASHA1H + ASHA1M + ASHA1P + ASHA1SU0 + ASHA1SU1 + ASHA256H + ASHA256H2 + ASHA256SU0 + ASHA256SU1 + ASHA512H + ASHA512H2 + ASHA512SU0 + ASHA512SU1 + AVADD + AVADDP + AVAND + AVBIF + AVCMEQ + AVCNT + AVEOR + AVMOV + AVLD1 + AVLD2 + AVLD3 + AVLD4 + AVLD1R + AVLD2R + AVLD3R + AVLD4R + AVORR + AVREV16 + AVREV32 + AVREV64 + AVST1 + AVST2 + AVST3 + AVST4 + AVDUP + AVADDV + AVMOVI + AVUADDLV + AVSUB + AVFMLA + AVFMLS + AVPMULL + AVPMULL2 + AVEXT + AVRBIT + AVUSHR + AVUSHLL + AVUSHLL2 + AVUXTL + AVUXTL2 + AVUZP1 + AVUZP2 + AVSHL + AVSRI + AVBSL + AVBIT + AVTBL + AVZIP1 + AVZIP2 + AVCMTST + ALAST + AB = obj.AJMP + ABL = obj.ACALL +) + +const ( + // shift types + SHIFT_LL = 0 << 22 + SHIFT_LR = 1 << 22 + SHIFT_AR = 2 << 22 +) + +// Arrangement for ARM64 SIMD instructions +const ( + // arrangement types + ARNG_8B = iota + ARNG_16B + ARNG_1D + ARNG_4H + ARNG_8H + ARNG_2S + ARNG_4S + ARNG_2D + ARNG_1Q + ARNG_B + ARNG_H + ARNG_S + ARNG_D +) diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames.go new file mode 100644 index 0000000..0ce620a --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames.go @@ -0,0 +1,512 @@ +// Code generated by stringer -i a.out.go -o anames.go -p arm64; DO NOT EDIT. + +package arm64 + +import "github.com/twitchyliquid64/golang-asm/obj" + +var Anames = []string{ + obj.A_ARCHSPECIFIC: "ADC", + "ADCS", + "ADCSW", + "ADCW", + "ADD", + "ADDS", + "ADDSW", + "ADDW", + "ADR", + "ADRP", + "AND", + "ANDS", + "ANDSW", + "ANDW", + "ASR", + "ASRW", + "AT", + "BFI", + "BFIW", + "BFM", + "BFMW", + "BFXIL", + "BFXILW", + "BIC", + "BICS", + "BICSW", + "BICW", + "BRK", + "CBNZ", + "CBNZW", + "CBZ", + "CBZW", + "CCMN", + "CCMNW", + "CCMP", + "CCMPW", + "CINC", + "CINCW", + "CINV", + "CINVW", + "CLREX", + "CLS", + "CLSW", + "CLZ", + "CLZW", + "CMN", + "CMNW", + "CMP", + "CMPW", + "CNEG", + "CNEGW", + "CRC32B", + "CRC32CB", + "CRC32CH", + "CRC32CW", + "CRC32CX", + "CRC32H", + "CRC32W", + "CRC32X", + "CSEL", + "CSELW", + "CSET", + "CSETM", + "CSETMW", + "CSETW", + "CSINC", + "CSINCW", + "CSINV", + "CSINVW", + "CSNEG", + "CSNEGW", + "DC", + "DCPS1", + "DCPS2", + "DCPS3", + "DMB", + "DRPS", + "DSB", + "EON", + "EONW", + "EOR", + "EORW", + "ERET", + "EXTR", + "EXTRW", + "HINT", + "HLT", + "HVC", + "IC", + "ISB", + "LDADDAB", + "LDADDAD", + "LDADDAH", + "LDADDAW", + "LDADDALB", + "LDADDALD", + "LDADDALH", + "LDADDALW", + "LDADDB", + "LDADDD", + "LDADDH", + "LDADDW", + "LDADDLB", + "LDADDLD", + "LDADDLH", + "LDADDLW", + "LDANDAB", + "LDANDAD", + "LDANDAH", + "LDANDAW", + "LDANDALB", + "LDANDALD", + "LDANDALH", + "LDANDALW", + "LDANDB", + "LDANDD", + "LDANDH", + "LDANDW", + "LDANDLB", + "LDANDLD", + "LDANDLH", + "LDANDLW", + "LDAR", + "LDARB", + "LDARH", + "LDARW", + "LDAXP", + "LDAXPW", + "LDAXR", + "LDAXRB", + "LDAXRH", + "LDAXRW", + "LDEORAB", + "LDEORAD", + "LDEORAH", + "LDEORAW", + "LDEORALB", + "LDEORALD", + "LDEORALH", + "LDEORALW", + "LDEORB", + "LDEORD", + "LDEORH", + "LDEORW", + "LDEORLB", + "LDEORLD", + "LDEORLH", + "LDEORLW", + "LDORAB", + "LDORAD", + "LDORAH", + "LDORAW", + "LDORALB", + "LDORALD", + "LDORALH", + "LDORALW", + "LDORB", + "LDORD", + "LDORH", + "LDORW", + "LDORLB", + "LDORLD", + "LDORLH", + "LDORLW", + "LDP", + "LDPW", + "LDPSW", + "LDXR", + "LDXRB", + "LDXRH", + "LDXRW", + "LDXP", + "LDXPW", + "LSL", + "LSLW", + "LSR", + "LSRW", + "MADD", + "MADDW", + "MNEG", + "MNEGW", + "MOVK", + "MOVKW", + "MOVN", + "MOVNW", + "MOVZ", + "MOVZW", + "MRS", + "MSR", + "MSUB", + "MSUBW", + "MUL", + "MULW", + "MVN", + "MVNW", + "NEG", + "NEGS", + "NEGSW", + "NEGW", + "NGC", + "NGCS", + "NGCSW", + "NGCW", + "NOOP", + "ORN", + "ORNW", + "ORR", + "ORRW", + "PRFM", + "PRFUM", + "RBIT", + "RBITW", + "REM", + "REMW", + "REV", + "REV16", + "REV16W", + "REV32", + "REVW", + "ROR", + "RORW", + "SBC", + "SBCS", + "SBCSW", + "SBCW", + "SBFIZ", + "SBFIZW", + "SBFM", + "SBFMW", + "SBFX", + "SBFXW", + "SDIV", + "SDIVW", + "SEV", + "SEVL", + "SMADDL", + "SMC", + "SMNEGL", + "SMSUBL", + "SMULH", + "SMULL", + "STXR", + "STXRB", + "STXRH", + "STXP", + "STXPW", + "STXRW", + "STLP", + "STLPW", + "STLR", + "STLRB", + "STLRH", + "STLRW", + "STLXP", + "STLXPW", + "STLXR", + "STLXRB", + "STLXRH", + "STLXRW", + "STP", + "STPW", + "SUB", + "SUBS", + "SUBSW", + "SUBW", + "SVC", + "SXTB", + "SXTBW", + "SXTH", + "SXTHW", + "SXTW", + "SYS", + "SYSL", + "TBNZ", + "TBZ", + "TLBI", + "TST", + "TSTW", + "UBFIZ", + "UBFIZW", + "UBFM", + "UBFMW", + "UBFX", + "UBFXW", + "UDIV", + "UDIVW", + "UMADDL", + "UMNEGL", + "UMSUBL", + "UMULH", + "UMULL", + "UREM", + "UREMW", + "UXTB", + "UXTH", + "UXTW", + "UXTBW", + "UXTHW", + "WFE", + "WFI", + "YIELD", + "MOVB", + "MOVBU", + "MOVH", + "MOVHU", + "MOVW", + "MOVWU", + "MOVD", + "MOVNP", + "MOVNPW", + "MOVP", + "MOVPD", + "MOVPQ", + "MOVPS", + "MOVPSW", + "MOVPW", + "SWPAD", + "SWPAW", + "SWPAH", + "SWPAB", + "SWPALD", + "SWPALW", + "SWPALH", + "SWPALB", + "SWPD", + "SWPW", + "SWPH", + "SWPB", + "SWPLD", + "SWPLW", + "SWPLH", + "SWPLB", + "BEQ", + "BNE", + "BCS", + "BHS", + "BCC", + "BLO", + "BMI", + "BPL", + "BVS", + "BVC", + "BHI", + "BLS", + "BGE", + "BLT", + "BGT", + "BLE", + "FABSD", + "FABSS", + "FADDD", + "FADDS", + "FCCMPD", + "FCCMPED", + "FCCMPS", + "FCCMPES", + "FCMPD", + "FCMPED", + "FCMPES", + "FCMPS", + "FCVTSD", + "FCVTDS", + "FCVTZSD", + "FCVTZSDW", + "FCVTZSS", + "FCVTZSSW", + "FCVTZUD", + "FCVTZUDW", + "FCVTZUS", + "FCVTZUSW", + "FDIVD", + "FDIVS", + "FLDPD", + "FLDPS", + "FMOVD", + "FMOVS", + "FMOVQ", + "FMULD", + "FMULS", + "FNEGD", + "FNEGS", + "FSQRTD", + "FSQRTS", + "FSTPD", + "FSTPS", + "FSUBD", + "FSUBS", + "SCVTFD", + "SCVTFS", + "SCVTFWD", + "SCVTFWS", + "UCVTFD", + "UCVTFS", + "UCVTFWD", + "UCVTFWS", + "WORD", + "DWORD", + "FCSELS", + "FCSELD", + "FMAXS", + "FMINS", + "FMAXD", + "FMIND", + "FMAXNMS", + "FMAXNMD", + "FNMULS", + "FNMULD", + "FRINTNS", + "FRINTND", + "FRINTPS", + "FRINTPD", + "FRINTMS", + "FRINTMD", + "FRINTZS", + "FRINTZD", + "FRINTAS", + "FRINTAD", + "FRINTXS", + "FRINTXD", + "FRINTIS", + "FRINTID", + "FMADDS", + "FMADDD", + "FMSUBS", + "FMSUBD", + "FNMADDS", + "FNMADDD", + "FNMSUBS", + "FNMSUBD", + "FMINNMS", + "FMINNMD", + "FCVTDH", + "FCVTHS", + "FCVTHD", + "FCVTSH", + "AESD", + "AESE", + "AESIMC", + "AESMC", + "SHA1C", + "SHA1H", + "SHA1M", + "SHA1P", + "SHA1SU0", + "SHA1SU1", + "SHA256H", + "SHA256H2", + "SHA256SU0", + "SHA256SU1", + "SHA512H", + "SHA512H2", + "SHA512SU0", + "SHA512SU1", + "VADD", + "VADDP", + "VAND", + "VBIF", + "VCMEQ", + "VCNT", + "VEOR", + "VMOV", + "VLD1", + "VLD2", + "VLD3", + "VLD4", + "VLD1R", + "VLD2R", + "VLD3R", + "VLD4R", + "VORR", + "VREV16", + "VREV32", + "VREV64", + "VST1", + "VST2", + "VST3", + "VST4", + "VDUP", + "VADDV", + "VMOVI", + "VUADDLV", + "VSUB", + "VFMLA", + "VFMLS", + "VPMULL", + "VPMULL2", + "VEXT", + "VRBIT", + "VUSHR", + "VUSHLL", + "VUSHLL2", + "VUXTL", + "VUXTL2", + "VUZP1", + "VUZP2", + "VSHL", + "VSRI", + "VBSL", + "VBIT", + "VTBL", + "VZIP1", + "VZIP2", + "VCMTST", + "LAST", +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames7.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames7.go new file mode 100644 index 0000000..96c9f78 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/anames7.go @@ -0,0 +1,100 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arm64 + +// This order should be strictly consistent to that in a.out.go +var cnames7 = []string{ + "NONE", + "REG", + "RSP", + "FREG", + "VREG", + "PAIR", + "SHIFT", + "EXTREG", + "SPR", + "COND", + "ARNG", + "ELEM", + "LIST", + "ZCON", + "ABCON0", + "ADDCON0", + "ABCON", + "AMCON", + "ADDCON", + "MBCON", + "MOVCON", + "BITCON", + "ADDCON2", + "LCON", + "MOVCON2", + "MOVCON3", + "VCON", + "FCON", + "VCONADDR", + "AACON", + "AACON2", + "LACON", + "AECON", + "SBRA", + "LBRA", + "ZAUTO", + "NSAUTO_8", + "NSAUTO_4", + "NSAUTO", + "NPAUTO", + "NAUTO4K", + "PSAUTO_8", + "PSAUTO_4", + "PSAUTO", + "PPAUTO", + "UAUTO4K_8", + "UAUTO4K_4", + "UAUTO4K_2", + "UAUTO4K", + "UAUTO8K_8", + "UAUTO8K_4", + "UAUTO8K", + "UAUTO16K_8", + "UAUTO16K", + "UAUTO32K", + "LAUTO", + "SEXT1", + "SEXT2", + "SEXT4", + "SEXT8", + "SEXT16", + "LEXT", + "ZOREG", + "NSOREG_8", + "NSOREG_4", + "NSOREG", + "NPOREG", + "NOREG4K", + "PSOREG_8", + "PSOREG_4", + "PSOREG", + "PPOREG", + "UOREG4K_8", + "UOREG4K_4", + "UOREG4K_2", + "UOREG4K", + "UOREG8K_8", + "UOREG8K_4", + "UOREG8K", + "UOREG16K_8", + "UOREG16K", + "UOREG32K", + "LOREG", + "ADDR", + "GOTADDR", + "TLS_LE", + "TLS_IE", + "ROFF", + "GOK", + "TEXTSIZE", + "NCLASS", +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go new file mode 100644 index 0000000..2bbb64b --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go @@ -0,0 +1,7140 @@ +// cmd/7l/asm.c, cmd/7l/asmout.c, cmd/7l/optab.c, cmd/7l/span.c, cmd/ld/sub.c, cmd/ld/mod.c, from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/ +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import ( + "github.com/twitchyliquid64/golang-asm/obj" + "github.com/twitchyliquid64/golang-asm/objabi" + "fmt" + "log" + "math" + "sort" +) + +// ctxt7 holds state while assembling a single function. +// Each function gets a fresh ctxt7. +// This allows for multiple functions to be safely concurrently assembled. +type ctxt7 struct { + ctxt *obj.Link + newprog obj.ProgAlloc + cursym *obj.LSym + blitrl *obj.Prog + elitrl *obj.Prog + autosize int32 + extrasize int32 + instoffset int64 + pc int64 + pool struct { + start uint32 + size uint32 + } +} + +const ( + funcAlign = 16 +) + +const ( + REGFROM = 1 +) + +type Optab struct { + as obj.As + a1 uint8 + a2 uint8 + a3 uint8 + a4 uint8 + type_ int8 + size int8 + param int16 + flag int8 + scond uint16 +} + +func IsAtomicInstruction(as obj.As) bool { + _, ok := atomicInstructions[as] + return ok +} + +// known field values of an instruction. +var atomicInstructions = map[obj.As]uint32{ + ALDADDAD: 3<<30 | 0x1c5<<21 | 0x00<<10, + ALDADDAW: 2<<30 | 0x1c5<<21 | 0x00<<10, + ALDADDAH: 1<<30 | 0x1c5<<21 | 0x00<<10, + ALDADDAB: 0<<30 | 0x1c5<<21 | 0x00<<10, + ALDADDALD: 3<<30 | 0x1c7<<21 | 0x00<<10, + ALDADDALW: 2<<30 | 0x1c7<<21 | 0x00<<10, + ALDADDALH: 1<<30 | 0x1c7<<21 | 0x00<<10, + ALDADDALB: 0<<30 | 0x1c7<<21 | 0x00<<10, + ALDADDD: 3<<30 | 0x1c1<<21 | 0x00<<10, + ALDADDW: 2<<30 | 0x1c1<<21 | 0x00<<10, + ALDADDH: 1<<30 | 0x1c1<<21 | 0x00<<10, + ALDADDB: 0<<30 | 0x1c1<<21 | 0x00<<10, + ALDADDLD: 3<<30 | 0x1c3<<21 | 0x00<<10, + ALDADDLW: 2<<30 | 0x1c3<<21 | 0x00<<10, + ALDADDLH: 1<<30 | 0x1c3<<21 | 0x00<<10, + ALDADDLB: 0<<30 | 0x1c3<<21 | 0x00<<10, + ALDANDAD: 3<<30 | 0x1c5<<21 | 0x04<<10, + ALDANDAW: 2<<30 | 0x1c5<<21 | 0x04<<10, + ALDANDAH: 1<<30 | 0x1c5<<21 | 0x04<<10, + ALDANDAB: 0<<30 | 0x1c5<<21 | 0x04<<10, + ALDANDALD: 3<<30 | 0x1c7<<21 | 0x04<<10, + ALDANDALW: 2<<30 | 0x1c7<<21 | 0x04<<10, + ALDANDALH: 1<<30 | 0x1c7<<21 | 0x04<<10, + ALDANDALB: 0<<30 | 0x1c7<<21 | 0x04<<10, + ALDANDD: 3<<30 | 0x1c1<<21 | 0x04<<10, + ALDANDW: 2<<30 | 0x1c1<<21 | 0x04<<10, + ALDANDH: 1<<30 | 0x1c1<<21 | 0x04<<10, + ALDANDB: 0<<30 | 0x1c1<<21 | 0x04<<10, + ALDANDLD: 3<<30 | 0x1c3<<21 | 0x04<<10, + ALDANDLW: 2<<30 | 0x1c3<<21 | 0x04<<10, + ALDANDLH: 1<<30 | 0x1c3<<21 | 0x04<<10, + ALDANDLB: 0<<30 | 0x1c3<<21 | 0x04<<10, + ALDEORAD: 3<<30 | 0x1c5<<21 | 0x08<<10, + ALDEORAW: 2<<30 | 0x1c5<<21 | 0x08<<10, + ALDEORAH: 1<<30 | 0x1c5<<21 | 0x08<<10, + ALDEORAB: 0<<30 | 0x1c5<<21 | 0x08<<10, + ALDEORALD: 3<<30 | 0x1c7<<21 | 0x08<<10, + ALDEORALW: 2<<30 | 0x1c7<<21 | 0x08<<10, + ALDEORALH: 1<<30 | 0x1c7<<21 | 0x08<<10, + ALDEORALB: 0<<30 | 0x1c7<<21 | 0x08<<10, + ALDEORD: 3<<30 | 0x1c1<<21 | 0x08<<10, + ALDEORW: 2<<30 | 0x1c1<<21 | 0x08<<10, + ALDEORH: 1<<30 | 0x1c1<<21 | 0x08<<10, + ALDEORB: 0<<30 | 0x1c1<<21 | 0x08<<10, + ALDEORLD: 3<<30 | 0x1c3<<21 | 0x08<<10, + ALDEORLW: 2<<30 | 0x1c3<<21 | 0x08<<10, + ALDEORLH: 1<<30 | 0x1c3<<21 | 0x08<<10, + ALDEORLB: 0<<30 | 0x1c3<<21 | 0x08<<10, + ALDORAD: 3<<30 | 0x1c5<<21 | 0x0c<<10, + ALDORAW: 2<<30 | 0x1c5<<21 | 0x0c<<10, + ALDORAH: 1<<30 | 0x1c5<<21 | 0x0c<<10, + ALDORAB: 0<<30 | 0x1c5<<21 | 0x0c<<10, + ALDORALD: 3<<30 | 0x1c7<<21 | 0x0c<<10, + ALDORALW: 2<<30 | 0x1c7<<21 | 0x0c<<10, + ALDORALH: 1<<30 | 0x1c7<<21 | 0x0c<<10, + ALDORALB: 0<<30 | 0x1c7<<21 | 0x0c<<10, + ALDORD: 3<<30 | 0x1c1<<21 | 0x0c<<10, + ALDORW: 2<<30 | 0x1c1<<21 | 0x0c<<10, + ALDORH: 1<<30 | 0x1c1<<21 | 0x0c<<10, + ALDORB: 0<<30 | 0x1c1<<21 | 0x0c<<10, + ALDORLD: 3<<30 | 0x1c3<<21 | 0x0c<<10, + ALDORLW: 2<<30 | 0x1c3<<21 | 0x0c<<10, + ALDORLH: 1<<30 | 0x1c3<<21 | 0x0c<<10, + ALDORLB: 0<<30 | 0x1c3<<21 | 0x0c<<10, + ASWPAD: 3<<30 | 0x1c5<<21 | 0x20<<10, + ASWPAW: 2<<30 | 0x1c5<<21 | 0x20<<10, + ASWPAH: 1<<30 | 0x1c5<<21 | 0x20<<10, + ASWPAB: 0<<30 | 0x1c5<<21 | 0x20<<10, + ASWPALD: 3<<30 | 0x1c7<<21 | 0x20<<10, + ASWPALW: 2<<30 | 0x1c7<<21 | 0x20<<10, + ASWPALH: 1<<30 | 0x1c7<<21 | 0x20<<10, + ASWPALB: 0<<30 | 0x1c7<<21 | 0x20<<10, + ASWPD: 3<<30 | 0x1c1<<21 | 0x20<<10, + ASWPW: 2<<30 | 0x1c1<<21 | 0x20<<10, + ASWPH: 1<<30 | 0x1c1<<21 | 0x20<<10, + ASWPB: 0<<30 | 0x1c1<<21 | 0x20<<10, + ASWPLD: 3<<30 | 0x1c3<<21 | 0x20<<10, + ASWPLW: 2<<30 | 0x1c3<<21 | 0x20<<10, + ASWPLH: 1<<30 | 0x1c3<<21 | 0x20<<10, + ASWPLB: 0<<30 | 0x1c3<<21 | 0x20<<10, +} + +var oprange [ALAST & obj.AMask][]Optab + +var xcmp [C_NCLASS][C_NCLASS]bool + +const ( + S32 = 0 << 31 + S64 = 1 << 31 + Sbit = 1 << 29 + LSL0_32 = 2 << 13 + LSL0_64 = 3 << 13 +) + +func OPDP2(x uint32) uint32 { + return 0<<30 | 0<<29 | 0xd6<<21 | x<<10 +} + +func OPDP3(sf uint32, op54 uint32, op31 uint32, o0 uint32) uint32 { + return sf<<31 | op54<<29 | 0x1B<<24 | op31<<21 | o0<<15 +} + +func OPBcc(x uint32) uint32 { + return 0x2A<<25 | 0<<24 | 0<<4 | x&15 +} + +func OPBLR(x uint32) uint32 { + /* x=0, JMP; 1, CALL; 2, RET */ + return 0x6B<<25 | 0<<23 | x<<21 | 0x1F<<16 | 0<<10 +} + +func SYSOP(l uint32, op0 uint32, op1 uint32, crn uint32, crm uint32, op2 uint32, rt uint32) uint32 { + return 0x354<<22 | l<<21 | op0<<19 | op1<<16 | crn&15<<12 | crm&15<<8 | op2<<5 | rt +} + +func SYSHINT(x uint32) uint32 { + return SYSOP(0, 0, 3, 2, 0, x, 0x1F) +} + +func LDSTR12U(sz uint32, v uint32, opc uint32) uint32 { + return sz<<30 | 7<<27 | v<<26 | 1<<24 | opc<<22 +} + +func LDSTR9S(sz uint32, v uint32, opc uint32) uint32 { + return sz<<30 | 7<<27 | v<<26 | 0<<24 | opc<<22 +} + +func LD2STR(o uint32) uint32 { + return o &^ (3 << 22) +} + +func LDSTX(sz uint32, o2 uint32, l uint32, o1 uint32, o0 uint32) uint32 { + return sz<<30 | 0x8<<24 | o2<<23 | l<<22 | o1<<21 | o0<<15 +} + +func FPCMP(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<14 | 8<<10 | op2 +} + +func FPCCMP(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | 1<<10 | op<<4 +} + +func FPOP1S(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<15 | 0x10<<10 +} + +func FPOP2S(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<12 | 2<<10 +} + +func FPOP3S(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 { + return m<<31 | s<<29 | 0x1F<<24 | type_<<22 | op<<21 | op2<<15 +} + +func FPCVTI(sf uint32, s uint32, type_ uint32, rmode uint32, op uint32) uint32 { + return sf<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | rmode<<19 | op<<16 | 0<<10 +} + +func ADR(p uint32, o uint32, rt uint32) uint32 { + return p<<31 | (o&3)<<29 | 0x10<<24 | ((o>>2)&0x7FFFF)<<5 | rt&31 +} + +func OPBIT(x uint32) uint32 { + return 1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | x<<10 +} + +func MOVCONST(d int64, s int, rt int) uint32 { + return uint32(((d>>uint(s*16))&0xFFFF)<<5) | uint32(s)&3<<21 | uint32(rt&31) +} + +const ( + // Optab.flag + LFROM = 1 << 0 // p.From uses constant pool + LTO = 1 << 1 // p.To uses constant pool + NOTUSETMP = 1 << 2 // p expands to multiple instructions, but does NOT use REGTMP +) + +var optab = []Optab{ + /* struct Optab: + OPCODE, from, prog->reg, from3, to, type,size,param,flag,scond */ + {obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0}, + + /* arithmetic operations */ + {AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AADC, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AADC, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ANEG, C_REG, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0}, + {ANEG, C_NONE, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0}, + {ANGC, C_REG, C_NONE, C_NONE, C_REG, 17, 4, 0, 0, 0}, + {ACMP, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0}, + {AADD, C_ADDCON, C_RSP, C_NONE, C_RSP, 2, 4, 0, 0, 0}, + {AADD, C_ADDCON, C_NONE, C_NONE, C_RSP, 2, 4, 0, 0, 0}, + {ACMP, C_ADDCON, C_RSP, C_NONE, C_NONE, 2, 4, 0, 0, 0}, + {AADD, C_MOVCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {AADD, C_MOVCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {ACMP, C_MOVCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0}, + {AADD, C_BITCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {AADD, C_BITCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0}, + {AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0}, + {AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0}, + {AADD, C_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0}, + {AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0}, + {AADD, C_MOVCON3, C_RSP, C_NONE, C_RSP, 13, 16, 0, 0, 0}, + {AADD, C_MOVCON3, C_NONE, C_NONE, C_RSP, 13, 16, 0, 0, 0}, + {AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 20, 0, 0, 0}, + {AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 20, 0, 0, 0}, + {ACMP, C_MOVCON2, C_REG, C_NONE, C_NONE, 13, 12, 0, 0, 0}, + {ACMP, C_MOVCON3, C_REG, C_NONE, C_NONE, 13, 16, 0, 0, 0}, + {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0}, + {AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {ACMP, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0}, + {ANEG, C_SHIFT, C_NONE, C_NONE, C_REG, 26, 4, 0, 0, 0}, + {AADD, C_REG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {ACMP, C_REG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0}, + {AADD, C_EXTREG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {AADD, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {AMVN, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {ACMP, C_EXTREG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0}, + {AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AMUL, C_REG, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0}, + {AMUL, C_REG, C_NONE, C_NONE, C_REG, 15, 4, 0, 0, 0}, + {AMADD, C_REG, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0}, + {AREM, C_REG, C_REG, C_NONE, C_REG, 16, 8, 0, 0, 0}, + {AREM, C_REG, C_NONE, C_NONE, C_REG, 16, 8, 0, 0, 0}, + {ASDIV, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ASDIV, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + + {AFADDS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFADDS, C_FREG, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMSUBD, C_FREG, C_FREG, C_FREG, C_FREG, 15, 4, 0, 0, 0}, + {AFCMPS, C_FREG, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0}, + {AFCMPS, C_FCON, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0}, + {AVADDP, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0}, + {AVADD, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0}, + {AVADD, C_VREG, C_VREG, C_NONE, C_VREG, 89, 4, 0, 0, 0}, + {AVADD, C_VREG, C_NONE, C_NONE, C_VREG, 89, 4, 0, 0, 0}, + {AVADDV, C_ARNG, C_NONE, C_NONE, C_VREG, 85, 4, 0, 0, 0}, + + /* logical operations */ + {AAND, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AAND, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AANDS, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AANDS, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ATST, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0}, + {AAND, C_MBCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0}, + {AAND, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {AANDS, C_MBCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {AANDS, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {ATST, C_MBCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0}, + {AAND, C_BITCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0}, + {AAND, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0}, + {AAND, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, + {AAND, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, + {AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, + {AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, + {ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0}, + {AAND, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0}, + {AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0}, + {AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0}, + {AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0}, + {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0}, + {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0}, + {AANDS, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0}, + {AANDS, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0}, + {AANDS, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0}, + {AANDS, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0}, + {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0}, + {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0}, + {ATST, C_MOVCON2, C_REG, C_NONE, C_NONE, 28, 12, 0, 0, 0}, + {ATST, C_MOVCON3, C_REG, C_NONE, C_NONE, 28, 16, 0, 0, 0}, + {ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 20, 0, 0, 0}, + {AAND, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AAND, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AANDS, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AANDS, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {ATST, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0}, + {AMOVD, C_RSP, C_NONE, C_NONE, C_RSP, 24, 4, 0, 0, 0}, + {AMVN, C_REG, C_NONE, C_NONE, C_REG, 24, 4, 0, 0, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVHU */ + {AMOVW, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVWU */ + /* TODO: MVN C_SHIFT */ + + /* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */ + {AMOVW, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0}, + {AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0}, + {AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, NOTUSETMP, 0}, + {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, NOTUSETMP, 0}, + + {AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0}, + {AMOVD, C_AACON, C_NONE, C_NONE, C_RSP, 4, 4, REGFROM, 0, 0}, + {AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, 0, 0}, + + /* load long effective stack address (load int32 offset and add) */ + {AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0}, + + // Move a large constant to a Vn. + {AFMOVQ, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0}, + {AFMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0}, + {AFMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0}, + + /* jump operations */ + {AB, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {AB, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0}, + {ABL, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {obj.ARET, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0}, + {obj.ARET, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0}, + {ACBZ, C_REG, C_NONE, C_NONE, C_SBRA, 39, 4, 0, 0, 0}, + {ATBZ, C_VCON, C_REG, C_NONE, C_SBRA, 40, 4, 0, 0, 0}, + {AERET, C_NONE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0}, + + // get a PC-relative address + {AADRP, C_SBRA, C_NONE, C_NONE, C_REG, 60, 4, 0, 0, 0}, + {AADR, C_SBRA, C_NONE, C_NONE, C_REG, 61, 4, 0, 0, 0}, + + {ACLREX, C_NONE, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0}, + {ACLREX, C_NONE, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0}, + {ABFM, C_VCON, C_REG, C_VCON, C_REG, 42, 4, 0, 0, 0}, + {ABFI, C_VCON, C_REG, C_VCON, C_REG, 43, 4, 0, 0, 0}, + {AEXTR, C_VCON, C_REG, C_REG, C_REG, 44, 4, 0, 0, 0}, + {ASXTB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {ACLS, C_REG, C_NONE, C_NONE, C_REG, 46, 4, 0, 0, 0}, + {ALSL, C_VCON, C_REG, C_NONE, C_REG, 8, 4, 0, 0, 0}, + {ALSL, C_VCON, C_NONE, C_NONE, C_REG, 8, 4, 0, 0, 0}, + {ALSL, C_REG, C_NONE, C_NONE, C_REG, 9, 4, 0, 0, 0}, + {ALSL, C_REG, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, + {ASVC, C_VCON, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0}, + {ASVC, C_NONE, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0}, + {ADWORD, C_NONE, C_NONE, C_NONE, C_VCON, 11, 8, 0, NOTUSETMP, 0}, + {ADWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 11, 8, 0, NOTUSETMP, 0}, + {ADWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 11, 8, 0, NOTUSETMP, 0}, + {ADWORD, C_NONE, C_NONE, C_NONE, C_LACON, 11, 8, 0, NOTUSETMP, 0}, + {AWORD, C_NONE, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0}, + {AMOVW, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0}, + {AMOVD, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0}, + {AMOVBU, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0}, + {AMOVH, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0}, + {AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0}, + {AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0}, + {AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 71, 8, 0, 0, 0}, + {AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 69, 4, 0, 0, 0}, + {AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 70, 8, 0, 0, 0}, + + {AFMOVS, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AFMOVS, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, + {AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0}, + {AFMOVS, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVD, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVS, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0}, + {AFMOVD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0}, + {AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0}, + {ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0}, + {AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0}, + {AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0}, + {AVMOV, C_REG, C_NONE, C_NONE, C_ARNG, 82, 4, 0, 0, 0}, + {AVMOV, C_REG, C_NONE, C_NONE, C_ELEM, 78, 4, 0, 0, 0}, + {AVMOV, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0}, + {AVDUP, C_ELEM, C_NONE, C_NONE, C_ARNG, 79, 4, 0, 0, 0}, + {AVMOVI, C_ADDCON, C_NONE, C_NONE, C_ARNG, 86, 4, 0, 0, 0}, + {AVFMLA, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0}, + {AVEXT, C_VCON, C_ARNG, C_ARNG, C_ARNG, 94, 4, 0, 0, 0}, + {AVTBL, C_ARNG, C_NONE, C_LIST, C_ARNG, 100, 4, 0, 0, 0}, + {AVUSHR, C_VCON, C_ARNG, C_NONE, C_ARNG, 95, 4, 0, 0, 0}, + {AVZIP1, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0}, + {AVUSHLL, C_VCON, C_ARNG, C_NONE, C_ARNG, 102, 4, 0, 0, 0}, + {AVUXTL, C_ARNG, C_NONE, C_NONE, C_ARNG, 102, 4, 0, 0, 0}, + + /* conditional operations */ + {ACSEL, C_COND, C_REG, C_REG, C_REG, 18, 4, 0, 0, 0}, + {ACINC, C_COND, C_REG, C_NONE, C_REG, 18, 4, 0, 0, 0}, + {ACSET, C_COND, C_NONE, C_NONE, C_REG, 18, 4, 0, 0, 0}, + {AFCSELD, C_COND, C_FREG, C_FREG, C_FREG, 18, 4, 0, 0, 0}, + {ACCMN, C_COND, C_REG, C_REG, C_VCON, 19, 4, 0, 0, 0}, + {ACCMN, C_COND, C_REG, C_VCON, C_VCON, 19, 4, 0, 0, 0}, + {AFCCMPS, C_COND, C_FREG, C_FREG, C_VCON, 57, 4, 0, 0, 0}, + + /* scaled 12-bit unsigned displacement store */ + {AMOVB, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_UAUTO8K, 20, 4, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_UOREG8K, 20, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0}, + + {AFMOVS, C_FREG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0}, + + /* unscaled 9-bit signed displacement store */ + {AMOVB, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + + {AFMOVS, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + + /* scaled 12-bit unsigned displacement load */ + {AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVBU, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVH, C_UAUTO8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVW, C_UAUTO16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVD, C_UAUTO32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + + {AFMOVS, C_UAUTO16K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVD, C_UAUTO32K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVD, C_UOREG32K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + + /* unscaled 9-bit signed displacement load */ + {AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVBU, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVH, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVW, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVD, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0}, + + {AFMOVS, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVD, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVD, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + + /* long displacement store */ + {AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + + {AFMOVS, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + + /* long displacement load */ + {AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVBU, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVH, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + + {AFMOVS, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0}, + {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0}, + {AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0}, + {AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0}, + + /* pre/post-indexed load (unscaled, signed 9-bit offset) */ + {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST}, + {AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST}, + + {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE}, + {AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE}, + + /* pre/post-indexed store (unscaled, signed 9-bit offset) */ + {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + + {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + + /* load with shifted or extended register offset */ + {AMOVD, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AMOVW, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AMOVH, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AMOVB, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AMOVBU, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AFMOVS, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0}, + {AFMOVD, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0}, + + /* store with extended register offset */ + {AMOVD, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AMOVB, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + + /* pre/post-indexed/signed-offset load/store register pair + (unscaled, signed 10-bit quad-aligned and long offset) */ + {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, + {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, + {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, + {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, + {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0}, + {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE}, + {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST}, + {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, + {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, + {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, + {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, + {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0}, + {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE}, + {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST}, + {ALDP, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0}, + + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0}, + + // differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4 + {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, + {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, + {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, + {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, + {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0}, + {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE}, + {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST}, + {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, + {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, + {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, + {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, + {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0}, + {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE}, + {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST}, + {ALDPW, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0}, + + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST}, + {ASTPW, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0}, + + {ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG + {ASWPD, C_REG, C_NONE, C_NONE, C_ZAUTO, 47, 4, REGSP, 0, 0}, // RegTo2=C_REG + {ALDAR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDAXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDXP, C_ZOREG, C_NONE, C_NONE, C_PAIR, 58, 4, 0, 0, 0}, + {ASTLR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_NONE + {ASTXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG + {ASTLXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG + {ASTXP, C_PAIR, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, + + /* VLD[1-4]/VST[1-4] */ + {AVLD1, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0}, + {AVLD1, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST}, + {AVLD1, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST}, + {AVLD1R, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0}, + {AVLD1R, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST}, + {AVLD1R, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST}, + {AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST}, + {AVLD1, C_ROFF, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST}, + {AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, 0}, + {AVST1, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0}, + {AVST1, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST}, + {AVST1, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST}, + {AVST2, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0}, + {AVST2, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST}, + {AVST2, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST}, + {AVST3, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0}, + {AVST3, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST}, + {AVST3, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST}, + {AVST4, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0}, + {AVST4, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST}, + {AVST4, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST}, + {AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, C_XPOST}, + {AVST1, C_ELEM, C_NONE, C_NONE, C_ROFF, 96, 4, 0, 0, C_XPOST}, + {AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, 0}, + + /* special */ + {AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0}, + {AMRS, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0}, + {AMSR, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0}, + {AMOVD, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0}, + {AMSR, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0}, + {APRFM, C_UOREG32K, C_NONE, C_NONE, C_SPR, 91, 4, 0, 0, 0}, + {APRFM, C_UOREG32K, C_NONE, C_NONE, C_LCON, 91, 4, 0, 0, 0}, + {ADMB, C_VCON, C_NONE, C_NONE, C_NONE, 51, 4, 0, 0, 0}, + {AHINT, C_VCON, C_NONE, C_NONE, C_NONE, 52, 4, 0, 0, 0}, + {ASYS, C_VCON, C_NONE, C_NONE, C_NONE, 50, 4, 0, 0, 0}, + {ASYS, C_VCON, C_REG, C_NONE, C_NONE, 50, 4, 0, 0, 0}, + {ASYSL, C_VCON, C_NONE, C_NONE, C_REG, 50, 4, 0, 0, 0}, + + /* encryption instructions */ + {AAESD, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0}, // for compatibility with old code + {AAESD, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0}, // recommend using the new one for better readability + {ASHA1C, C_VREG, C_REG, C_NONE, C_VREG, 1, 4, 0, 0, 0}, + {ASHA1C, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0}, + {ASHA1H, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0}, + {ASHA1SU0, C_ARNG, C_ARNG, C_NONE, C_ARNG, 1, 4, 0, 0, 0}, + {ASHA256H, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0}, + {AVREV32, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0}, + {AVPMULL, C_ARNG, C_ARNG, C_NONE, C_ARNG, 93, 4, 0, 0, 0}, + + {obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0}, + {obj.APCDATA, C_VCON, C_NONE, C_NONE, C_VCON, 0, 0, 0, 0, 0}, + {obj.AFUNCDATA, C_VCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0, 0, 0}, + {obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.ANOP, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // nop variants, see #40689 + {obj.ANOP, C_REG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.ANOP, C_VREG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL + {obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL + {obj.APCALIGN, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // align code + + {obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0}, +} + +/* + * valid pstate field values, and value to use in instruction + */ +var pstatefield = []struct { + reg int16 + enc uint32 +}{ + {REG_SPSel, 0<<16 | 4<<12 | 5<<5}, + {REG_DAIFSet, 3<<16 | 4<<12 | 6<<5}, + {REG_DAIFClr, 3<<16 | 4<<12 | 7<<5}, +} + +var prfopfield = []struct { + reg int16 + enc uint32 +}{ + {REG_PLDL1KEEP, 0}, + {REG_PLDL1STRM, 1}, + {REG_PLDL2KEEP, 2}, + {REG_PLDL2STRM, 3}, + {REG_PLDL3KEEP, 4}, + {REG_PLDL3STRM, 5}, + {REG_PLIL1KEEP, 8}, + {REG_PLIL1STRM, 9}, + {REG_PLIL2KEEP, 10}, + {REG_PLIL2STRM, 11}, + {REG_PLIL3KEEP, 12}, + {REG_PLIL3STRM, 13}, + {REG_PSTL1KEEP, 16}, + {REG_PSTL1STRM, 17}, + {REG_PSTL2KEEP, 18}, + {REG_PSTL2STRM, 19}, + {REG_PSTL3KEEP, 20}, + {REG_PSTL3STRM, 21}, +} + +// Used for padinng NOOP instruction +const OP_NOOP = 0xd503201f + +// align code to a certain length by padding bytes. +func pcAlignPadLength(pc int64, alignedValue int64, ctxt *obj.Link) int { + if !((alignedValue&(alignedValue-1) == 0) && 8 <= alignedValue && alignedValue <= 2048) { + ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", alignedValue) + } + return int(-pc & (alignedValue - 1)) +} + +func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { + if ctxt.Retpoline { + ctxt.Diag("-spectre=ret not supported on arm64") + ctxt.Retpoline = false // don't keep printing + } + + p := cursym.Func.Text + if p == nil || p.Link == nil { // handle external functions and ELF section symbols + return + } + + if oprange[AAND&obj.AMask] == nil { + ctxt.Diag("arm64 ops not initialized, call arm64.buildop first") + } + + c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset & 0xffffffff), extrasize: int32(p.To.Offset >> 32)} + p.To.Offset &= 0xffffffff // extrasize is no longer needed + + bflag := 1 + pc := int64(0) + p.Pc = pc + var m int + var o *Optab + for p = p.Link; p != nil; p = p.Link { + if p.As == ADWORD && (pc&7) != 0 { + pc += 4 + } + p.Pc = pc + o = c.oplook(p) + m = int(o.size) + if m == 0 { + switch p.As { + case obj.APCALIGN: + alignedValue := p.From.Offset + m = pcAlignPadLength(pc, alignedValue, ctxt) + // Update the current text symbol alignment value. + if int32(alignedValue) > cursym.Func.Align { + cursym.Func.Align = int32(alignedValue) + } + break + case obj.ANOP, obj.AFUNCDATA, obj.APCDATA: + continue + default: + c.ctxt.Diag("zero-width instruction\n%v", p) + } + } + switch o.flag & (LFROM | LTO) { + case LFROM: + c.addpool(p, &p.From) + + case LTO: + c.addpool(p, &p.To) + break + } + + if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */ + c.checkpool(p, 0) + } + pc += int64(m) + if c.blitrl != nil { + c.checkpool(p, 1) + } + } + + c.cursym.Size = pc + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + for bflag != 0 { + bflag = 0 + pc = 0 + for p = c.cursym.Func.Text.Link; p != nil; p = p.Link { + if p.As == ADWORD && (pc&7) != 0 { + pc += 4 + } + p.Pc = pc + o = c.oplook(p) + + /* very large branches */ + if (o.type_ == 7 || o.type_ == 39 || o.type_ == 40) && p.To.Target() != nil { // 7: BEQ and like, 39: CBZ and like, 40: TBZ and like + otxt := p.To.Target().Pc - pc + var toofar bool + switch o.type_ { + case 7, 39: // branch instruction encodes 19 bits + toofar = otxt <= -(1<<20)+10 || otxt >= (1<<20)-10 + case 40: // branch instruction encodes 14 bits + toofar = otxt <= -(1<<15)+10 || otxt >= (1<<15)-10 + } + if toofar { + q := c.newprog() + q.Link = p.Link + p.Link = q + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.To.SetTarget(p.To.Target()) + p.To.SetTarget(q) + q = c.newprog() + q.Link = p.Link + p.Link = q + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.To.SetTarget(q.Link.Link) + bflag = 1 + } + } + m = int(o.size) + + if m == 0 { + switch p.As { + case obj.APCALIGN: + alignedValue := p.From.Offset + m = pcAlignPadLength(pc, alignedValue, ctxt) + break + case obj.ANOP, obj.AFUNCDATA, obj.APCDATA: + continue + default: + c.ctxt.Diag("zero-width instruction\n%v", p) + } + } + + pc += int64(m) + } + } + + pc += -pc & (funcAlign - 1) + c.cursym.Size = pc + + /* + * lay out the code, emitting code and data relocations. + */ + c.cursym.Grow(c.cursym.Size) + bp := c.cursym.P + psz := int32(0) + var i int + var out [6]uint32 + for p := c.cursym.Func.Text.Link; p != nil; p = p.Link { + c.pc = p.Pc + o = c.oplook(p) + + // need to align DWORDs on 8-byte boundary. The ISA doesn't + // require it, but the various 64-bit loads we generate assume it. + if o.as == ADWORD && psz%8 != 0 { + bp[3] = 0 + bp[2] = bp[3] + bp[1] = bp[2] + bp[0] = bp[1] + bp = bp[4:] + psz += 4 + } + + if int(o.size) > 4*len(out) { + log.Fatalf("out array in span7 is too small, need at least %d for %v", o.size/4, p) + } + if p.As == obj.APCALIGN { + alignedValue := p.From.Offset + v := pcAlignPadLength(p.Pc, alignedValue, c.ctxt) + for i = 0; i < int(v/4); i++ { + // emit ANOOP instruction by the padding size + c.ctxt.Arch.ByteOrder.PutUint32(bp, OP_NOOP) + bp = bp[4:] + psz += 4 + } + } else { + c.asmout(p, o, out[:]) + for i = 0; i < int(o.size/4); i++ { + c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i]) + bp = bp[4:] + psz += 4 + } + } + } + + // Mark nonpreemptible instruction sequences. + // We use REGTMP as a scratch register during call injection, + // so instruction sequences that use REGTMP are unsafe to + // preempt asynchronously. + obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable) +} + +// isUnsafePoint returns whether p is an unsafe point. +func (c *ctxt7) isUnsafePoint(p *obj.Prog) bool { + // If p explicitly uses REGTMP, it's unsafe to preempt, because the + // preemption sequence clobbers REGTMP. + return p.From.Reg == REGTMP || p.To.Reg == REGTMP || p.Reg == REGTMP +} + +// isRestartable returns whether p is a multi-instruction sequence that, +// if preempted, can be restarted. +func (c *ctxt7) isRestartable(p *obj.Prog) bool { + if c.isUnsafePoint(p) { + return false + } + // If p is a multi-instruction sequence with uses REGTMP inserted by + // the assembler in order to materialize a large constant/offset, we + // can restart p (at the start of the instruction sequence), recompute + // the content of REGTMP, upon async preemption. Currently, all cases + // of assembler-inserted REGTMP fall into this category. + // If p doesn't use REGTMP, it can be simply preempted, so we don't + // mark it. + o := c.oplook(p) + return o.size > 4 && o.flag&NOTUSETMP == 0 +} + +/* + * when the first reference to the literal pool threatens + * to go out of range of a 1Mb PC-relative offset + * drop the pool now, and branch round it. + */ +func (c *ctxt7) checkpool(p *obj.Prog, skip int) { + if c.pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(c.pool.size)-int64(c.pool.start)+8)) { + c.flushpool(p, skip) + } else if p.Link == nil { + c.flushpool(p, 2) + } +} + +func (c *ctxt7) flushpool(p *obj.Prog, skip int) { + if c.blitrl != nil { + if skip != 0 { + if c.ctxt.Debugvlog && skip == 1 { + fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start) + } + q := c.newprog() + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.To.SetTarget(p.Link) + q.Link = c.blitrl + q.Pos = p.Pos + c.blitrl = q + } else if p.Pc+int64(c.pool.size)-int64(c.pool.start) < maxPCDisp { + return + } + + // The line number for constant pool entries doesn't really matter. + // We set it to the line number of the preceding instruction so that + // there are no deltas to encode in the pc-line tables. + for q := c.blitrl; q != nil; q = q.Link { + q.Pos = p.Pos + } + + c.elitrl.Link = p.Link + p.Link = c.blitrl + + c.blitrl = nil /* BUG: should refer back to values until out-of-range */ + c.elitrl = nil + c.pool.size = 0 + c.pool.start = 0 + } +} + +/* + * MOVD foo(SB), R is actually + * MOVD addr, REGTMP + * MOVD REGTMP, R + * where addr is the address of the DWORD containing the address of foo. + * + * TODO: hash + */ +func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) { + cls := c.aclass(a) + lit := c.instoffset + t := c.newprog() + t.As = AWORD + sz := 4 + + if a.Type == obj.TYPE_CONST { + if lit != int64(int32(lit)) && uint64(lit) != uint64(uint32(lit)) { + // out of range -0x80000000 ~ 0xffffffff, must store 64-bit + t.As = ADWORD + sz = 8 + } // else store 32-bit + } else if p.As == AMOVD && a.Type != obj.TYPE_MEM || cls == C_ADDR || cls == C_VCON || lit != int64(int32(lit)) || uint64(lit) != uint64(uint32(lit)) { + // conservative: don't know if we want signed or unsigned extension. + // in case of ambiguity, store 64-bit + t.As = ADWORD + sz = 8 + } + + switch cls { + // TODO(aram): remove. + default: + if a.Name != obj.NAME_EXTERN { + fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(cls), p) + } + + t.To.Offset = a.Offset + t.To.Sym = a.Sym + t.To.Type = a.Type + t.To.Name = a.Name + + /* This is here because MOV uint12<<12, R is disabled in optab. + Because of this, we need to load the constant from memory. */ + case C_ADDCON: + fallthrough + + case C_ZAUTO, + C_PSAUTO, + C_PSAUTO_8, + C_PSAUTO_4, + C_PPAUTO, + C_UAUTO4K_8, + C_UAUTO4K_4, + C_UAUTO4K_2, + C_UAUTO4K, + C_UAUTO8K_8, + C_UAUTO8K_4, + C_UAUTO8K, + C_UAUTO16K_8, + C_UAUTO16K, + C_UAUTO32K, + C_NSAUTO_8, + C_NSAUTO_4, + C_NSAUTO, + C_NPAUTO, + C_NAUTO4K, + C_LAUTO, + C_PPOREG, + C_PSOREG, + C_PSOREG_4, + C_PSOREG_8, + C_UOREG4K_8, + C_UOREG4K_4, + C_UOREG4K_2, + C_UOREG4K, + C_UOREG8K_8, + C_UOREG8K_4, + C_UOREG8K, + C_UOREG16K_8, + C_UOREG16K, + C_UOREG32K, + C_NSOREG_8, + C_NSOREG_4, + C_NSOREG, + C_NPOREG, + C_NOREG4K, + C_LOREG, + C_LACON, + C_ADDCON2, + C_LCON, + C_VCON: + if a.Name == obj.NAME_EXTERN { + fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p) + } + + t.To.Type = obj.TYPE_CONST + t.To.Offset = lit + break + } + + for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ + if q.To == t.To { + p.Pool = q + return + } + } + + q := c.newprog() + *q = *t + q.Pc = int64(c.pool.size) + if c.blitrl == nil { + c.blitrl = q + c.pool.start = uint32(p.Pc) + } else { + c.elitrl.Link = q + } + c.elitrl = q + c.pool.size = -c.pool.size & (funcAlign - 1) + c.pool.size += uint32(sz) + p.Pool = q +} + +func (c *ctxt7) regoff(a *obj.Addr) uint32 { + c.instoffset = 0 + c.aclass(a) + return uint32(c.instoffset) +} + +func isSTLXRop(op obj.As) bool { + switch op { + case ASTLXR, ASTLXRW, ASTLXRB, ASTLXRH, + ASTXR, ASTXRW, ASTXRB, ASTXRH: + return true + } + return false +} + +func isSTXPop(op obj.As) bool { + switch op { + case ASTXP, ASTLXP, ASTXPW, ASTLXPW: + return true + } + return false +} + +func isANDop(op obj.As) bool { + switch op { + case AAND, AORR, AEOR, AANDS, ATST, + ABIC, AEON, AORN, ABICS: + return true + } + return false +} + +func isANDWop(op obj.As) bool { + switch op { + case AANDW, AORRW, AEORW, AANDSW, ATSTW, + ABICW, AEONW, AORNW, ABICSW: + return true + } + return false +} + +func isADDop(op obj.As) bool { + switch op { + case AADD, AADDS, ASUB, ASUBS, ACMN, ACMP: + return true + } + return false +} + +func isADDWop(op obj.As) bool { + switch op { + case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW: + return true + } + return false +} + +func isRegShiftOrExt(a *obj.Addr) bool { + return (a.Index-obj.RBaseARM64)®_EXT != 0 || (a.Index-obj.RBaseARM64)®_LSL != 0 +} + +// Maximum PC-relative displacement. +// The actual limit is ±2²⁰, but we are conservative +// to avoid needing to recompute the literal pool flush points +// as span-dependent jumps are enlarged. +const maxPCDisp = 512 * 1024 + +// ispcdisp reports whether v is a valid PC-relative displacement. +func ispcdisp(v int32) bool { + return -maxPCDisp < v && v < maxPCDisp && v&3 == 0 +} + +func isaddcon(v int64) bool { + /* uimm12 or uimm24? */ + if v < 0 { + return false + } + if (v & 0xFFF) == 0 { + v >>= 12 + } + return v <= 0xFFF +} + +func isaddcon2(v int64) bool { + return 0 <= v && v <= 0xFFFFFF +} + +// isbitcon reports whether a constant can be encoded into a logical instruction. +// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64, +// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones. +// special cases: 0 and -1 are not bitcon. +// this function needs to run against virtually all the constants, so it needs to be fast. +// for this reason, bitcon testing and bitcon encoding are separate functions. +func isbitcon(x uint64) bool { + if x == 1<<64-1 || x == 0 { + return false + } + // determine the period and sign-extend a unit to 64 bits + switch { + case x != x>>32|x<<32: + // period is 64 + // nothing to do + case x != x>>16|x<<48: + // period is 32 + x = uint64(int64(int32(x))) + case x != x>>8|x<<56: + // period is 16 + x = uint64(int64(int16(x))) + case x != x>>4|x<<60: + // period is 8 + x = uint64(int64(int8(x))) + default: + // period is 4 or 2, always true + // 0001, 0010, 0100, 1000 -- 0001 rotate + // 0011, 0110, 1100, 1001 -- 0011 rotate + // 0111, 1011, 1101, 1110 -- 0111 rotate + // 0101, 1010 -- 01 rotate, repeat + return true + } + return sequenceOfOnes(x) || sequenceOfOnes(^x) +} + +// sequenceOfOnes tests whether a constant is a sequence of ones in binary, with leading and trailing zeros +func sequenceOfOnes(x uint64) bool { + y := x & -x // lowest set bit of x. x is good iff x+y is a power of 2 + y += x + return (y-1)&y == 0 +} + +// bitconEncode returns the encoding of a bitcon used in logical instructions +// x is known to be a bitcon +// a bitcon is a sequence of n ones at low bits (i.e. 1<>32|x<<32: + period = 64 + case x != x>>16|x<<48: + period = 32 + x = uint64(int64(int32(x))) + case x != x>>8|x<<56: + period = 16 + x = uint64(int64(int16(x))) + case x != x>>4|x<<60: + period = 8 + x = uint64(int64(int8(x))) + case x != x>>2|x<<62: + period = 4 + x = uint64(int64(x<<60) >> 60) + default: + period = 2 + x = uint64(int64(x<<62) >> 62) + } + neg := false + if int64(x) < 0 { + x = ^x + neg = true + } + y := x & -x // lowest set bit of x. + s := log2(y) + n := log2(x+y) - s // x (or ^x) is a sequence of n ones left shifted by s bits + if neg { + // ^x is a sequence of n ones left shifted by s bits + // adjust n, s for x + s = n + s + n = period - n + } + + N := uint32(0) + if mode == 64 && period == 64 { + N = 1 + } + R := (period - s) & (period - 1) & uint32(mode-1) // shift amount of right rotate + S := (n - 1) | 63&^(period<<1-1) // low bits = #ones - 1, high bits encodes period + return N<<22 | R<<16 | S<<10 +} + +func log2(x uint64) uint32 { + if x == 0 { + panic("log2 of 0") + } + n := uint32(0) + if x >= 1<<32 { + x >>= 32 + n += 32 + } + if x >= 1<<16 { + x >>= 16 + n += 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + if x >= 1<<4 { + x >>= 4 + n += 4 + } + if x >= 1<<2 { + x >>= 2 + n += 2 + } + if x >= 1<<1 { + x >>= 1 + n += 1 + } + return n +} + +func autoclass(l int64) int { + if l == 0 { + return C_ZAUTO + } + + if l < 0 { + if l >= -256 && (l&7) == 0 { + return C_NSAUTO_8 + } + if l >= -256 && (l&3) == 0 { + return C_NSAUTO_4 + } + if l >= -256 { + return C_NSAUTO + } + if l >= -512 && (l&7) == 0 { + return C_NPAUTO + } + if l >= -4095 { + return C_NAUTO4K + } + return C_LAUTO + } + + if l <= 255 { + if (l & 7) == 0 { + return C_PSAUTO_8 + } + if (l & 3) == 0 { + return C_PSAUTO_4 + } + return C_PSAUTO + } + if l <= 504 && l&7 == 0 { + return C_PPAUTO + } + if l <= 4095 { + if l&7 == 0 { + return C_UAUTO4K_8 + } + if l&3 == 0 { + return C_UAUTO4K_4 + } + if l&1 == 0 { + return C_UAUTO4K_2 + } + return C_UAUTO4K + } + if l <= 8190 { + if l&7 == 0 { + return C_UAUTO8K_8 + } + if l&3 == 0 { + return C_UAUTO8K_4 + } + if l&1 == 0 { + return C_UAUTO8K + } + } + if l <= 16380 { + if l&7 == 0 { + return C_UAUTO16K_8 + } + if l&3 == 0 { + return C_UAUTO16K + } + } + if l <= 32760 && (l&7) == 0 { + return C_UAUTO32K + } + return C_LAUTO +} + +func oregclass(l int64) int { + return autoclass(l) - C_ZAUTO + C_ZOREG +} + +/* + * given an offset v and a class c (see above) + * return the offset value to use in the instruction, + * scaled if necessary + */ +func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 { + s := 0 + if cls >= C_SEXT1 && cls <= C_SEXT16 { + s = cls - C_SEXT1 + } else { + switch cls { + case C_UAUTO4K, C_UOREG4K, C_ZOREG: + s = 0 + case C_UAUTO8K, C_UOREG8K: + s = 1 + case C_UAUTO16K, C_UOREG16K: + s = 2 + case C_UAUTO32K, C_UOREG32K: + s = 3 + default: + c.ctxt.Diag("bad class: %v\n%v", DRconv(cls), p) + } + } + vs := v >> uint(s) + if vs<= REG_ARNG && r < REG_ELEM: + return C_ARNG + case r >= REG_ELEM && r < REG_ELEM_END: + return C_ELEM + case r >= REG_UXTB && r < REG_SPECIAL: + return C_EXTREG + case r >= REG_SPECIAL: + return C_SPR + } + return C_GOK +} + +// con32class reclassifies the constant of 32-bit instruction. Because the constant type is 32-bit, +// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it. +func (c *ctxt7) con32class(a *obj.Addr) int { + v := uint32(a.Offset) + if v == 0 { + return C_ZCON + } + if isaddcon(int64(v)) { + if v <= 0xFFF { + if isbitcon(uint64(a.Offset)) { + return C_ABCON0 + } + return C_ADDCON0 + } + if isbitcon(uint64(a.Offset)) { + return C_ABCON + } + if movcon(int64(v)) >= 0 { + return C_AMCON + } + if movcon(int64(^v)) >= 0 { + return C_AMCON + } + return C_ADDCON + } + + t := movcon(int64(v)) + if t >= 0 { + if isbitcon(uint64(a.Offset)) { + return C_MBCON + } + return C_MOVCON + } + + t = movcon(int64(^v)) + if t >= 0 { + if isbitcon(uint64(a.Offset)) { + return C_MBCON + } + return C_MOVCON + } + + if isbitcon(uint64(a.Offset)) { + return C_BITCON + } + + if 0 <= v && v <= 0xffffff { + return C_ADDCON2 + } + return C_LCON +} + +// con64class reclassifies the constant of C_VCON and C_LCON class. +func (c *ctxt7) con64class(a *obj.Addr) int { + zeroCount := 0 + negCount := 0 + for i := uint(0); i < 4; i++ { + immh := uint32(a.Offset >> (i * 16) & 0xffff) + if immh == 0 { + zeroCount++ + } else if immh == 0xffff { + negCount++ + } + } + if zeroCount >= 3 || negCount >= 3 { + return C_MOVCON + } else if zeroCount == 2 || negCount == 2 { + return C_MOVCON2 + } else if zeroCount == 1 || negCount == 1 { + return C_MOVCON3 + } else { + return C_VCON + } +} + +func (c *ctxt7) aclass(a *obj.Addr) int { + switch a.Type { + case obj.TYPE_NONE: + return C_NONE + + case obj.TYPE_REG: + return rclass(a.Reg) + + case obj.TYPE_REGREG: + return C_PAIR + + case obj.TYPE_SHIFT: + return C_SHIFT + + case obj.TYPE_REGLIST: + return C_LIST + + case obj.TYPE_MEM: + // The base register should be an integer register. + if int16(REG_F0) <= a.Reg && a.Reg <= int16(REG_V31) { + break + } + switch a.Name { + case obj.NAME_EXTERN, obj.NAME_STATIC: + if a.Sym == nil { + break + } + c.instoffset = a.Offset + if a.Sym != nil { // use relocation + if a.Sym.Type == objabi.STLSBSS { + if c.ctxt.Flag_shared { + return C_TLS_IE + } else { + return C_TLS_LE + } + } + return C_ADDR + } + return C_LEXT + + case obj.NAME_GOTREF: + return C_GOTADDR + + case obj.NAME_AUTO: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-SP. + a.Reg = obj.REG_NONE + } + // The frame top 8 or 16 bytes are for FP + c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize) + return autoclass(c.instoffset) + + case obj.NAME_PARAM: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-FP. + a.Reg = obj.REG_NONE + } + c.instoffset = int64(c.autosize) + a.Offset + 8 + return autoclass(c.instoffset) + + case obj.NAME_NONE: + if a.Index != 0 { + if a.Offset != 0 { + if isRegShiftOrExt(a) { + // extended or shifted register offset, (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2). + return C_ROFF + } + return C_GOK + } + // register offset, (Rn)(Rm) + return C_ROFF + } + c.instoffset = a.Offset + return oregclass(c.instoffset) + } + return C_GOK + + case obj.TYPE_FCONST: + return C_FCON + + case obj.TYPE_TEXTSIZE: + return C_TEXTSIZE + + case obj.TYPE_CONST, obj.TYPE_ADDR: + switch a.Name { + case obj.NAME_NONE: + c.instoffset = a.Offset + if a.Reg != 0 && a.Reg != REGZERO { + break + } + v := c.instoffset + if v == 0 { + return C_ZCON + } + if isaddcon(v) { + if v <= 0xFFF { + if isbitcon(uint64(v)) { + return C_ABCON0 + } + return C_ADDCON0 + } + if isbitcon(uint64(v)) { + return C_ABCON + } + if movcon(v) >= 0 { + return C_AMCON + } + if movcon(^v) >= 0 { + return C_AMCON + } + return C_ADDCON + } + + t := movcon(v) + if t >= 0 { + if isbitcon(uint64(v)) { + return C_MBCON + } + return C_MOVCON + } + + t = movcon(^v) + if t >= 0 { + if isbitcon(uint64(v)) { + return C_MBCON + } + return C_MOVCON + } + + if isbitcon(uint64(v)) { + return C_BITCON + } + + if 0 <= v && v <= 0xffffff { + return C_ADDCON2 + } + + if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) { + return C_LCON + } + return C_VCON + + case obj.NAME_EXTERN, obj.NAME_STATIC: + if a.Sym == nil { + return C_GOK + } + if a.Sym.Type == objabi.STLSBSS { + c.ctxt.Diag("taking address of TLS variable is not supported") + } + c.instoffset = a.Offset + return C_VCONADDR + + case obj.NAME_AUTO: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-SP. + a.Reg = obj.REG_NONE + } + // The frame top 8 or 16 bytes are for FP + c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize) + + case obj.NAME_PARAM: + if a.Reg == REGSP { + // unset base register for better printing, since + // a.Offset is still relative to pseudo-FP. + a.Reg = obj.REG_NONE + } + c.instoffset = int64(c.autosize) + a.Offset + 8 + default: + return C_GOK + } + cf := c.instoffset + if isaddcon(cf) || isaddcon(-cf) { + return C_AACON + } + if isaddcon2(cf) { + return C_AACON2 + } + + return C_LACON + + case obj.TYPE_BRANCH: + return C_SBRA + } + + return C_GOK +} + +func oclass(a *obj.Addr) int { + return int(a.Class) - 1 +} + +func (c *ctxt7) oplook(p *obj.Prog) *Optab { + a1 := int(p.Optab) + if a1 != 0 { + return &optab[a1-1] + } + a1 = int(p.From.Class) + if a1 == 0 { + a0 := c.aclass(&p.From) + // do not break C_ADDCON2 when S bit is set + if (p.As == AADDS || p.As == AADDSW || p.As == ASUBS || p.As == ASUBSW) && a0 == C_ADDCON2 { + a0 = C_LCON + } + a1 = a0 + 1 + p.From.Class = int8(a1) + // more specific classification of 32-bit integers + if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE { + if p.As == AMOVW || isADDWop(p.As) { + ra0 := c.con32class(&p.From) + // do not break C_ADDCON2 when S bit is set + if (p.As == AADDSW || p.As == ASUBSW) && ra0 == C_ADDCON2 { + ra0 = C_LCON + } + a1 = ra0 + 1 + p.From.Class = int8(a1) + } + if isANDWop(p.As) && a0 != C_BITCON { + // For 32-bit logical instruction with constant, + // the BITCON test is special in that it looks at + // the 64-bit which has the high 32-bit as a copy + // of the low 32-bit. We have handled that and + // don't pass it to con32class. + a1 = c.con32class(&p.From) + 1 + p.From.Class = int8(a1) + } + if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) { + a1 = c.con64class(&p.From) + 1 + p.From.Class = int8(a1) + } + } + } + + a1-- + a3 := C_NONE + 1 + if p.GetFrom3() != nil { + a3 = int(p.GetFrom3().Class) + if a3 == 0 { + a3 = c.aclass(p.GetFrom3()) + 1 + p.GetFrom3().Class = int8(a3) + } + } + + a3-- + a4 := int(p.To.Class) + if a4 == 0 { + a4 = c.aclass(&p.To) + 1 + p.To.Class = int8(a4) + } + + a4-- + a2 := C_NONE + if p.Reg != 0 { + a2 = rclass(p.Reg) + } + + if false { + fmt.Printf("oplook %v %d %d %d %d\n", p.As, a1, a2, a3, a4) + fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) + } + + ops := oprange[p.As&obj.AMask] + c1 := &xcmp[a1] + c2 := &xcmp[a2] + c3 := &xcmp[a3] + c4 := &xcmp[a4] + c5 := &xcmp[p.Scond>>5] + for i := range ops { + op := &ops[i] + if (int(op.a2) == a2 || c2[op.a2]) && c5[op.scond>>5] && c1[op.a1] && c3[op.a3] && c4[op.a4] { + p.Optab = uint16(cap(optab) - cap(ops) + i + 1) + return op + } + } + + c.ctxt.Diag("illegal combination: %v %v %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4), p.From.Type, p.To.Type) + // Turn illegal instruction into an UNDEF, avoid crashing in asmout + return &Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0} +} + +func cmp(a int, b int) bool { + if a == b { + return true + } + switch a { + case C_RSP: + if b == C_REG { + return true + } + + case C_REG: + if b == C_ZCON { + return true + } + + case C_ADDCON0: + if b == C_ZCON || b == C_ABCON0 { + return true + } + + case C_ADDCON: + if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON || b == C_AMCON { + return true + } + + case C_BITCON: + if b == C_ABCON0 || b == C_ABCON || b == C_MBCON { + return true + } + + case C_MOVCON: + if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_AMCON { + return true + } + + case C_ADDCON2: + if b == C_ZCON || b == C_ADDCON || b == C_ADDCON0 { + return true + } + + case C_LCON: + if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON || b == C_ADDCON2 || b == C_AMCON { + return true + } + + case C_MOVCON2: + return cmp(C_LCON, b) + + case C_VCON: + return cmp(C_LCON, b) + + case C_LACON: + if b == C_AACON || b == C_AACON2 { + return true + } + + case C_SEXT2: + if b == C_SEXT1 { + return true + } + + case C_SEXT4: + if b == C_SEXT1 || b == C_SEXT2 { + return true + } + + case C_SEXT8: + if b >= C_SEXT1 && b <= C_SEXT4 { + return true + } + + case C_SEXT16: + if b >= C_SEXT1 && b <= C_SEXT8 { + return true + } + + case C_LEXT: + if b >= C_SEXT1 && b <= C_SEXT16 { + return true + } + + case C_NSAUTO_4: + if b == C_NSAUTO_8 { + return true + } + + case C_NSAUTO: + switch b { + case C_NSAUTO_4, C_NSAUTO_8: + return true + } + + case C_NPAUTO: + switch b { + case C_NSAUTO_8: + return true + } + + case C_NAUTO4K: + switch b { + case C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO: + return true + } + + case C_PSAUTO_8: + if b == C_ZAUTO { + return true + } + + case C_PSAUTO_4: + switch b { + case C_ZAUTO, C_PSAUTO_8: + return true + } + + case C_PSAUTO: + switch b { + case C_ZAUTO, C_PSAUTO_8, C_PSAUTO_4: + return true + } + + case C_PPAUTO: + switch b { + case C_ZAUTO, C_PSAUTO_8: + return true + } + + case C_UAUTO4K: + switch b { + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, + C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8: + return true + } + + case C_UAUTO8K: + switch b { + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, + C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8: + return true + } + + case C_UAUTO16K: + switch b { + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, + C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8: + return true + } + + case C_UAUTO32K: + switch b { + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, + C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8: + return true + } + + case C_LAUTO: + switch b { + case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO, + C_NAUTO4K, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, + C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, + C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8, + C_UAUTO16K, C_UAUTO16K_8, + C_UAUTO32K: + return true + } + + case C_NSOREG_4: + if b == C_NSOREG_8 { + return true + } + + case C_NSOREG: + switch b { + case C_NSOREG_4, C_NSOREG_8: + return true + } + + case C_NPOREG: + switch b { + case C_NSOREG_8: + return true + } + + case C_NOREG4K: + switch b { + case C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG: + return true + } + + case C_PSOREG_4: + switch b { + case C_ZOREG, C_PSOREG_8: + return true + } + + case C_PSOREG: + switch b { + case C_ZOREG, C_PSOREG_8, C_PSOREG_4: + return true + } + + case C_PPOREG: + switch b { + case C_ZOREG, C_PSOREG_8: + return true + } + + case C_UOREG4K: + switch b { + case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, + C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8: + return true + } + + case C_UOREG8K: + switch b { + case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, + C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, + C_UOREG8K_4, C_UOREG8K_8: + return true + } + + case C_UOREG16K: + switch b { + case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, + C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4, + C_UOREG8K_8, C_UOREG16K_8: + return true + } + + case C_UOREG32K: + switch b { + case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, + C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8: + return true + } + + case C_LOREG: + switch b { + case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG, + C_NOREG4K, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG, + C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, + C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8, + C_UOREG16K, C_UOREG16K_8, + C_UOREG32K: + return true + } + + case C_LBRA: + if b == C_SBRA { + return true + } + } + + return false +} + +type ocmp []Optab + +func (x ocmp) Len() int { + return len(x) +} + +func (x ocmp) Swap(i, j int) { + x[i], x[j] = x[j], x[i] +} + +func (x ocmp) Less(i, j int) bool { + p1 := &x[i] + p2 := &x[j] + if p1.as != p2.as { + return p1.as < p2.as + } + if p1.a1 != p2.a1 { + return p1.a1 < p2.a1 + } + if p1.a2 != p2.a2 { + return p1.a2 < p2.a2 + } + if p1.a3 != p2.a3 { + return p1.a3 < p2.a3 + } + if p1.a4 != p2.a4 { + return p1.a4 < p2.a4 + } + if p1.scond != p2.scond { + return p1.scond < p2.scond + } + return false +} + +func oprangeset(a obj.As, t []Optab) { + oprange[a&obj.AMask] = t +} + +func buildop(ctxt *obj.Link) { + if oprange[AAND&obj.AMask] != nil { + // Already initialized; stop now. + // This happens in the cmd/asm tests, + // each of which re-initializes the arch. + return + } + + var n int + for i := 0; i < C_GOK; i++ { + for n = 0; n < C_GOK; n++ { + if cmp(n, i) { + xcmp[i][n] = true + } + } + } + for n = 0; optab[n].as != obj.AXXX; n++ { + } + sort.Sort(ocmp(optab[:n])) + for i := 0; i < n; i++ { + r := optab[i].as + start := i + for optab[i].as == r { + i++ + } + t := optab[start:i] + i-- + oprangeset(r, t) + switch r { + default: + ctxt.Diag("unknown op in build: %v", r) + ctxt.DiagFlush() + log.Fatalf("bad code") + + case AADD: + oprangeset(AADDS, t) + oprangeset(ASUB, t) + oprangeset(ASUBS, t) + oprangeset(AADDW, t) + oprangeset(AADDSW, t) + oprangeset(ASUBW, t) + oprangeset(ASUBSW, t) + + case AAND: /* logical immediate, logical shifted register */ + oprangeset(AANDW, t) + oprangeset(AEOR, t) + oprangeset(AEORW, t) + oprangeset(AORR, t) + oprangeset(AORRW, t) + oprangeset(ABIC, t) + oprangeset(ABICW, t) + oprangeset(AEON, t) + oprangeset(AEONW, t) + oprangeset(AORN, t) + oprangeset(AORNW, t) + + case AANDS: /* logical immediate, logical shifted register, set flags, cannot target RSP */ + oprangeset(AANDSW, t) + oprangeset(ABICS, t) + oprangeset(ABICSW, t) + + case ANEG: + oprangeset(ANEGS, t) + oprangeset(ANEGSW, t) + oprangeset(ANEGW, t) + + case AADC: /* rn=Rd */ + oprangeset(AADCW, t) + + oprangeset(AADCS, t) + oprangeset(AADCSW, t) + oprangeset(ASBC, t) + oprangeset(ASBCW, t) + oprangeset(ASBCS, t) + oprangeset(ASBCSW, t) + + case ANGC: /* rn=REGZERO */ + oprangeset(ANGCW, t) + + oprangeset(ANGCS, t) + oprangeset(ANGCSW, t) + + case ACMP: + oprangeset(ACMPW, t) + oprangeset(ACMN, t) + oprangeset(ACMNW, t) + + case ATST: + oprangeset(ATSTW, t) + + /* register/register, and shifted */ + case AMVN: + oprangeset(AMVNW, t) + + case AMOVK: + oprangeset(AMOVKW, t) + oprangeset(AMOVN, t) + oprangeset(AMOVNW, t) + oprangeset(AMOVZ, t) + oprangeset(AMOVZW, t) + + case ASWPD: + for i := range atomicInstructions { + oprangeset(i, t) + } + + case ABEQ: + oprangeset(ABNE, t) + oprangeset(ABCS, t) + oprangeset(ABHS, t) + oprangeset(ABCC, t) + oprangeset(ABLO, t) + oprangeset(ABMI, t) + oprangeset(ABPL, t) + oprangeset(ABVS, t) + oprangeset(ABVC, t) + oprangeset(ABHI, t) + oprangeset(ABLS, t) + oprangeset(ABGE, t) + oprangeset(ABLT, t) + oprangeset(ABGT, t) + oprangeset(ABLE, t) + + case ALSL: + oprangeset(ALSLW, t) + oprangeset(ALSR, t) + oprangeset(ALSRW, t) + oprangeset(AASR, t) + oprangeset(AASRW, t) + oprangeset(AROR, t) + oprangeset(ARORW, t) + + case ACLS: + oprangeset(ACLSW, t) + oprangeset(ACLZ, t) + oprangeset(ACLZW, t) + oprangeset(ARBIT, t) + oprangeset(ARBITW, t) + oprangeset(AREV, t) + oprangeset(AREVW, t) + oprangeset(AREV16, t) + oprangeset(AREV16W, t) + oprangeset(AREV32, t) + + case ASDIV: + oprangeset(ASDIVW, t) + oprangeset(AUDIV, t) + oprangeset(AUDIVW, t) + oprangeset(ACRC32B, t) + oprangeset(ACRC32CB, t) + oprangeset(ACRC32CH, t) + oprangeset(ACRC32CW, t) + oprangeset(ACRC32CX, t) + oprangeset(ACRC32H, t) + oprangeset(ACRC32W, t) + oprangeset(ACRC32X, t) + + case AMADD: + oprangeset(AMADDW, t) + oprangeset(AMSUB, t) + oprangeset(AMSUBW, t) + oprangeset(ASMADDL, t) + oprangeset(ASMSUBL, t) + oprangeset(AUMADDL, t) + oprangeset(AUMSUBL, t) + + case AREM: + oprangeset(AREMW, t) + oprangeset(AUREM, t) + oprangeset(AUREMW, t) + + case AMUL: + oprangeset(AMULW, t) + oprangeset(AMNEG, t) + oprangeset(AMNEGW, t) + oprangeset(ASMNEGL, t) + oprangeset(ASMULL, t) + oprangeset(ASMULH, t) + oprangeset(AUMNEGL, t) + oprangeset(AUMULH, t) + oprangeset(AUMULL, t) + + case AMOVB: + oprangeset(AMOVBU, t) + + case AMOVH: + oprangeset(AMOVHU, t) + + case AMOVW: + oprangeset(AMOVWU, t) + + case ABFM: + oprangeset(ABFMW, t) + oprangeset(ASBFM, t) + oprangeset(ASBFMW, t) + oprangeset(AUBFM, t) + oprangeset(AUBFMW, t) + + case ABFI: + oprangeset(ABFIW, t) + oprangeset(ABFXIL, t) + oprangeset(ABFXILW, t) + oprangeset(ASBFIZ, t) + oprangeset(ASBFIZW, t) + oprangeset(ASBFX, t) + oprangeset(ASBFXW, t) + oprangeset(AUBFIZ, t) + oprangeset(AUBFIZW, t) + oprangeset(AUBFX, t) + oprangeset(AUBFXW, t) + + case AEXTR: + oprangeset(AEXTRW, t) + + case ASXTB: + oprangeset(ASXTBW, t) + oprangeset(ASXTH, t) + oprangeset(ASXTHW, t) + oprangeset(ASXTW, t) + oprangeset(AUXTB, t) + oprangeset(AUXTH, t) + oprangeset(AUXTW, t) + oprangeset(AUXTBW, t) + oprangeset(AUXTHW, t) + + case ACCMN: + oprangeset(ACCMNW, t) + oprangeset(ACCMP, t) + oprangeset(ACCMPW, t) + + case ACSEL: + oprangeset(ACSELW, t) + oprangeset(ACSINC, t) + oprangeset(ACSINCW, t) + oprangeset(ACSINV, t) + oprangeset(ACSINVW, t) + oprangeset(ACSNEG, t) + oprangeset(ACSNEGW, t) + + case ACINC: + // aliases Rm=Rn, !cond + oprangeset(ACINCW, t) + oprangeset(ACINV, t) + oprangeset(ACINVW, t) + oprangeset(ACNEG, t) + oprangeset(ACNEGW, t) + + // aliases, Rm=Rn=REGZERO, !cond + case ACSET: + oprangeset(ACSETW, t) + + oprangeset(ACSETM, t) + oprangeset(ACSETMW, t) + + case AMOVD, + AMOVBU, + AB, + ABL, + AWORD, + ADWORD, + obj.ARET, + obj.ATEXT: + break + + case ALDP: + oprangeset(AFLDPD, t) + + case ASTP: + oprangeset(AFSTPD, t) + + case ASTPW: + oprangeset(AFSTPS, t) + + case ALDPW: + oprangeset(ALDPSW, t) + oprangeset(AFLDPS, t) + + case AERET: + oprangeset(AWFE, t) + oprangeset(AWFI, t) + oprangeset(AYIELD, t) + oprangeset(ASEV, t) + oprangeset(ASEVL, t) + oprangeset(ANOOP, t) + oprangeset(ADRPS, t) + + case ACBZ: + oprangeset(ACBZW, t) + oprangeset(ACBNZ, t) + oprangeset(ACBNZW, t) + + case ATBZ: + oprangeset(ATBNZ, t) + + case AADR, AADRP: + break + + case ACLREX: + break + + case ASVC: + oprangeset(AHVC, t) + oprangeset(AHLT, t) + oprangeset(ASMC, t) + oprangeset(ABRK, t) + oprangeset(ADCPS1, t) + oprangeset(ADCPS2, t) + oprangeset(ADCPS3, t) + + case AFADDS: + oprangeset(AFADDD, t) + oprangeset(AFSUBS, t) + oprangeset(AFSUBD, t) + oprangeset(AFMULS, t) + oprangeset(AFMULD, t) + oprangeset(AFNMULS, t) + oprangeset(AFNMULD, t) + oprangeset(AFDIVS, t) + oprangeset(AFMAXD, t) + oprangeset(AFMAXS, t) + oprangeset(AFMIND, t) + oprangeset(AFMINS, t) + oprangeset(AFMAXNMD, t) + oprangeset(AFMAXNMS, t) + oprangeset(AFMINNMD, t) + oprangeset(AFMINNMS, t) + oprangeset(AFDIVD, t) + + case AFMSUBD: + oprangeset(AFMSUBS, t) + oprangeset(AFMADDS, t) + oprangeset(AFMADDD, t) + oprangeset(AFNMSUBS, t) + oprangeset(AFNMSUBD, t) + oprangeset(AFNMADDS, t) + oprangeset(AFNMADDD, t) + + case AFCVTSD: + oprangeset(AFCVTDS, t) + oprangeset(AFABSD, t) + oprangeset(AFABSS, t) + oprangeset(AFNEGD, t) + oprangeset(AFNEGS, t) + oprangeset(AFSQRTD, t) + oprangeset(AFSQRTS, t) + oprangeset(AFRINTNS, t) + oprangeset(AFRINTND, t) + oprangeset(AFRINTPS, t) + oprangeset(AFRINTPD, t) + oprangeset(AFRINTMS, t) + oprangeset(AFRINTMD, t) + oprangeset(AFRINTZS, t) + oprangeset(AFRINTZD, t) + oprangeset(AFRINTAS, t) + oprangeset(AFRINTAD, t) + oprangeset(AFRINTXS, t) + oprangeset(AFRINTXD, t) + oprangeset(AFRINTIS, t) + oprangeset(AFRINTID, t) + oprangeset(AFCVTDH, t) + oprangeset(AFCVTHS, t) + oprangeset(AFCVTHD, t) + oprangeset(AFCVTSH, t) + + case AFCMPS: + oprangeset(AFCMPD, t) + oprangeset(AFCMPES, t) + oprangeset(AFCMPED, t) + + case AFCCMPS: + oprangeset(AFCCMPD, t) + oprangeset(AFCCMPES, t) + oprangeset(AFCCMPED, t) + + case AFCSELD: + oprangeset(AFCSELS, t) + + case AFMOVS, AFMOVD, AFMOVQ: + break + + case AFCVTZSD: + oprangeset(AFCVTZSDW, t) + oprangeset(AFCVTZSS, t) + oprangeset(AFCVTZSSW, t) + oprangeset(AFCVTZUD, t) + oprangeset(AFCVTZUDW, t) + oprangeset(AFCVTZUS, t) + oprangeset(AFCVTZUSW, t) + + case ASCVTFD: + oprangeset(ASCVTFS, t) + oprangeset(ASCVTFWD, t) + oprangeset(ASCVTFWS, t) + oprangeset(AUCVTFD, t) + oprangeset(AUCVTFS, t) + oprangeset(AUCVTFWD, t) + oprangeset(AUCVTFWS, t) + + case ASYS: + oprangeset(AAT, t) + oprangeset(ADC, t) + oprangeset(AIC, t) + oprangeset(ATLBI, t) + + case ASYSL, AHINT: + break + + case ADMB: + oprangeset(ADSB, t) + oprangeset(AISB, t) + + case AMRS, AMSR: + break + + case ALDAR: + oprangeset(ALDARW, t) + oprangeset(ALDARB, t) + oprangeset(ALDARH, t) + fallthrough + + case ALDXR: + oprangeset(ALDXRB, t) + oprangeset(ALDXRH, t) + oprangeset(ALDXRW, t) + + case ALDAXR: + oprangeset(ALDAXRB, t) + oprangeset(ALDAXRH, t) + oprangeset(ALDAXRW, t) + + case ALDXP: + oprangeset(ALDXPW, t) + oprangeset(ALDAXP, t) + oprangeset(ALDAXPW, t) + + case ASTLR: + oprangeset(ASTLRB, t) + oprangeset(ASTLRH, t) + oprangeset(ASTLRW, t) + + case ASTXR: + oprangeset(ASTXRB, t) + oprangeset(ASTXRH, t) + oprangeset(ASTXRW, t) + + case ASTLXR: + oprangeset(ASTLXRB, t) + oprangeset(ASTLXRH, t) + oprangeset(ASTLXRW, t) + + case ASTXP: + oprangeset(ASTLXP, t) + oprangeset(ASTLXPW, t) + oprangeset(ASTXPW, t) + + case AVADDP: + oprangeset(AVAND, t) + oprangeset(AVCMEQ, t) + oprangeset(AVORR, t) + oprangeset(AVEOR, t) + oprangeset(AVBSL, t) + oprangeset(AVBIT, t) + oprangeset(AVCMTST, t) + oprangeset(AVUZP1, t) + oprangeset(AVUZP2, t) + oprangeset(AVBIF, t) + + case AVADD: + oprangeset(AVSUB, t) + + case AAESD: + oprangeset(AAESE, t) + oprangeset(AAESMC, t) + oprangeset(AAESIMC, t) + oprangeset(ASHA1SU1, t) + oprangeset(ASHA256SU0, t) + oprangeset(ASHA512SU0, t) + + case ASHA1C: + oprangeset(ASHA1P, t) + oprangeset(ASHA1M, t) + + case ASHA256H: + oprangeset(ASHA256H2, t) + oprangeset(ASHA512H, t) + oprangeset(ASHA512H2, t) + + case ASHA1SU0: + oprangeset(ASHA256SU1, t) + oprangeset(ASHA512SU1, t) + + case AVADDV: + oprangeset(AVUADDLV, t) + + case AVFMLA: + oprangeset(AVFMLS, t) + + case AVPMULL: + oprangeset(AVPMULL2, t) + + case AVUSHR: + oprangeset(AVSHL, t) + oprangeset(AVSRI, t) + + case AVREV32: + oprangeset(AVCNT, t) + oprangeset(AVRBIT, t) + oprangeset(AVREV64, t) + oprangeset(AVREV16, t) + + case AVZIP1: + oprangeset(AVZIP2, t) + + case AVUXTL: + oprangeset(AVUXTL2, t) + + case AVUSHLL: + oprangeset(AVUSHLL2, t) + + case AVLD1R: + oprangeset(AVLD2, t) + oprangeset(AVLD2R, t) + oprangeset(AVLD3, t) + oprangeset(AVLD3R, t) + oprangeset(AVLD4, t) + oprangeset(AVLD4R, t) + + case ASHA1H, + AVCNT, + AVMOV, + AVLD1, + AVST1, + AVST2, + AVST3, + AVST4, + AVTBL, + AVDUP, + AVMOVI, + APRFM, + AVEXT: + break + + case obj.ANOP, + obj.AUNDEF, + obj.AFUNCDATA, + obj.APCALIGN, + obj.APCDATA, + obj.ADUFFZERO, + obj.ADUFFCOPY: + break + } + } +} + +// chipfloat7() checks if the immediate constants available in FMOVS/FMOVD instructions. +// For details of the range of constants available, see +// http://infocenter.arm.com/help/topic/com.arm.doc.dui0473m/dom1359731199385.html. +func (c *ctxt7) chipfloat7(e float64) int { + ei := math.Float64bits(e) + l := uint32(int32(ei)) + h := uint32(int32(ei >> 32)) + + if l != 0 || h&0xffff != 0 { + return -1 + } + h1 := h & 0x7fc00000 + if h1 != 0x40000000 && h1 != 0x3fc00000 { + return -1 + } + n := 0 + + // sign bit (a) + if h&0x80000000 != 0 { + n |= 1 << 7 + } + + // exp sign bit (b) + if h1 == 0x3fc00000 { + n |= 1 << 6 + } + + // rest of exp and mantissa (cd-efgh) + n |= int((h >> 16) & 0x3f) + + //print("match %.8lux %.8lux %d\n", l, h, n); + return n +} + +/* form offset parameter to SYS; special register number */ +func SYSARG5(op0 int, op1 int, Cn int, Cm int, op2 int) int { + return op0<<19 | op1<<16 | Cn<<12 | Cm<<8 | op2<<5 +} + +func SYSARG4(op1 int, Cn int, Cm int, op2 int) int { + return SYSARG5(0, op1, Cn, Cm, op2) +} + +// checkUnpredictable checks if the sourse and transfer registers are the same register. +// ARM64 manual says it is "constrained unpredictable" if the src and dst registers of STP/LDP are same. +func (c *ctxt7) checkUnpredictable(p *obj.Prog, isload bool, wback bool, rn int16, rt1 int16, rt2 int16) { + if wback && rn != REGSP && (rn == rt1 || rn == rt2) { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + if isload && rt1 == rt2 { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } +} + +/* checkindex checks if index >= 0 && index <= maxindex */ +func (c *ctxt7) checkindex(p *obj.Prog, index, maxindex int) { + if index < 0 || index > maxindex { + c.ctxt.Diag("register element index out of range 0 to %d: %v", maxindex, p) + } +} + +/* checkoffset checks whether the immediate offset is valid for VLD[1-4].P and VST[1-4].P */ +func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) { + var offset, list, n, expect int64 + switch as { + case AVLD1, AVLD2, AVLD3, AVLD4, AVLD1R, AVLD2R, AVLD3R, AVLD4R: + offset = p.From.Offset + list = p.To.Offset + case AVST1, AVST2, AVST3, AVST4: + offset = p.To.Offset + list = p.From.Offset + default: + c.ctxt.Diag("invalid operation on op %v", p.As) + } + opcode := (list >> 12) & 15 + q := (list >> 30) & 1 + size := (list >> 10) & 3 + if offset == 0 { + return + } + switch opcode { + case 0x7: + n = 1 // one register + case 0xa: + n = 2 // two registers + case 0x6: + n = 3 // three registers + case 0x2: + n = 4 // four registers + default: + c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p) + } + + switch as { + case AVLD1R, AVLD2R, AVLD3R, AVLD4R: + if offset != n*(1<> 5) & 7 + switch p.As { + case AMOVB, AMOVBU: + if amount != 0 { + c.ctxt.Diag("invalid index shift amount: %v", p) + } + case AMOVH, AMOVHU: + if amount != 1 && amount != 0 { + c.ctxt.Diag("invalid index shift amount: %v", p) + } + case AMOVW, AMOVWU, AFMOVS: + if amount != 2 && amount != 0 { + c.ctxt.Diag("invalid index shift amount: %v", p) + } + case AMOVD, AFMOVD: + if amount != 3 && amount != 0 { + c.ctxt.Diag("invalid index shift amount: %v", p) + } + default: + panic("invalid operation") + } +} + +func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { + var os [5]uint32 + o1 := uint32(0) + o2 := uint32(0) + o3 := uint32(0) + o4 := uint32(0) + o5 := uint32(0) + if false { /*debug['P']*/ + fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) + } + switch o.type_ { + default: + c.ctxt.Diag("%v: unknown asm %d", p, o.type_) + + case 0: /* pseudo ops */ + break + + case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */ + o1 = c.oprrr(p, p.As) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 2: /* add/sub $(uimm12|uimm24)[,R],R; cmp $(uimm12|uimm24),R */ + o1 = c.opirr(p, p.As) + + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + if (o1 & Sbit) == 0 { + c.ctxt.Diag("ineffective ZR destination\n%v", p) + } + rt = REGZERO + } + + r := int(p.Reg) + if r == 0 { + r = rt + } + v := int32(c.regoff(&p.From)) + o1 = c.oaddi(p, int32(o1), v, r, rt) + + case 3: /* op R<> 10) & 63 + is64bit := o1 & (1 << 31) + if is64bit == 0 && amount >= 32 { + c.ctxt.Diag("shift amount out of range 0 to 31: %v", p) + } + o1 |= uint32(p.From.Offset) /* includes reg, op, etc */ + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if p.As == AMVN || p.As == AMVNW { + r = REGZERO + } else if r == 0 { + r = rt + } + o1 |= (uint32(r&31) << 5) | uint32(rt&31) + + case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R; mov $addcon2, R */ + rt := int(p.To.Reg) + r := int(o.param) + + if r == 0 { + r = REGZERO + } else if r == REGFROM { + r = int(p.From.Reg) + } + if r == 0 { + r = REGSP + } + + v := int32(c.regoff(&p.From)) + var op int32 + if v < 0 { + v = -v + op = int32(c.opirr(p, ASUB)) + } else { + op = int32(c.opirr(p, AADD)) + } + + if int(o.size) == 8 { + o1 = c.oaddi(p, op, v&0xfff000, r, REGTMP) + o2 = c.oaddi(p, op, v&0x000fff, REGTMP, rt) + break + } + + o1 = c.oaddi(p, op, v, r, rt) + + case 5: /* b s; bl s */ + o1 = c.opbra(p, p.As) + + if p.To.Sym == nil { + o1 |= uint32(c.brdist(p, 0, 26, 2)) + break + } + + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = objabi.R_CALLARM64 + + case 6: /* b ,O(R); bl ,O(R) */ + o1 = c.opbrr(p, p.As) + + o1 |= uint32(p.To.Reg&31) << 5 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 0 + rel.Type = objabi.R_CALLIND + + case 7: /* beq s */ + o1 = c.opbra(p, p.As) + + o1 |= uint32(c.brdist(p, 0, 19, 2) << 5) + + case 8: /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */ + rt := int(p.To.Reg) + + rf := int(p.Reg) + if rf == 0 { + rf = rt + } + v := int32(p.From.Offset) + switch p.As { + case AASR: + o1 = c.opbfm(p, ASBFM, int(v), 63, rf, rt) + + case AASRW: + o1 = c.opbfm(p, ASBFMW, int(v), 31, rf, rt) + + case ALSL: + o1 = c.opbfm(p, AUBFM, int((64-v)&63), int(63-v), rf, rt) + + case ALSLW: + o1 = c.opbfm(p, AUBFMW, int((32-v)&31), int(31-v), rf, rt) + + case ALSR: + o1 = c.opbfm(p, AUBFM, int(v), 63, rf, rt) + + case ALSRW: + o1 = c.opbfm(p, AUBFMW, int(v), 31, rf, rt) + + case AROR: + o1 = c.opextr(p, AEXTR, v, rf, rf, rt) + + case ARORW: + o1 = c.opextr(p, AEXTRW, v, rf, rf, rt) + + default: + c.ctxt.Diag("bad shift $con\n%v", p) + break + } + + case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */ + o1 = c.oprrr(p, p.As) + + r := int(p.Reg) + if r == 0 { + r = int(p.To.Reg) + } + o1 |= (uint32(p.From.Reg&31) << 16) | (uint32(r&31) << 5) | uint32(p.To.Reg&31) + + case 10: /* brk/hvc/.../svc [$con] */ + o1 = c.opimm(p, p.As) + + if p.From.Type != obj.TYPE_NONE { + o1 |= uint32((p.From.Offset & 0xffff) << 5) + } + + case 11: /* dword */ + c.aclass(&p.To) + + o1 = uint32(c.instoffset) + o2 = uint32(c.instoffset >> 32) + if p.To.Sym != nil { + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = objabi.R_ADDR + o2 = 0 + o1 = o2 + } + + case 12: /* movT $vcon, reg */ + // NOTE: this case does not use REGTMP. If it ever does, + // remove the NOTUSETMP flag in optab. + num := c.omovlconst(p.As, p, &p.From, int(p.To.Reg), os[:]) + if num == 0 { + c.ctxt.Diag("invalid constant: %v", p) + } + o1 = os[0] + o2 = os[1] + o3 = os[2] + o4 = os[3] + + case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */ + o := uint32(0) + num := uint8(0) + cls := oclass(&p.From) + if isADDWop(p.As) { + if !cmp(C_LCON, cls) { + c.ctxt.Diag("illegal combination: %v", p) + } + num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:]) + } else { + num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:]) + } + if num == 0 { + c.ctxt.Diag("invalid constant: %v", p) + } + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) { + o = c.opxrrr(p, p.As, false) + o |= REGTMP & 31 << 16 + o |= LSL0_64 + } else { + o = c.oprrr(p, p.As) + o |= REGTMP & 31 << 16 /* shift is 0 */ + } + + o |= uint32(r&31) << 5 + o |= uint32(rt & 31) + + os[num] = o + o1 = os[0] + o2 = os[1] + o3 = os[2] + o4 = os[3] + o5 = os[4] + + case 14: /* word */ + if c.aclass(&p.To) == C_ADDR { + c.ctxt.Diag("address constant needs DWORD\n%v", p) + } + o1 = uint32(c.instoffset) + if p.To.Sym != nil { + // This case happens with words generated + // in the PC stream as part of the literal pool. + rel := obj.Addrel(c.cursym) + + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = objabi.R_ADDR + o1 = 0 + } + + case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub/fmadd/fmsub/fnmadd/fnmsub Rm,Ra,Rn,Rd */ + o1 = c.oprrr(p, p.As) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + var r int + var ra int + if p.From3Type() == obj.TYPE_REG { + r = int(p.GetFrom3().Reg) + ra = int(p.Reg) + if ra == 0 { + ra = REGZERO + } + } else { + r = int(p.Reg) + if r == 0 { + r = rt + } + ra = REGZERO + } + + o1 |= (uint32(rf&31) << 16) | (uint32(ra&31) << 10) | (uint32(r&31) << 5) | uint32(rt&31) + + case 16: /* XremY R[,R],R -> XdivY; XmsubY */ + o1 = c.oprrr(p, p.As) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | REGTMP&31 + o2 = c.oprrr(p, AMSUBW) + o2 |= o1 & (1 << 31) /* same size */ + o2 |= (uint32(rf&31) << 16) | (uint32(r&31) << 10) | (REGTMP & 31 << 5) | uint32(rt&31) + + case 17: /* op Rm,[Rn],Rd; default Rn=ZR */ + o1 = c.oprrr(p, p.As) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + if r == 0 { + r = REGZERO + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */ + o1 = c.oprrr(p, p.As) + + cond := int(p.From.Reg) + if cond < COND_EQ || cond > COND_NV { + c.ctxt.Diag("invalid condition: %v", p) + } else { + cond -= COND_EQ + } + + r := int(p.Reg) + var rf int + if r != 0 { + if p.From3Type() == obj.TYPE_NONE { + /* CINC/CINV/CNEG */ + rf = r + cond ^= 1 + } else { + rf = int(p.GetFrom3().Reg) /* CSEL */ + } + } else { + /* CSET */ + rf = REGZERO + r = rf + cond ^= 1 + } + + rt := int(p.To.Reg) + o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(r&31) << 5) | uint32(rt&31) + + case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */ + nzcv := int(p.To.Offset) + + cond := int(p.From.Reg) + if cond < COND_EQ || cond > COND_NV { + c.ctxt.Diag("invalid condition\n%v", p) + } else { + cond -= COND_EQ + } + var rf int + if p.GetFrom3().Type == obj.TYPE_REG { + o1 = c.oprrr(p, p.As) + rf = int(p.GetFrom3().Reg) /* Rm */ + } else { + o1 = c.opirr(p, p.As) + rf = int(p.GetFrom3().Offset & 0x1F) + } + + o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv) + + case 20: /* movT R,O(R) -> strT */ + v := int32(c.regoff(&p.To)) + sz := int32(1 << uint(movesize(p.As))) + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */ + o1 = c.olsr9s(p, int32(c.opstr9(p, p.As)), v, r, int(p.From.Reg)) + } else { + v = int32(c.offsetshift(p, int64(v), int(o.a4))) + o1 = c.olsr12u(p, int32(c.opstr12(p, p.As)), v, r, int(p.From.Reg)) + } + + case 21: /* movT O(R),R -> ldrT */ + v := int32(c.regoff(&p.From)) + sz := int32(1 << uint(movesize(p.As))) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */ + o1 = c.olsr9s(p, int32(c.opldr9(p, p.As)), v, r, int(p.To.Reg)) + } else { + v = int32(c.offsetshift(p, int64(v), int(o.a1))) + //print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1); + o1 = c.olsr12u(p, int32(c.opldr12(p, p.As)), v, r, int(p.To.Reg)) + } + + case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */ + if p.From.Reg != REGSP && p.From.Reg == p.To.Reg { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + + v := int32(p.From.Offset) + + if v < -256 || v > 255 { + c.ctxt.Diag("offset out of range [-255,254]: %v", p) + } + o1 = c.opldrpp(p, p.As) + if o.scond == C_XPOST { + o1 |= 1 << 10 + } else { + o1 |= 3 << 10 + } + o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.From.Reg&31) << 5) | uint32(p.To.Reg&31) + + case 23: /* movT R,(R)O!; movT O(R)!, R -> strT */ + if p.To.Reg != REGSP && p.From.Reg == p.To.Reg { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + + v := int32(p.To.Offset) + + if v < -256 || v > 255 { + c.ctxt.Diag("offset out of range [-255,254]: %v", p) + } + o1 = LD2STR(c.opldrpp(p, p.As)) + if o.scond == C_XPOST { + o1 |= 1 << 10 + } else { + o1 |= 3 << 10 + } + o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.To.Reg&31) << 5) | uint32(p.From.Reg&31) + + case 24: /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + s := rf == REGSP || rt == REGSP + if p.As == AMVN || p.As == AMVNW { + if s { + c.ctxt.Diag("illegal SP reference\n%v", p) + } + o1 = c.oprrr(p, p.As) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + } else if s { + o1 = c.opirr(p, p.As) + o1 |= (uint32(rf&31) << 5) | uint32(rt&31) + } else { + o1 = c.oprrr(p, p.As) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + } + + case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */ + o1 = c.oprrr(p, p.As) + + rf := int(p.From.Reg) + if rf == C_NONE { + rf = int(p.To.Reg) + } + rt := int(p.To.Reg) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + + case 26: /* negX Rm< subX Rm<> 5) & 7 + if amount > 4 { + c.ctxt.Diag("shift amount out of range 0 to 4: %v", p) + } + o1 = c.opxrrr(p, p.As, true) + o1 |= c.encRegShiftOrExt(&p.From, p.From.Reg) /* includes reg, op, etc */ + } else { + o1 = c.opxrrr(p, p.As, false) + o1 |= uint32(p.From.Reg&31) << 16 + } + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 |= (uint32(r&31) << 5) | uint32(rt&31) + + case 28: /* logop $vcon, [R], R (64 bit literal) */ + o := uint32(0) + num := uint8(0) + cls := oclass(&p.From) + if isANDWop(p.As) { + if !cmp(C_LCON, cls) { + c.ctxt.Diag("illegal combination: %v", p) + } + num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:]) + } else { + num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:]) + } + + if num == 0 { + c.ctxt.Diag("invalid constant: %v", p) + } + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + o = c.oprrr(p, p.As) + o |= REGTMP & 31 << 16 /* shift is 0 */ + o |= uint32(r&31) << 5 + o |= uint32(rt & 31) + + os[num] = o + o1 = os[0] + o2 = os[1] + o3 = os[2] + o4 = os[3] + o5 = os[4] + + case 29: /* op Rn, Rd */ + fc := c.aclass(&p.From) + tc := c.aclass(&p.To) + if (p.As == AFMOVD || p.As == AFMOVS) && (fc == C_REG || fc == C_ZCON || tc == C_REG || tc == C_ZCON) { + // FMOV Rx, Fy or FMOV Fy, Rx + o1 = FPCVTI(0, 0, 0, 0, 6) + if p.As == AFMOVD { + o1 |= 1<<31 | 1<<22 // 64-bit + } + if fc == C_REG || fc == C_ZCON { + o1 |= 1 << 16 // FMOV Rx, Fy + } + } else { + o1 = c.oprrr(p, p.As) + } + o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31) + + case 30: /* movT R,L(R) -> strT */ + // if offset L can be split into hi+lo, and both fit into instructions, do + // add $hi, R, Rtmp + // str R, lo(Rtmp) + // otherwise, use constant pool + // mov $L, Rtmp (from constant pool) + // str R, (R+Rtmp) + s := movesize(o.as) + if s < 0 { + c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p) + } + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + + v := int32(c.regoff(&p.To)) + var hi int32 + if v < 0 || (v&((1<>uint(s))&0xFFF, REGTMP, int(p.From.Reg)) + break + + storeusepool: + if r == REGTMP || p.From.Reg == REGTMP { + c.ctxt.Diag("REGTMP used in large offset store: %v", p) + } + o1 = c.omovlit(AMOVD, p, &p.To, REGTMP) + o2 = c.olsxrr(p, int32(c.opstrr(p, p.As, false)), int(p.From.Reg), r, REGTMP) + + case 31: /* movT L(R), R -> ldrT */ + // if offset L can be split into hi+lo, and both fit into instructions, do + // add $hi, R, Rtmp + // ldr lo(Rtmp), R + // otherwise, use constant pool + // mov $L, Rtmp (from constant pool) + // ldr (R+Rtmp), R + s := movesize(o.as) + if s < 0 { + c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p) + } + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + + v := int32(c.regoff(&p.From)) + var hi int32 + if v < 0 || (v&((1<>uint(s))&0xFFF, REGTMP, int(p.To.Reg)) + break + + loadusepool: + if r == REGTMP || p.From.Reg == REGTMP { + c.ctxt.Diag("REGTMP used in large offset load: %v", p) + } + o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) + o2 = c.olsxrr(p, int32(c.opldrr(p, p.As, false)), int(p.To.Reg), r, REGTMP) + + case 32: /* mov $con, R -> movz/movn */ + o1 = c.omovconst(p.As, p, &p.From, int(p.To.Reg)) + + case 33: /* movk $uimm16 << pos */ + o1 = c.opirr(p, p.As) + + d := p.From.Offset + s := movcon(d) + if s < 0 || s >= 4 { + c.ctxt.Diag("bad constant for MOVK: %#x\n%v", uint64(d), p) + } + if (o1&S64) == 0 && s >= 2 { + c.ctxt.Diag("illegal bit position\n%v", p) + } + if ((d >> uint(s*16)) >> 16) != 0 { + c.ctxt.Diag("requires uimm16\n%v", p) + } + rt := int(p.To.Reg) + + o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31)) + + case 34: /* mov $lacon,R */ + o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) + + if o1 == 0 { + break + } + o2 = c.opxrrr(p, AADD, false) + o2 |= REGTMP & 31 << 16 + o2 |= LSL0_64 + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 |= uint32(r&31) << 5 + o2 |= uint32(p.To.Reg & 31) + + case 35: /* mov SPR,R -> mrs */ + o1 = c.oprrr(p, AMRS) + + // SysRegEnc function returns the system register encoding and accessFlags. + _, v, accessFlags := SysRegEnc(p.From.Reg) + if v == 0 { + c.ctxt.Diag("illegal system register:\n%v", p) + } + if (o1 & (v &^ (3 << 19))) != 0 { + c.ctxt.Diag("MRS register value overlap\n%v", p) + } + if accessFlags&SR_READ == 0 { + c.ctxt.Diag("system register is not readable: %v", p) + } + + o1 |= v + o1 |= uint32(p.To.Reg & 31) + + case 36: /* mov R,SPR */ + o1 = c.oprrr(p, AMSR) + + // SysRegEnc function returns the system register encoding and accessFlags. + _, v, accessFlags := SysRegEnc(p.To.Reg) + if v == 0 { + c.ctxt.Diag("illegal system register:\n%v", p) + } + if (o1 & (v &^ (3 << 19))) != 0 { + c.ctxt.Diag("MSR register value overlap\n%v", p) + } + if accessFlags&SR_WRITE == 0 { + c.ctxt.Diag("system register is not writable: %v", p) + } + + o1 |= v + o1 |= uint32(p.From.Reg & 31) + + case 37: /* mov $con,PSTATEfield -> MSR [immediate] */ + if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 { + c.ctxt.Diag("illegal immediate for PSTATE field\n%v", p) + } + o1 = c.opirr(p, AMSR) + o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */ + v := uint32(0) + for i := 0; i < len(pstatefield); i++ { + if pstatefield[i].reg == p.To.Reg { + v = pstatefield[i].enc + break + } + } + + if v == 0 { + c.ctxt.Diag("illegal PSTATE field for immediate move\n%v", p) + } + o1 |= v + + case 38: /* clrex [$imm] */ + o1 = c.opimm(p, p.As) + + if p.To.Type == obj.TYPE_NONE { + o1 |= 0xF << 8 + } else { + o1 |= uint32((p.To.Offset & 0xF) << 8) + } + + case 39: /* cbz R, rel */ + o1 = c.opirr(p, p.As) + + o1 |= uint32(p.From.Reg & 31) + o1 |= uint32(c.brdist(p, 0, 19, 2) << 5) + + case 40: /* tbz */ + o1 = c.opirr(p, p.As) + + v := int32(p.From.Offset) + if v < 0 || v > 63 { + c.ctxt.Diag("illegal bit number\n%v", p) + } + o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19) + o1 |= uint32(c.brdist(p, 0, 14, 2) << 5) + o1 |= uint32(p.Reg & 31) + + case 41: /* eret, nop, others with no operands */ + o1 = c.op0(p, p.As) + + case 42: /* bfm R,r,s,R */ + o1 = c.opbfm(p, p.As, int(p.From.Offset), int(p.GetFrom3().Offset), int(p.Reg), int(p.To.Reg)) + + case 43: /* bfm aliases */ + r := int(p.From.Offset) + s := int(p.GetFrom3().Offset) + rf := int(p.Reg) + rt := int(p.To.Reg) + if rf == 0 { + rf = rt + } + switch p.As { + case ABFI: + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, ABFM, r, s-1, rf, rt) + + case ABFIW: + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, ABFMW, r, s-1, rf, rt) + + case ABFXIL: + o1 = c.opbfm(p, ABFM, r, r+s-1, rf, rt) + + case ABFXILW: + o1 = c.opbfm(p, ABFMW, r, r+s-1, rf, rt) + + case ASBFIZ: + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, ASBFM, r, s-1, rf, rt) + + case ASBFIZW: + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, ASBFMW, r, s-1, rf, rt) + + case ASBFX: + o1 = c.opbfm(p, ASBFM, r, r+s-1, rf, rt) + + case ASBFXW: + o1 = c.opbfm(p, ASBFMW, r, r+s-1, rf, rt) + + case AUBFIZ: + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, AUBFM, r, s-1, rf, rt) + + case AUBFIZW: + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, AUBFMW, r, s-1, rf, rt) + + case AUBFX: + o1 = c.opbfm(p, AUBFM, r, r+s-1, rf, rt) + + case AUBFXW: + o1 = c.opbfm(p, AUBFMW, r, r+s-1, rf, rt) + + default: + c.ctxt.Diag("bad bfm alias\n%v", p) + break + } + + case 44: /* extr $b, Rn, Rm, Rd */ + o1 = c.opextr(p, p.As, int32(p.From.Offset), int(p.GetFrom3().Reg), int(p.Reg), int(p.To.Reg)) + + case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */ + rf := int(p.From.Reg) + + rt := int(p.To.Reg) + as := p.As + if rf == REGZERO { + as = AMOVWU /* clearer in disassembly */ + } + switch as { + case AMOVB, ASXTB: + o1 = c.opbfm(p, ASBFM, 0, 7, rf, rt) + + case AMOVH, ASXTH: + o1 = c.opbfm(p, ASBFM, 0, 15, rf, rt) + + case AMOVW, ASXTW: + o1 = c.opbfm(p, ASBFM, 0, 31, rf, rt) + + case AMOVBU, AUXTB: + o1 = c.opbfm(p, AUBFM, 0, 7, rf, rt) + + case AMOVHU, AUXTH: + o1 = c.opbfm(p, AUBFM, 0, 15, rf, rt) + + case AMOVWU: + o1 = c.oprrr(p, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + + case AUXTW: + o1 = c.opbfm(p, AUBFM, 0, 31, rf, rt) + + case ASXTBW: + o1 = c.opbfm(p, ASBFMW, 0, 7, rf, rt) + + case ASXTHW: + o1 = c.opbfm(p, ASBFMW, 0, 15, rf, rt) + + case AUXTBW: + o1 = c.opbfm(p, AUBFMW, 0, 7, rf, rt) + + case AUXTHW: + o1 = c.opbfm(p, AUBFMW, 0, 15, rf, rt) + + default: + c.ctxt.Diag("bad sxt %v", as) + break + } + + case 46: /* cls */ + o1 = c.opbit(p, p.As) + + o1 |= uint32(p.From.Reg&31) << 5 + o1 |= uint32(p.To.Reg & 31) + + case 47: /* SWPx/LDADDx/LDANDx/LDEORx/LDORx Rs, (Rb), Rt */ + rs := p.From.Reg + rt := p.RegTo2 + rb := p.To.Reg + + fields := atomicInstructions[p.As] + // rt can't be sp. rt can't be r31 when field A is 0, A bit is the 23rd bit. + if rt == REG_RSP || (rt == REGZERO && (fields&(1<<23) == 0)) { + c.ctxt.Diag("illegal destination register: %v\n", p) + } + o1 |= fields | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31) + + case 48: /* ADD $C_ADDCON2, Rm, Rd */ + // NOTE: this case does not use REGTMP. If it ever does, + // remove the NOTUSETMP flag in optab. + op := c.opirr(p, p.As) + if op&Sbit != 0 { + c.ctxt.Diag("can not break addition/subtraction when S bit is set", p) + } + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0x000fff, r, rt) + o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0xfff000, rt, rt) + + case 50: /* sys/sysl */ + o1 = c.opirr(p, p.As) + + if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 { + c.ctxt.Diag("illegal SYS argument\n%v", p) + } + o1 |= uint32(p.From.Offset) + if p.To.Type == obj.TYPE_REG { + o1 |= uint32(p.To.Reg & 31) + } else if p.Reg != 0 { + o1 |= uint32(p.Reg & 31) + } else { + o1 |= 0x1F + } + + case 51: /* dmb */ + o1 = c.opirr(p, p.As) + + if p.From.Type == obj.TYPE_CONST { + o1 |= uint32((p.From.Offset & 0xF) << 8) + } + + case 52: /* hint */ + o1 = c.opirr(p, p.As) + + o1 |= uint32((p.From.Offset & 0x7F) << 5) + + case 53: /* and/or/eor/bic/tst/... $bitcon, Rn, Rd */ + a := p.As + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + mode := 64 + v := uint64(p.From.Offset) + switch p.As { + case AANDW, AORRW, AEORW, AANDSW, ATSTW: + mode = 32 + case ABIC, AORN, AEON, ABICS: + v = ^v + case ABICW, AORNW, AEONW, ABICSW: + v = ^v + mode = 32 + } + o1 = c.opirr(p, a) + o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31) + + case 54: /* floating point arith */ + o1 = c.oprrr(p, p.As) + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if (o1&(0x1F<<24)) == (0x1E<<24) && (o1&(1<<11)) == 0 { /* monadic */ + r = rf + rf = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 55: /* floating-point constant */ + var rf int + o1 = 0xf<<25 | 1<<21 | 1<<12 + rf = c.chipfloat7(p.From.Val.(float64)) + if rf < 0 { + c.ctxt.Diag("invalid floating-point immediate\n%v", p) + } + if p.As == AFMOVD { + o1 |= 1 << 22 + } + o1 |= (uint32(rf&0xff) << 13) | uint32(p.To.Reg&31) + + case 56: /* floating point compare */ + o1 = c.oprrr(p, p.As) + + var rf int + if p.From.Type == obj.TYPE_FCONST { + o1 |= 8 /* zero */ + rf = 0 + } else { + rf = int(p.From.Reg) + } + rt := int(p.Reg) + o1 |= uint32(rf&31)<<16 | uint32(rt&31)<<5 + + case 57: /* floating point conditional compare */ + o1 = c.oprrr(p, p.As) + + cond := int(p.From.Reg) + if cond < COND_EQ || cond > COND_NV { + c.ctxt.Diag("invalid condition\n%v", p) + } else { + cond -= COND_EQ + } + + nzcv := int(p.To.Offset) + if nzcv&^0xF != 0 { + c.ctxt.Diag("implausible condition\n%v", p) + } + rf := int(p.Reg) + if p.GetFrom3() == nil || p.GetFrom3().Reg < REG_F0 || p.GetFrom3().Reg > REG_F31 { + c.ctxt.Diag("illegal FCCMP\n%v", p) + break + } + rt := int(p.GetFrom3().Reg) + o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv) + + case 58: /* ldar/ldarb/ldarh/ldaxp/ldxp/ldaxr/ldxr */ + o1 = c.opload(p, p.As) + + o1 |= 0x1F << 16 + o1 |= uint32(p.From.Reg&31) << 5 + if p.As == ALDXP || p.As == ALDXPW || p.As == ALDAXP || p.As == ALDAXPW { + if int(p.To.Reg) == int(p.To.Offset) { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + o1 |= uint32(p.To.Offset&31) << 10 + } else { + o1 |= 0x1F << 10 + } + o1 |= uint32(p.To.Reg & 31) + + case 59: /* stxr/stlxr/stxp/stlxp */ + s := p.RegTo2 + n := p.To.Reg + t := p.From.Reg + if isSTLXRop(p.As) { + if s == t || (s == n && n != REGSP) { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + } else if isSTXPop(p.As) { + t2 := int16(p.From.Offset) + if (s == t || s == t2) || (s == n && n != REGSP) { + c.ctxt.Diag("constrained unpredictable behavior: %v", p) + } + } + if s == REG_RSP { + c.ctxt.Diag("illegal destination register: %v\n", p) + } + o1 = c.opstore(p, p.As) + + if p.RegTo2 != obj.REG_NONE { + o1 |= uint32(p.RegTo2&31) << 16 + } else { + o1 |= 0x1F << 16 + } + if isSTXPop(p.As) { + o1 |= uint32(p.From.Offset&31) << 10 + } + o1 |= uint32(p.To.Reg&31)<<5 | uint32(p.From.Reg&31) + + case 60: /* adrp label,r */ + d := c.brdist(p, 12, 21, 0) + + o1 = ADR(1, uint32(d), uint32(p.To.Reg)) + + case 61: /* adr label, r */ + d := c.brdist(p, 0, 21, 0) + + o1 = ADR(0, uint32(d), uint32(p.To.Reg)) + + case 62: /* op $movcon, [R], R -> mov $movcon, REGTMP + op REGTMP, [R], R */ + if p.Reg == REGTMP { + c.ctxt.Diag("cannot use REGTMP as source: %v\n", p) + } + if isADDWop(p.As) || isANDWop(p.As) { + o1 = c.omovconst(AMOVW, p, &p.From, REGTMP) + } else { + o1 = c.omovconst(AMOVD, p, &p.From, REGTMP) + } + + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + if p.To.Reg == REGSP || r == REGSP { + o2 = c.opxrrr(p, p.As, false) + o2 |= REGTMP & 31 << 16 + o2 |= LSL0_64 + } else { + o2 = c.oprrr(p, p.As) + o2 |= REGTMP & 31 << 16 /* shift is 0 */ + } + o2 |= uint32(r&31) << 5 + o2 |= uint32(rt & 31) + + /* reloc ops */ + case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */ + o1 = ADR(1, 0, REGTMP) + o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = objabi.R_ADDRARM64 + o3 = c.olsr12u(p, int32(c.opstr12(p, p.As)), 0, REGTMP, int(p.From.Reg)) + + case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */ + o1 = ADR(1, 0, REGTMP) + o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.From.Sym + rel.Add = p.From.Offset + rel.Type = objabi.R_ADDRARM64 + o3 = c.olsr12u(p, int32(c.opldr12(p, p.As)), 0, REGTMP, int(p.To.Reg)) + + case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */ + v := int32(c.regoff(&p.From)) + r := int(p.From.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid ldp source: %v\n", p) + } + o1 |= c.opldpstp(p, o, v, uint32(r), uint32(p.To.Reg), uint32(p.To.Offset), 1) + + case 67: /* stp (r1, r2), O(R)!; stp (r1, r2), (R)O! */ + r := int(p.To.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid stp destination: %v\n", p) + } + v := int32(c.regoff(&p.To)) + o1 = c.opldpstp(p, o, v, uint32(r), uint32(p.From.Reg), uint32(p.From.Offset), 0) + + case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */ + // NOTE: this case does not use REGTMP. If it ever does, + // remove the NOTUSETMP flag in optab. + if p.As == AMOVW { + c.ctxt.Diag("invalid load of 32-bit address: %v", p) + } + o1 = ADR(1, 0, uint32(p.To.Reg)) + o2 = c.opirr(p, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31) + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.From.Sym + rel.Add = p.From.Offset + rel.Type = objabi.R_ADDRARM64 + + case 69: /* LE model movd $tlsvar, reg -> movz reg, 0 + reloc */ + o1 = c.opirr(p, AMOVZ) + o1 |= uint32(p.To.Reg & 31) + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 4 + rel.Sym = p.From.Sym + rel.Type = objabi.R_ARM64_TLS_LE + if p.From.Offset != 0 { + c.ctxt.Diag("invalid offset on MOVW $tlsvar") + } + + case 70: /* IE model movd $tlsvar, reg -> adrp REGTMP, 0; ldr reg, [REGTMP, #0] + relocs */ + o1 = ADR(1, 0, REGTMP) + o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg)) + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.From.Sym + rel.Add = 0 + rel.Type = objabi.R_ARM64_TLS_IE + if p.From.Offset != 0 { + c.ctxt.Diag("invalid offset on MOVW $tlsvar") + } + + case 71: /* movd sym@GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */ + o1 = ADR(1, 0, REGTMP) + o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg)) + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.From.Sym + rel.Add = 0 + rel.Type = objabi.R_ARM64_GOTPCREL + + case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2 Vm., Vn., Vd. */ + af := int((p.From.Reg >> 5) & 15) + af3 := int((p.Reg >> 5) & 15) + at := int((p.To.Reg >> 5) & 15) + if af != af3 || af != at { + c.ctxt.Diag("operand mismatch: %v", p) + break + } + o1 = c.oprrr(p, p.As) + rf := int((p.From.Reg) & 31) + rt := int((p.To.Reg) & 31) + r := int((p.Reg) & 31) + + Q := 0 + size := 0 + switch af { + case ARNG_16B: + Q = 1 + size = 0 + case ARNG_2D: + Q = 1 + size = 3 + case ARNG_2S: + Q = 0 + size = 2 + case ARNG_4H: + Q = 0 + size = 1 + case ARNG_4S: + Q = 1 + size = 2 + case ARNG_8B: + Q = 0 + size = 0 + case ARNG_8H: + Q = 1 + size = 1 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + + switch p.As { + case AVORR, AVAND, AVEOR, AVBIT, AVBSL, AVBIF: + if af != ARNG_16B && af != ARNG_8B { + c.ctxt.Diag("invalid arrangement: %v", p) + } + case AVFMLA, AVFMLS: + if af != ARNG_2D && af != ARNG_2S && af != ARNG_4S { + c.ctxt.Diag("invalid arrangement: %v", p) + } + } + switch p.As { + case AVAND, AVEOR: + size = 0 + case AVBSL: + size = 1 + case AVORR, AVBIT, AVBIF: + size = 2 + case AVFMLA, AVFMLS: + if af == ARNG_2D { + size = 1 + } else { + size = 0 + } + } + + o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 73: /* vmov V.[index], R */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + imm5 := 0 + o1 = 7<<25 | 0xf<<10 + index := int(p.From.Index) + switch (p.From.Reg >> 5) & 15 { + case ARNG_B: + c.checkindex(p, index, 15) + imm5 |= 1 + imm5 |= index << 1 + case ARNG_H: + c.checkindex(p, index, 7) + imm5 |= 2 + imm5 |= index << 2 + case ARNG_S: + c.checkindex(p, index, 3) + imm5 |= 4 + imm5 |= index << 3 + case ARNG_D: + c.checkindex(p, index, 1) + imm5 |= 8 + imm5 |= index << 4 + o1 |= 1 << 30 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 74: + // add $O, R, Rtmp or sub $O, R, Rtmp + // ldp (Rtmp), (R1, R2) + r := int(p.From.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid ldp source: %v", p) + } + v := int32(c.regoff(&p.From)) + + if v > 0 { + if v > 4095 { + c.ctxt.Diag("offset out of range: %v", p) + } + o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP) + } + if v < 0 { + if v < -4095 { + c.ctxt.Diag("offset out of range: %v", p) + } + o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP) + } + o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1) + + case 75: + // mov $L, Rtmp (from constant pool) + // add Rtmp, R, Rtmp + // ldp (Rtmp), (R1, R2) + r := int(p.From.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid ldp source: %v", p) + } + o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) + o2 = c.opxrrr(p, AADD, false) + o2 |= (REGTMP & 31) << 16 + o2 |= uint32(r&31) << 5 + o2 |= uint32(REGTMP & 31) + o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1) + + case 76: + // add $O, R, Rtmp or sub $O, R, Rtmp + // stp (R1, R2), (Rtmp) + r := int(p.To.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid stp destination: %v", p) + } + v := int32(c.regoff(&p.To)) + if v > 0 { + if v > 4095 { + c.ctxt.Diag("offset out of range: %v", p) + } + o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP) + } + if v < 0 { + if v < -4095 { + c.ctxt.Diag("offset out of range: %v", p) + } + o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP) + } + o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0) + + case 77: + // mov $L, Rtmp (from constant pool) + // add Rtmp, R, Rtmp + // stp (R1, R2), (Rtmp) + r := int(p.To.Reg) + if r == obj.REG_NONE { + r = int(o.param) + } + if r == obj.REG_NONE { + c.ctxt.Diag("invalid stp destination: %v", p) + } + o1 = c.omovlit(AMOVD, p, &p.To, REGTMP) + o2 = c.opxrrr(p, AADD, false) + o2 |= REGTMP & 31 << 16 + o2 |= uint32(r&31) << 5 + o2 |= uint32(REGTMP & 31) + o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0) + + case 78: /* vmov R, V.[index] */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + imm5 := 0 + o1 = 1<<30 | 7<<25 | 7<<10 + index := int(p.To.Index) + switch (p.To.Reg >> 5) & 15 { + case ARNG_B: + c.checkindex(p, index, 15) + imm5 |= 1 + imm5 |= index << 1 + case ARNG_H: + c.checkindex(p, index, 7) + imm5 |= 2 + imm5 |= index << 2 + case ARNG_S: + c.checkindex(p, index, 3) + imm5 |= 4 + imm5 |= index << 3 + case ARNG_D: + c.checkindex(p, index, 1) + imm5 |= 8 + imm5 |= index << 4 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 79: /* vdup Vn.[index], Vd. */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + o1 = 7<<25 | 1<<10 + var imm5, Q int + index := int(p.From.Index) + switch (p.To.Reg >> 5) & 15 { + case ARNG_16B: + c.checkindex(p, index, 15) + Q = 1 + imm5 = 1 + imm5 |= index << 1 + case ARNG_2D: + c.checkindex(p, index, 1) + Q = 1 + imm5 = 8 + imm5 |= index << 4 + case ARNG_2S: + c.checkindex(p, index, 3) + Q = 0 + imm5 = 4 + imm5 |= index << 3 + case ARNG_4H: + c.checkindex(p, index, 7) + Q = 0 + imm5 = 2 + imm5 |= index << 2 + case ARNG_4S: + c.checkindex(p, index, 3) + Q = 1 + imm5 = 4 + imm5 |= index << 3 + case ARNG_8B: + c.checkindex(p, index, 15) + Q = 0 + imm5 = 1 + imm5 |= index << 1 + case ARNG_8H: + c.checkindex(p, index, 7) + Q = 1 + imm5 = 2 + imm5 |= index << 2 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + o1 |= (uint32(Q&1) << 30) | (uint32(imm5&0x1f) << 16) + o1 |= (uint32(rf&31) << 5) | uint32(rt&31) + + case 80: /* vmov V.[index], Vn */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + imm5 := 0 + index := int(p.From.Index) + switch p.As { + case AVMOV: + o1 = 1<<30 | 15<<25 | 1<<10 + switch (p.From.Reg >> 5) & 15 { + case ARNG_B: + c.checkindex(p, index, 15) + imm5 |= 1 + imm5 |= index << 1 + case ARNG_H: + c.checkindex(p, index, 7) + imm5 |= 2 + imm5 |= index << 2 + case ARNG_S: + c.checkindex(p, index, 3) + imm5 |= 4 + imm5 |= index << 3 + case ARNG_D: + c.checkindex(p, index, 1) + imm5 |= 8 + imm5 |= index << 4 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + default: + c.ctxt.Diag("unsupported op %v", p.As) + } + o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 81: /* vld[1-4]|vld[1-4]r (Rn), [Vt1., Vt2., ...] */ + c.checkoffset(p, p.As) + r := int(p.From.Reg) + o1 = c.oprrr(p, p.As) + if o.scond == C_XPOST { + o1 |= 1 << 23 + if p.From.Index == 0 { + // immediate offset variant + o1 |= 0x1f << 16 + } else { + // register offset variant + if isRegShiftOrExt(&p.From) { + c.ctxt.Diag("invalid extended register op: %v\n", p) + } + o1 |= uint32(p.From.Index&0x1f) << 16 + } + } + o1 |= uint32(p.To.Offset) + // cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset + // add opcode(bit 12-15) for vld1, mask it off if it's not vld1 + o1 = c.maskOpvldvst(p, o1) + o1 |= uint32(r&31) << 5 + + case 82: /* vmov Rn, Vd. */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + o1 = 7<<25 | 3<<10 + var imm5, Q uint32 + switch (p.To.Reg >> 5) & 15 { + case ARNG_16B: + Q = 1 + imm5 = 1 + case ARNG_2D: + Q = 1 + imm5 = 8 + case ARNG_2S: + Q = 0 + imm5 = 4 + case ARNG_4H: + Q = 0 + imm5 = 2 + case ARNG_4S: + Q = 1 + imm5 = 4 + case ARNG_8B: + Q = 0 + imm5 = 1 + case ARNG_8H: + Q = 1 + imm5 = 2 + default: + c.ctxt.Diag("invalid arrangement on VMOV Rn, Vd.: %v\n", p) + } + o1 |= (Q & 1 << 30) | (imm5 & 0x1f << 16) + o1 |= (uint32(rf&31) << 5) | uint32(rt&31) + + case 83: /* vmov Vn., Vd. */ + af := int((p.From.Reg >> 5) & 15) + at := int((p.To.Reg >> 5) & 15) + if af != at { + c.ctxt.Diag("invalid arrangement: %v\n", p) + } + o1 = c.oprrr(p, p.As) + rf := int((p.From.Reg) & 31) + rt := int((p.To.Reg) & 31) + + var Q, size uint32 + switch af { + case ARNG_8B: + Q = 0 + size = 0 + case ARNG_16B: + Q = 1 + size = 0 + case ARNG_4H: + Q = 0 + size = 1 + case ARNG_8H: + Q = 1 + size = 1 + case ARNG_2S: + Q = 0 + size = 2 + case ARNG_4S: + Q = 1 + size = 2 + default: + c.ctxt.Diag("invalid arrangement: %v\n", p) + } + + if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) { + c.ctxt.Diag("invalid arrangement: %v", p) + } + + if p.As == AVREV32 && (af == ARNG_2S || af == ARNG_4S) { + c.ctxt.Diag("invalid arrangement: %v", p) + } + + if p.As == AVREV16 && af != ARNG_8B && af != ARNG_16B { + c.ctxt.Diag("invalid arrangement: %v", p) + } + + if p.As == AVMOV { + o1 |= uint32(rf&31) << 16 + } + + if p.As == AVRBIT { + size = 1 + } + + o1 |= (Q&1)<<30 | (size&3)<<22 | uint32(rf&31)<<5 | uint32(rt&31) + + case 84: /* vst[1-4] [Vt1., Vt2., ...], (Rn) */ + c.checkoffset(p, p.As) + r := int(p.To.Reg) + o1 = 3 << 26 + if o.scond == C_XPOST { + o1 |= 1 << 23 + if p.To.Index == 0 { + // immediate offset variant + o1 |= 0x1f << 16 + } else { + // register offset variant + if isRegShiftOrExt(&p.To) { + c.ctxt.Diag("invalid extended register: %v\n", p) + } + o1 |= uint32(p.To.Index&31) << 16 + } + } + o1 |= uint32(p.From.Offset) + // cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset + // add opcode(bit 12-15) for vst1, mask it off if it's not vst1 + o1 = c.maskOpvldvst(p, o1) + o1 |= uint32(r&31) << 5 + + case 85: /* vaddv/vuaddlv Vn., Vd*/ + af := int((p.From.Reg >> 5) & 15) + o1 = c.oprrr(p, p.As) + rf := int((p.From.Reg) & 31) + rt := int((p.To.Reg) & 31) + Q := 0 + size := 0 + switch af { + case ARNG_8B: + Q = 0 + size = 0 + case ARNG_16B: + Q = 1 + size = 0 + case ARNG_4H: + Q = 0 + size = 1 + case ARNG_8H: + Q = 1 + size = 1 + case ARNG_4S: + Q = 1 + size = 2 + default: + c.ctxt.Diag("invalid arrangement: %v\n", p) + } + o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 86: /* vmovi $imm8, Vd.*/ + at := int((p.To.Reg >> 5) & 15) + r := int(p.From.Offset) + if r > 255 || r < 0 { + c.ctxt.Diag("immediate constant out of range: %v\n", p) + } + rt := int((p.To.Reg) & 31) + Q := 0 + switch at { + case ARNG_8B: + Q = 0 + case ARNG_16B: + Q = 1 + default: + c.ctxt.Diag("invalid arrangement: %v\n", p) + } + o1 = 0xf<<24 | 0xe<<12 | 1<<10 + o1 |= (uint32(Q&1) << 30) | (uint32((r>>5)&7) << 16) | (uint32(r&0x1f) << 5) | uint32(rt&31) + + case 87: /* stp (r,r), addr(SB) -> adrp + add + stp */ + o1 = ADR(1, 0, REGTMP) + o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = objabi.R_ADDRARM64 + o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0) + + case 88: /* ldp addr(SB), (r,r) -> adrp + add + ldp */ + o1 = ADR(1, 0, REGTMP) + o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31 + rel := obj.Addrel(c.cursym) + rel.Off = int32(c.pc) + rel.Siz = 8 + rel.Sym = p.From.Sym + rel.Add = p.From.Offset + rel.Type = objabi.R_ADDRARM64 + o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1) + + case 89: /* vadd/vsub Vm, Vn, Vd */ + switch p.As { + case AVADD: + o1 = 5<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10 + + case AVSUB: + o1 = 7<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10 + + default: + c.ctxt.Diag("bad opcode: %v\n", p) + break + } + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + // This is supposed to be something that stops execution. + // It's not supposed to be reached, ever, but if it is, we'd + // like to be able to tell how we got there. Assemble as + // 0xbea71700 which is guaranteed to raise undefined instruction + // exception. + case 90: + o1 = 0xbea71700 + + case 91: /* prfm imm(Rn), */ + imm := uint32(p.From.Offset) + r := p.From.Reg + v := uint32(0xff) + if p.To.Type == obj.TYPE_CONST { + v = uint32(p.To.Offset) + if v > 31 { + c.ctxt.Diag("illegal prefetch operation\n%v", p) + } + } else { + for i := 0; i < len(prfopfield); i++ { + if prfopfield[i].reg == p.To.Reg { + v = prfopfield[i].enc + break + } + } + if v == 0xff { + c.ctxt.Diag("illegal prefetch operation:\n%v", p) + } + } + + o1 = c.opldrpp(p, p.As) + o1 |= (uint32(r&31) << 5) | (uint32((imm>>3)&0xfff) << 10) | (uint32(v & 31)) + + case 92: /* vmov Vn.[index], Vd.[index] */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + imm4 := 0 + imm5 := 0 + o1 = 3<<29 | 7<<25 | 1<<10 + index1 := int(p.To.Index) + index2 := int(p.From.Index) + if ((p.To.Reg >> 5) & 15) != ((p.From.Reg >> 5) & 15) { + c.ctxt.Diag("operand mismatch: %v", p) + } + switch (p.To.Reg >> 5) & 15 { + case ARNG_B: + c.checkindex(p, index1, 15) + c.checkindex(p, index2, 15) + imm5 |= 1 + imm5 |= index1 << 1 + imm4 |= index2 + case ARNG_H: + c.checkindex(p, index1, 7) + c.checkindex(p, index2, 7) + imm5 |= 2 + imm5 |= index1 << 2 + imm4 |= index2 << 1 + case ARNG_S: + c.checkindex(p, index1, 3) + c.checkindex(p, index2, 3) + imm5 |= 4 + imm5 |= index1 << 3 + imm4 |= index2 << 2 + case ARNG_D: + c.checkindex(p, index1, 1) + c.checkindex(p, index2, 1) + imm5 |= 8 + imm5 |= index1 << 4 + imm4 |= index2 << 3 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + o1 |= (uint32(imm5&0x1f) << 16) | (uint32(imm4&0xf) << 11) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 93: /* vpmull{2} Vm., Vn., Vd */ + af := int((p.From.Reg >> 5) & 15) + at := int((p.To.Reg >> 5) & 15) + a := int((p.Reg >> 5) & 15) + + var Q, size uint32 + if p.As == AVPMULL { + Q = 0 + } else { + Q = 1 + } + + var fArng int + switch at { + case ARNG_8H: + if Q == 0 { + fArng = ARNG_8B + } else { + fArng = ARNG_16B + } + size = 0 + case ARNG_1Q: + if Q == 0 { + fArng = ARNG_1D + } else { + fArng = ARNG_2D + } + size = 3 + default: + c.ctxt.Diag("invalid arrangement on Vd.: %v", p) + } + + if af != a || af != fArng { + c.ctxt.Diag("invalid arrangement: %v", p) + } + + o1 = c.oprrr(p, p.As) + rf := int((p.From.Reg) & 31) + rt := int((p.To.Reg) & 31) + r := int((p.Reg) & 31) + + o1 |= ((Q & 1) << 30) | ((size & 3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 94: /* vext $imm4, Vm., Vn., Vd. */ + af := int(((p.GetFrom3().Reg) >> 5) & 15) + at := int((p.To.Reg >> 5) & 15) + a := int((p.Reg >> 5) & 15) + index := int(p.From.Offset) + + if af != a || af != at { + c.ctxt.Diag("invalid arrangement: %v", p) + break + } + + var Q uint32 + var b int + if af == ARNG_8B { + Q = 0 + b = 7 + } else if af == ARNG_16B { + Q = 1 + b = 15 + } else { + c.ctxt.Diag("invalid arrangement, should be B8 or B16: %v", p) + break + } + + if index < 0 || index > b { + c.ctxt.Diag("illegal offset: %v", p) + } + + o1 = c.opirr(p, p.As) + rf := int((p.GetFrom3().Reg) & 31) + rt := int((p.To.Reg) & 31) + r := int((p.Reg) & 31) + + o1 |= ((Q & 1) << 30) | (uint32(r&31) << 16) | (uint32(index&15) << 11) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 95: /* vushr $shift, Vn., Vd. */ + at := int((p.To.Reg >> 5) & 15) + af := int((p.Reg >> 5) & 15) + shift := int(p.From.Offset) + + if af != at { + c.ctxt.Diag("invalid arrangement on op Vn., Vd.: %v", p) + } + + var Q uint32 + var imax, esize int + + switch af { + case ARNG_8B, ARNG_4H, ARNG_2S: + Q = 0 + case ARNG_16B, ARNG_8H, ARNG_4S, ARNG_2D: + Q = 1 + default: + c.ctxt.Diag("invalid arrangement on op Vn., Vd.: %v", p) + } + + switch af { + case ARNG_8B, ARNG_16B: + imax = 15 + esize = 8 + case ARNG_4H, ARNG_8H: + imax = 31 + esize = 16 + case ARNG_2S, ARNG_4S: + imax = 63 + esize = 32 + case ARNG_2D: + imax = 127 + esize = 64 + } + + imm := 0 + + switch p.As { + case AVUSHR, AVSRI: + imm = esize*2 - shift + if imm < esize || imm > imax { + c.ctxt.Diag("shift out of range: %v", p) + } + case AVSHL: + imm = esize + shift + if imm > imax { + c.ctxt.Diag("shift out of range: %v", p) + } + default: + c.ctxt.Diag("invalid instruction %v\n", p) + } + + o1 = c.opirr(p, p.As) + rt := int((p.To.Reg) & 31) + rf := int((p.Reg) & 31) + + o1 |= ((Q & 1) << 30) | (uint32(imm&127) << 16) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 96: /* vst1 Vt1.[index], offset(Rn) */ + af := int((p.From.Reg >> 5) & 15) + rt := int((p.From.Reg) & 31) + rf := int((p.To.Reg) & 31) + r := int(p.To.Index & 31) + index := int(p.From.Index) + offset := int32(c.regoff(&p.To)) + + if o.scond == C_XPOST { + if (p.To.Index != 0) && (offset != 0) { + c.ctxt.Diag("invalid offset: %v", p) + } + if p.To.Index == 0 && offset == 0 { + c.ctxt.Diag("invalid offset: %v", p) + } + } + + if offset != 0 { + r = 31 + } + + var Q, S, size int + var opcode uint32 + switch af { + case ARNG_B: + c.checkindex(p, index, 15) + if o.scond == C_XPOST && offset != 0 && offset != 1 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 3 + S = (index >> 2) & 1 + size = index & 3 + opcode = 0 + case ARNG_H: + c.checkindex(p, index, 7) + if o.scond == C_XPOST && offset != 0 && offset != 2 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 2 + S = (index >> 1) & 1 + size = (index & 1) << 1 + opcode = 2 + case ARNG_S: + c.checkindex(p, index, 3) + if o.scond == C_XPOST && offset != 0 && offset != 4 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 1 + S = index & 1 + size = 0 + opcode = 4 + case ARNG_D: + c.checkindex(p, index, 1) + if o.scond == C_XPOST && offset != 0 && offset != 8 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index + S = 0 + size = 1 + opcode = 4 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + + if o.scond == C_XPOST { + o1 |= 27 << 23 + } else { + o1 |= 26 << 23 + } + + o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 97: /* vld1 offset(Rn), vt.[index] */ + at := int((p.To.Reg >> 5) & 15) + rt := int((p.To.Reg) & 31) + rf := int((p.From.Reg) & 31) + r := int(p.From.Index & 31) + index := int(p.To.Index) + offset := int32(c.regoff(&p.From)) + + if o.scond == C_XPOST { + if (p.From.Index != 0) && (offset != 0) { + c.ctxt.Diag("invalid offset: %v", p) + } + if p.From.Index == 0 && offset == 0 { + c.ctxt.Diag("invalid offset: %v", p) + } + } + + if offset != 0 { + r = 31 + } + + Q := 0 + S := 0 + size := 0 + var opcode uint32 + switch at { + case ARNG_B: + c.checkindex(p, index, 15) + if o.scond == C_XPOST && offset != 0 && offset != 1 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 3 + S = (index >> 2) & 1 + size = index & 3 + opcode = 0 + case ARNG_H: + c.checkindex(p, index, 7) + if o.scond == C_XPOST && offset != 0 && offset != 2 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 2 + S = (index >> 1) & 1 + size = (index & 1) << 1 + opcode = 2 + case ARNG_S: + c.checkindex(p, index, 3) + if o.scond == C_XPOST && offset != 0 && offset != 4 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index >> 1 + S = index & 1 + size = 0 + opcode = 4 + case ARNG_D: + c.checkindex(p, index, 1) + if o.scond == C_XPOST && offset != 0 && offset != 8 { + c.ctxt.Diag("invalid offset: %v", p) + } + Q = index + S = 0 + size = 1 + opcode = 4 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + + if o.scond == C_XPOST { + o1 |= 110 << 21 + } else { + o1 |= 106 << 21 + } + + o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 98: /* MOVD (Rn)(Rm.SXTW[<, [Vt1., Vt2., ...], Vd. */ + af := int((p.From.Reg >> 5) & 15) + at := int((p.To.Reg >> 5) & 15) + if af != at { + c.ctxt.Diag("invalid arrangement: %v\n", p) + } + var q, len uint32 + switch af { + case ARNG_8B: + q = 0 + case ARNG_16B: + q = 1 + default: + c.ctxt.Diag("invalid arrangement: %v", p) + } + rf := int(p.From.Reg) + rt := int(p.To.Reg) + offset := int(p.GetFrom3().Offset) + opcode := (offset >> 12) & 15 + switch opcode { + case 0x7: + len = 0 // one register + case 0xa: + len = 1 // two register + case 0x6: + len = 2 // three registers + case 0x2: + len = 3 // four registers + default: + c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p) + } + o1 = q<<30 | 0xe<<24 | len<<13 + o1 |= (uint32(rf&31) << 16) | uint32(offset&31)<<5 | uint32(rt&31) + + case 101: // FOMVQ/FMOVD $vcon, Vd -> load from constant pool. + o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg)) + + case 102: /* vushll, vushll2, vuxtl, vuxtl2 */ + o1 = c.opirr(p, p.As) + rf := p.Reg + af := uint8((p.Reg >> 5) & 15) + at := uint8((p.To.Reg >> 5) & 15) + shift := int(p.From.Offset) + if p.As == AVUXTL || p.As == AVUXTL2 { + rf = p.From.Reg + af = uint8((p.From.Reg >> 5) & 15) + shift = 0 + } + + pack := func(q, x, y uint8) uint32 { + return uint32(q)<<16 | uint32(x)<<8 | uint32(y) + } + + var Q uint8 = uint8(o1>>30) & 1 + var immh, width uint8 + switch pack(Q, af, at) { + case pack(0, ARNG_8B, ARNG_8H): + immh, width = 1, 8 + case pack(1, ARNG_16B, ARNG_8H): + immh, width = 1, 8 + case pack(0, ARNG_4H, ARNG_4S): + immh, width = 2, 16 + case pack(1, ARNG_8H, ARNG_4S): + immh, width = 2, 16 + case pack(0, ARNG_2S, ARNG_2D): + immh, width = 4, 32 + case pack(1, ARNG_4S, ARNG_2D): + immh, width = 4, 32 + default: + c.ctxt.Diag("operand mismatch: %v\n", p) + } + if !(0 <= shift && shift <= int(width-1)) { + c.ctxt.Diag("shift amount out of range: %v\n", p) + } + o1 |= uint32(immh)<<19 | uint32(shift)<<16 | uint32(rf&31)<<5 | uint32(p.To.Reg&31) + } + out[0] = o1 + out[1] = o2 + out[2] = o3 + out[3] = o4 + out[4] = o5 +} + +/* + * basic Rm op Rn -> Rd (using shifted register with 0) + * also op Rn -> Rt + * also Rm*Rn op Ra -> Rd + * also Vm op Vn -> Vd + */ +func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 { + switch a { + case AADC: + return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case AADCW: + return S32 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case AADCS: + return S64 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case AADCSW: + return S32 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case ANGC, ASBC: + return S64 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case ANGCS, ASBCS: + return S64 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case ANGCW, ASBCW: + return S32 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case ANGCSW, ASBCSW: + return S32 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case AADD: + return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case AADDW: + return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMN, AADDS: + return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMNW, AADDSW: + return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMP, ASUBS: + return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMPW, ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case AAND: + return S64 | 0<<29 | 0xA<<24 + + case AANDW: + return S32 | 0<<29 | 0xA<<24 + + case AMOVD, AORR: + return S64 | 1<<29 | 0xA<<24 + + // case AMOVW: + case AMOVWU, AORRW: + return S32 | 1<<29 | 0xA<<24 + + case AEOR: + return S64 | 2<<29 | 0xA<<24 + + case AEORW: + return S32 | 2<<29 | 0xA<<24 + + case AANDS, ATST: + return S64 | 3<<29 | 0xA<<24 + + case AANDSW, ATSTW: + return S32 | 3<<29 | 0xA<<24 + + case ABIC: + return S64 | 0<<29 | 0xA<<24 | 1<<21 + + case ABICW: + return S32 | 0<<29 | 0xA<<24 | 1<<21 + + case ABICS: + return S64 | 3<<29 | 0xA<<24 | 1<<21 + + case ABICSW: + return S32 | 3<<29 | 0xA<<24 | 1<<21 + + case AEON: + return S64 | 2<<29 | 0xA<<24 | 1<<21 + + case AEONW: + return S32 | 2<<29 | 0xA<<24 | 1<<21 + + case AMVN, AORN: + return S64 | 1<<29 | 0xA<<24 | 1<<21 + + case AMVNW, AORNW: + return S32 | 1<<29 | 0xA<<24 | 1<<21 + + case AASR: + return S64 | OPDP2(10) /* also ASRV */ + + case AASRW: + return S32 | OPDP2(10) + + case ALSL: + return S64 | OPDP2(8) + + case ALSLW: + return S32 | OPDP2(8) + + case ALSR: + return S64 | OPDP2(9) + + case ALSRW: + return S32 | OPDP2(9) + + case AROR: + return S64 | OPDP2(11) + + case ARORW: + return S32 | OPDP2(11) + + case ACCMN: + return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* cond<<12 | nzcv<<0 */ + + case ACCMNW: + return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 + + case ACCMP: + return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMPW: + return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 + + case ACRC32B: + return S32 | OPDP2(16) + + case ACRC32H: + return S32 | OPDP2(17) + + case ACRC32W: + return S32 | OPDP2(18) + + case ACRC32X: + return S64 | OPDP2(19) + + case ACRC32CB: + return S32 | OPDP2(20) + + case ACRC32CH: + return S32 | OPDP2(21) + + case ACRC32CW: + return S32 | OPDP2(22) + + case ACRC32CX: + return S64 | OPDP2(23) + + case ACSEL: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSELW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSET: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACSETW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACSETM: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSETMW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACINC, ACSINC: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACINCW, ACSINCW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACINV, ACSINV: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACINVW, ACSINVW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACNEG, ACSNEG: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACNEGW, ACSNEGW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case AMUL, AMADD: + return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15 + + case AMULW, AMADDW: + return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15 + + case AMNEG, AMSUB: + return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15 + + case AMNEGW, AMSUBW: + return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15 + + case AMRS: + return SYSOP(1, 2, 0, 0, 0, 0, 0) + + case AMSR: + return SYSOP(0, 2, 0, 0, 0, 0, 0) + + case ANEG: + return S64 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21 + + case ANEGW: + return S32 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21 + + case ANEGS: + return S64 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21 + + case ANEGSW: + return S32 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21 + + case AREM, ASDIV: + return S64 | OPDP2(3) + + case AREMW, ASDIVW: + return S32 | OPDP2(3) + + case ASMULL, ASMADDL: + return OPDP3(1, 0, 1, 0) + + case ASMNEGL, ASMSUBL: + return OPDP3(1, 0, 1, 1) + + case ASMULH: + return OPDP3(1, 0, 2, 0) + + case AUMULL, AUMADDL: + return OPDP3(1, 0, 5, 0) + + case AUMNEGL, AUMSUBL: + return OPDP3(1, 0, 5, 1) + + case AUMULH: + return OPDP3(1, 0, 6, 0) + + case AUREM, AUDIV: + return S64 | OPDP2(2) + + case AUREMW, AUDIVW: + return S32 | OPDP2(2) + + case AAESE: + return 0x4E<<24 | 2<<20 | 8<<16 | 4<<12 | 2<<10 + + case AAESD: + return 0x4E<<24 | 2<<20 | 8<<16 | 5<<12 | 2<<10 + + case AAESMC: + return 0x4E<<24 | 2<<20 | 8<<16 | 6<<12 | 2<<10 + + case AAESIMC: + return 0x4E<<24 | 2<<20 | 8<<16 | 7<<12 | 2<<10 + + case ASHA1C: + return 0x5E<<24 | 0<<12 + + case ASHA1P: + return 0x5E<<24 | 1<<12 + + case ASHA1M: + return 0x5E<<24 | 2<<12 + + case ASHA1SU0: + return 0x5E<<24 | 3<<12 + + case ASHA256H: + return 0x5E<<24 | 4<<12 + + case ASHA256H2: + return 0x5E<<24 | 5<<12 + + case ASHA256SU1: + return 0x5E<<24 | 6<<12 + + case ASHA1H: + return 0x5E<<24 | 2<<20 | 8<<16 | 0<<12 | 2<<10 + + case ASHA1SU1: + return 0x5E<<24 | 2<<20 | 8<<16 | 1<<12 | 2<<10 + + case ASHA256SU0: + return 0x5E<<24 | 2<<20 | 8<<16 | 2<<12 | 2<<10 + + case ASHA512H: + return 0xCE<<24 | 3<<21 | 8<<12 + + case ASHA512H2: + return 0xCE<<24 | 3<<21 | 8<<12 | 4<<8 + + case ASHA512SU1: + return 0xCE<<24 | 3<<21 | 8<<12 | 8<<8 + + case ASHA512SU0: + return 0xCE<<24 | 3<<22 | 8<<12 + + case AFCVTZSD: + return FPCVTI(1, 0, 1, 3, 0) + + case AFCVTZSDW: + return FPCVTI(0, 0, 1, 3, 0) + + case AFCVTZSS: + return FPCVTI(1, 0, 0, 3, 0) + + case AFCVTZSSW: + return FPCVTI(0, 0, 0, 3, 0) + + case AFCVTZUD: + return FPCVTI(1, 0, 1, 3, 1) + + case AFCVTZUDW: + return FPCVTI(0, 0, 1, 3, 1) + + case AFCVTZUS: + return FPCVTI(1, 0, 0, 3, 1) + + case AFCVTZUSW: + return FPCVTI(0, 0, 0, 3, 1) + + case ASCVTFD: + return FPCVTI(1, 0, 1, 0, 2) + + case ASCVTFS: + return FPCVTI(1, 0, 0, 0, 2) + + case ASCVTFWD: + return FPCVTI(0, 0, 1, 0, 2) + + case ASCVTFWS: + return FPCVTI(0, 0, 0, 0, 2) + + case AUCVTFD: + return FPCVTI(1, 0, 1, 0, 3) + + case AUCVTFS: + return FPCVTI(1, 0, 0, 0, 3) + + case AUCVTFWD: + return FPCVTI(0, 0, 1, 0, 3) + + case AUCVTFWS: + return FPCVTI(0, 0, 0, 0, 3) + + case AFADDS: + return FPOP2S(0, 0, 0, 2) + + case AFADDD: + return FPOP2S(0, 0, 1, 2) + + case AFSUBS: + return FPOP2S(0, 0, 0, 3) + + case AFSUBD: + return FPOP2S(0, 0, 1, 3) + + case AFMADDD: + return FPOP3S(0, 0, 1, 0, 0) + + case AFMADDS: + return FPOP3S(0, 0, 0, 0, 0) + + case AFMSUBD: + return FPOP3S(0, 0, 1, 0, 1) + + case AFMSUBS: + return FPOP3S(0, 0, 0, 0, 1) + + case AFNMADDD: + return FPOP3S(0, 0, 1, 1, 0) + + case AFNMADDS: + return FPOP3S(0, 0, 0, 1, 0) + + case AFNMSUBD: + return FPOP3S(0, 0, 1, 1, 1) + + case AFNMSUBS: + return FPOP3S(0, 0, 0, 1, 1) + + case AFMULS: + return FPOP2S(0, 0, 0, 0) + + case AFMULD: + return FPOP2S(0, 0, 1, 0) + + case AFDIVS: + return FPOP2S(0, 0, 0, 1) + + case AFDIVD: + return FPOP2S(0, 0, 1, 1) + + case AFMAXS: + return FPOP2S(0, 0, 0, 4) + + case AFMINS: + return FPOP2S(0, 0, 0, 5) + + case AFMAXD: + return FPOP2S(0, 0, 1, 4) + + case AFMIND: + return FPOP2S(0, 0, 1, 5) + + case AFMAXNMS: + return FPOP2S(0, 0, 0, 6) + + case AFMAXNMD: + return FPOP2S(0, 0, 1, 6) + + case AFMINNMS: + return FPOP2S(0, 0, 0, 7) + + case AFMINNMD: + return FPOP2S(0, 0, 1, 7) + + case AFNMULS: + return FPOP2S(0, 0, 0, 8) + + case AFNMULD: + return FPOP2S(0, 0, 1, 8) + + case AFCMPS: + return FPCMP(0, 0, 0, 0, 0) + + case AFCMPD: + return FPCMP(0, 0, 1, 0, 0) + + case AFCMPES: + return FPCMP(0, 0, 0, 0, 16) + + case AFCMPED: + return FPCMP(0, 0, 1, 0, 16) + + case AFCCMPS: + return FPCCMP(0, 0, 0, 0) + + case AFCCMPD: + return FPCCMP(0, 0, 1, 0) + + case AFCCMPES: + return FPCCMP(0, 0, 0, 1) + + case AFCCMPED: + return FPCCMP(0, 0, 1, 1) + + case AFCSELS: + return 0x1E<<24 | 0<<22 | 1<<21 | 3<<10 + + case AFCSELD: + return 0x1E<<24 | 1<<22 | 1<<21 | 3<<10 + + case AFMOVS: + return FPOP1S(0, 0, 0, 0) + + case AFABSS: + return FPOP1S(0, 0, 0, 1) + + case AFNEGS: + return FPOP1S(0, 0, 0, 2) + + case AFSQRTS: + return FPOP1S(0, 0, 0, 3) + + case AFCVTSD: + return FPOP1S(0, 0, 0, 5) + + case AFCVTSH: + return FPOP1S(0, 0, 0, 7) + + case AFRINTNS: + return FPOP1S(0, 0, 0, 8) + + case AFRINTPS: + return FPOP1S(0, 0, 0, 9) + + case AFRINTMS: + return FPOP1S(0, 0, 0, 10) + + case AFRINTZS: + return FPOP1S(0, 0, 0, 11) + + case AFRINTAS: + return FPOP1S(0, 0, 0, 12) + + case AFRINTXS: + return FPOP1S(0, 0, 0, 14) + + case AFRINTIS: + return FPOP1S(0, 0, 0, 15) + + case AFMOVD: + return FPOP1S(0, 0, 1, 0) + + case AFABSD: + return FPOP1S(0, 0, 1, 1) + + case AFNEGD: + return FPOP1S(0, 0, 1, 2) + + case AFSQRTD: + return FPOP1S(0, 0, 1, 3) + + case AFCVTDS: + return FPOP1S(0, 0, 1, 4) + + case AFCVTDH: + return FPOP1S(0, 0, 1, 7) + + case AFRINTND: + return FPOP1S(0, 0, 1, 8) + + case AFRINTPD: + return FPOP1S(0, 0, 1, 9) + + case AFRINTMD: + return FPOP1S(0, 0, 1, 10) + + case AFRINTZD: + return FPOP1S(0, 0, 1, 11) + + case AFRINTAD: + return FPOP1S(0, 0, 1, 12) + + case AFRINTXD: + return FPOP1S(0, 0, 1, 14) + + case AFRINTID: + return FPOP1S(0, 0, 1, 15) + + case AFCVTHS: + return FPOP1S(0, 0, 3, 4) + + case AFCVTHD: + return FPOP1S(0, 0, 3, 5) + + case AVADD: + return 7<<25 | 1<<21 | 1<<15 | 1<<10 + + case AVSUB: + return 0x17<<25 | 1<<21 | 1<<15 | 1<<10 + + case AVADDP: + return 7<<25 | 1<<21 | 1<<15 | 15<<10 + + case AVAND: + return 7<<25 | 1<<21 | 7<<10 + + case AVCMEQ: + return 1<<29 | 0x71<<21 | 0x23<<10 + + case AVCNT: + return 0xE<<24 | 0x10<<17 | 5<<12 | 2<<10 + + case AVZIP1: + return 0xE<<24 | 3<<12 | 2<<10 + + case AVZIP2: + return 0xE<<24 | 1<<14 | 3<<12 | 2<<10 + + case AVEOR: + return 1<<29 | 0x71<<21 | 7<<10 + + case AVORR: + return 7<<25 | 5<<21 | 7<<10 + + case AVREV16: + return 3<<26 | 2<<24 | 1<<21 | 3<<11 + + case AVREV32: + return 11<<26 | 2<<24 | 1<<21 | 1<<11 + + case AVREV64: + return 3<<26 | 2<<24 | 1<<21 | 1<<11 + + case AVMOV: + return 7<<25 | 5<<21 | 7<<10 + + case AVADDV: + return 7<<25 | 3<<20 | 3<<15 | 7<<11 + + case AVUADDLV: + return 1<<29 | 7<<25 | 3<<20 | 7<<11 + + case AVFMLA: + return 7<<25 | 0<<23 | 1<<21 | 3<<14 | 3<<10 + + case AVFMLS: + return 7<<25 | 1<<23 | 1<<21 | 3<<14 | 3<<10 + + case AVPMULL, AVPMULL2: + return 0xE<<24 | 1<<21 | 0x38<<10 + + case AVRBIT: + return 0x2E<<24 | 1<<22 | 0x10<<17 | 5<<12 | 2<<10 + + case AVLD1, AVLD2, AVLD3, AVLD4: + return 3<<26 | 1<<22 + + case AVLD1R, AVLD3R: + return 0xD<<24 | 1<<22 + + case AVLD2R, AVLD4R: + return 0xD<<24 | 3<<21 + + case AVBIF: + return 1<<29 | 7<<25 | 7<<21 | 7<<10 + + case AVBIT: + return 1<<29 | 0x75<<21 | 7<<10 + + case AVBSL: + return 1<<29 | 0x73<<21 | 7<<10 + + case AVCMTST: + return 0xE<<24 | 1<<21 | 0x23<<10 + + case AVUZP1: + return 7<<25 | 3<<11 + + case AVUZP2: + return 7<<25 | 1<<14 | 3<<11 + } + + c.ctxt.Diag("%v: bad rrr %d %v", p, a, a) + return 0 +} + +/* + * imm -> Rd + * imm op Rn -> Rd + */ +func (c *ctxt7) opirr(p *obj.Prog, a obj.As) uint32 { + switch a { + /* op $addcon, Rn, Rd */ + case AMOVD, AADD: + return S64 | 0<<30 | 0<<29 | 0x11<<24 + + case ACMN, AADDS: + return S64 | 0<<30 | 1<<29 | 0x11<<24 + + case AMOVW, AADDW: + return S32 | 0<<30 | 0<<29 | 0x11<<24 + + case ACMNW, AADDSW: + return S32 | 0<<30 | 1<<29 | 0x11<<24 + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x11<<24 + + case ACMP, ASUBS: + return S64 | 1<<30 | 1<<29 | 0x11<<24 + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x11<<24 + + case ACMPW, ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x11<<24 + + /* op $imm(SB), Rd; op label, Rd */ + case AADR: + return 0<<31 | 0x10<<24 + + case AADRP: + return 1<<31 | 0x10<<24 + + /* op $bimm, Rn, Rd */ + case AAND, ABIC: + return S64 | 0<<29 | 0x24<<23 + + case AANDW, ABICW: + return S32 | 0<<29 | 0x24<<23 | 0<<22 + + case AORR, AORN: + return S64 | 1<<29 | 0x24<<23 + + case AORRW, AORNW: + return S32 | 1<<29 | 0x24<<23 | 0<<22 + + case AEOR, AEON: + return S64 | 2<<29 | 0x24<<23 + + case AEORW, AEONW: + return S32 | 2<<29 | 0x24<<23 | 0<<22 + + case AANDS, ABICS, ATST: + return S64 | 3<<29 | 0x24<<23 + + case AANDSW, ABICSW, ATSTW: + return S32 | 3<<29 | 0x24<<23 | 0<<22 + + case AASR: + return S64 | 0<<29 | 0x26<<23 /* alias of SBFM */ + + case AASRW: + return S32 | 0<<29 | 0x26<<23 | 0<<22 + + /* op $width, $lsb, Rn, Rd */ + case ABFI: + return S64 | 2<<29 | 0x26<<23 | 1<<22 + /* alias of BFM */ + + case ABFIW: + return S32 | 2<<29 | 0x26<<23 | 0<<22 + + /* op $imms, $immr, Rn, Rd */ + case ABFM: + return S64 | 1<<29 | 0x26<<23 | 1<<22 + + case ABFMW: + return S32 | 1<<29 | 0x26<<23 | 0<<22 + + case ASBFM: + return S64 | 0<<29 | 0x26<<23 | 1<<22 + + case ASBFMW: + return S32 | 0<<29 | 0x26<<23 | 0<<22 + + case AUBFM: + return S64 | 2<<29 | 0x26<<23 | 1<<22 + + case AUBFMW: + return S32 | 2<<29 | 0x26<<23 | 0<<22 + + case ABFXIL: + return S64 | 1<<29 | 0x26<<23 | 1<<22 /* alias of BFM */ + + case ABFXILW: + return S32 | 1<<29 | 0x26<<23 | 0<<22 + + case AEXTR: + return S64 | 0<<29 | 0x27<<23 | 1<<22 | 0<<21 + + case AEXTRW: + return S32 | 0<<29 | 0x27<<23 | 0<<22 | 0<<21 + + case ACBNZ: + return S64 | 0x1A<<25 | 1<<24 + + case ACBNZW: + return S32 | 0x1A<<25 | 1<<24 + + case ACBZ: + return S64 | 0x1A<<25 | 0<<24 + + case ACBZW: + return S32 | 0x1A<<25 | 0<<24 + + case ACCMN: + return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMNW: + return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 + + case ACCMP: + return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMPW: + return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 + + case AMOVK: + return S64 | 3<<29 | 0x25<<23 + + case AMOVKW: + return S32 | 3<<29 | 0x25<<23 + + case AMOVN: + return S64 | 0<<29 | 0x25<<23 + + case AMOVNW: + return S32 | 0<<29 | 0x25<<23 + + case AMOVZ: + return S64 | 2<<29 | 0x25<<23 + + case AMOVZW: + return S32 | 2<<29 | 0x25<<23 + + case AMSR: + return SYSOP(0, 0, 0, 4, 0, 0, 0x1F) /* MSR (immediate) */ + + case AAT, + ADC, + AIC, + ATLBI, + ASYS: + return SYSOP(0, 1, 0, 0, 0, 0, 0) + + case ASYSL: + return SYSOP(1, 1, 0, 0, 0, 0, 0) + + case ATBZ: + return 0x36 << 24 + + case ATBNZ: + return 0x37 << 24 + + case ADSB: + return SYSOP(0, 0, 3, 3, 0, 4, 0x1F) + + case ADMB: + return SYSOP(0, 0, 3, 3, 0, 5, 0x1F) + + case AISB: + return SYSOP(0, 0, 3, 3, 0, 6, 0x1F) + + case AHINT: + return SYSOP(0, 0, 3, 2, 0, 0, 0x1F) + + case AVEXT: + return 0x2E<<24 | 0<<23 | 0<<21 | 0<<15 + + case AVUSHR: + return 0x5E<<23 | 1<<10 + + case AVSHL: + return 0x1E<<23 | 21<<10 + + case AVSRI: + return 0x5E<<23 | 17<<10 + + case AVUSHLL, AVUXTL: + return 1<<29 | 15<<24 | 0x29<<10 + + case AVUSHLL2, AVUXTL2: + return 3<<29 | 15<<24 | 0x29<<10 + } + + c.ctxt.Diag("%v: bad irr %v", p, a) + return 0 +} + +func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 { + switch a { + case ACLS: + return S64 | OPBIT(5) + + case ACLSW: + return S32 | OPBIT(5) + + case ACLZ: + return S64 | OPBIT(4) + + case ACLZW: + return S32 | OPBIT(4) + + case ARBIT: + return S64 | OPBIT(0) + + case ARBITW: + return S32 | OPBIT(0) + + case AREV: + return S64 | OPBIT(3) + + case AREVW: + return S32 | OPBIT(2) + + case AREV16: + return S64 | OPBIT(1) + + case AREV16W: + return S32 | OPBIT(1) + + case AREV32: + return S64 | OPBIT(2) + + default: + c.ctxt.Diag("bad bit op\n%v", p) + return 0 + } +} + +/* + * add/subtract sign or zero-extended register + */ +func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 { + extension := uint32(0) + if !extend { + switch a { + case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS: + extension = LSL0_64 + + case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW: + extension = LSL0_32 + } + } + + switch a { + case AADD: + return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case AADDW: + return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ACMN, AADDS: + return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ACMNW, AADDSW: + return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ACMP, ASUBS: + return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + + case ACMPW, ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension + } + + c.ctxt.Diag("bad opxrrr %v\n%v", a, p) + return 0 +} + +func (c *ctxt7) opimm(p *obj.Prog, a obj.As) uint32 { + switch a { + case ASVC: + return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */ + + case AHVC: + return 0xD4<<24 | 0<<21 | 2 + + case ASMC: + return 0xD4<<24 | 0<<21 | 3 + + case ABRK: + return 0xD4<<24 | 1<<21 | 0 + + case AHLT: + return 0xD4<<24 | 2<<21 | 0 + + case ADCPS1: + return 0xD4<<24 | 5<<21 | 1 + + case ADCPS2: + return 0xD4<<24 | 5<<21 | 2 + + case ADCPS3: + return 0xD4<<24 | 5<<21 | 3 + + case ACLREX: + return SYSOP(0, 0, 3, 3, 0, 2, 0x1F) + } + + c.ctxt.Diag("%v: bad imm %v", p, a) + return 0 +} + +func (c *ctxt7) brdist(p *obj.Prog, preshift int, flen int, shift int) int64 { + v := int64(0) + t := int64(0) + q := p.To.Target() + if q == nil { + // TODO: don't use brdist for this case, as it isn't a branch. + // (Calls from omovlit, and maybe adr/adrp opcodes as well.) + q = p.Pool + } + if q != nil { + v = (q.Pc >> uint(preshift)) - (c.pc >> uint(preshift)) + if (v & ((1 << uint(shift)) - 1)) != 0 { + c.ctxt.Diag("misaligned label\n%v", p) + } + v >>= uint(shift) + t = int64(1) << uint(flen-1) + if v < -t || v >= t { + c.ctxt.Diag("branch too far %#x vs %#x [%p]\n%v\n%v", v, t, c.blitrl, p, q) + panic("branch too far") + } + } + + return v & ((t << 1) - 1) +} + +/* + * pc-relative branches + */ +func (c *ctxt7) opbra(p *obj.Prog, a obj.As) uint32 { + switch a { + case ABEQ: + return OPBcc(0x0) + + case ABNE: + return OPBcc(0x1) + + case ABCS: + return OPBcc(0x2) + + case ABHS: + return OPBcc(0x2) + + case ABCC: + return OPBcc(0x3) + + case ABLO: + return OPBcc(0x3) + + case ABMI: + return OPBcc(0x4) + + case ABPL: + return OPBcc(0x5) + + case ABVS: + return OPBcc(0x6) + + case ABVC: + return OPBcc(0x7) + + case ABHI: + return OPBcc(0x8) + + case ABLS: + return OPBcc(0x9) + + case ABGE: + return OPBcc(0xa) + + case ABLT: + return OPBcc(0xb) + + case ABGT: + return OPBcc(0xc) + + case ABLE: + return OPBcc(0xd) /* imm19<<5 | cond */ + + case AB: + return 0<<31 | 5<<26 /* imm26 */ + + case obj.ADUFFZERO, obj.ADUFFCOPY, ABL: + return 1<<31 | 5<<26 + } + + c.ctxt.Diag("%v: bad bra %v", p, a) + return 0 +} + +func (c *ctxt7) opbrr(p *obj.Prog, a obj.As) uint32 { + switch a { + case ABL: + return OPBLR(1) /* BLR */ + + case AB: + return OPBLR(0) /* BR */ + + case obj.ARET: + return OPBLR(2) /* RET */ + } + + c.ctxt.Diag("%v: bad brr %v", p, a) + return 0 +} + +func (c *ctxt7) op0(p *obj.Prog, a obj.As) uint32 { + switch a { + case ADRPS: + return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5 + + case AERET: + return 0x6B<<25 | 4<<21 | 0x1F<<16 | 0<<10 | 0x1F<<5 + + case ANOOP: + return SYSHINT(0) + + case AYIELD: + return SYSHINT(1) + + case AWFE: + return SYSHINT(2) + + case AWFI: + return SYSHINT(3) + + case ASEV: + return SYSHINT(4) + + case ASEVL: + return SYSHINT(5) + } + + c.ctxt.Diag("%v: bad op0 %v", p, a) + return 0 +} + +/* + * register offset + */ +func (c *ctxt7) opload(p *obj.Prog, a obj.As) uint32 { + switch a { + case ALDAR: + return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARW: + return LDSTX(2, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARB: + return LDSTX(0, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARH: + return LDSTX(1, 1, 1, 0, 1) | 0x1F<<10 + + case ALDAXP: + return LDSTX(3, 0, 1, 1, 1) + + case ALDAXPW: + return LDSTX(2, 0, 1, 1, 1) + + case ALDAXR: + return LDSTX(3, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRW: + return LDSTX(2, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRB: + return LDSTX(0, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRH: + return LDSTX(1, 0, 1, 0, 1) | 0x1F<<10 + + case ALDXR: + return LDSTX(3, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRB: + return LDSTX(0, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRH: + return LDSTX(1, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRW: + return LDSTX(2, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXP: + return LDSTX(3, 0, 1, 1, 0) + + case ALDXPW: + return LDSTX(2, 0, 1, 1, 0) + + case AMOVNP: + return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + + case AMOVNPW: + return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + } + + c.ctxt.Diag("bad opload %v\n%v", a, p) + return 0 +} + +func (c *ctxt7) opstore(p *obj.Prog, a obj.As) uint32 { + switch a { + case ASTLR: + return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLRB: + return LDSTX(0, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLRH: + return LDSTX(1, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLP: + return LDSTX(3, 0, 0, 1, 1) + + case ASTLPW: + return LDSTX(2, 0, 0, 1, 1) + + case ASTLRW: + return LDSTX(2, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLXP: + return LDSTX(3, 0, 0, 1, 1) + + case ASTLXPW: + return LDSTX(2, 0, 0, 1, 1) + + case ASTLXR: + return LDSTX(3, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRB: + return LDSTX(0, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRH: + return LDSTX(1, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRW: + return LDSTX(2, 0, 0, 0, 1) | 0x1F<<10 + + case ASTXR: + return LDSTX(3, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXRB: + return LDSTX(0, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXRH: + return LDSTX(1, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXP: + return LDSTX(3, 0, 0, 1, 0) + + case ASTXPW: + return LDSTX(2, 0, 0, 1, 0) + + case ASTXRW: + return LDSTX(2, 0, 0, 0, 0) | 0x1F<<10 + + case AMOVNP: + return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + + case AMOVNPW: + return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + } + + c.ctxt.Diag("bad opstore %v\n%v", a, p) + return 0 +} + +/* + * load/store register (unsigned immediate) C3.3.13 + * these produce 64-bit values (when there's an option) + */ +func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 { + if v < 0 || v >= (1<<12) { + c.ctxt.Diag("offset out of range: %d\n%v", v, p) + } + o |= (v & 0xFFF) << 10 + o |= int32(b&31) << 5 + o |= int32(r & 31) + return uint32(o) +} + +func (c *ctxt7) opldr12(p *obj.Prog, a obj.As) uint32 { + switch a { + case AMOVD: + return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */ + + case AMOVW: + return LDSTR12U(2, 0, 2) + + case AMOVWU: + return LDSTR12U(2, 0, 1) + + case AMOVH: + return LDSTR12U(1, 0, 2) + + case AMOVHU: + return LDSTR12U(1, 0, 1) + + case AMOVB: + return LDSTR12U(0, 0, 2) + + case AMOVBU: + return LDSTR12U(0, 0, 1) + + case AFMOVS: + return LDSTR12U(2, 1, 1) + + case AFMOVD: + return LDSTR12U(3, 1, 1) + } + + c.ctxt.Diag("bad opldr12 %v\n%v", a, p) + return 0 +} + +func (c *ctxt7) opstr12(p *obj.Prog, a obj.As) uint32 { + return LD2STR(c.opldr12(p, a)) +} + +/* + * load/store register (unscaled immediate) C3.3.12 + */ +func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 { + if v < -256 || v > 255 { + c.ctxt.Diag("offset out of range: %d\n%v", v, p) + } + o |= (v & 0x1FF) << 12 + o |= int32(b&31) << 5 + o |= int32(r & 31) + return uint32(o) +} + +func (c *ctxt7) opldr9(p *obj.Prog, a obj.As) uint32 { + switch a { + case AMOVD: + return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */ + + case AMOVW: + return LDSTR9S(2, 0, 2) + + case AMOVWU: + return LDSTR9S(2, 0, 1) + + case AMOVH: + return LDSTR9S(1, 0, 2) + + case AMOVHU: + return LDSTR9S(1, 0, 1) + + case AMOVB: + return LDSTR9S(0, 0, 2) + + case AMOVBU: + return LDSTR9S(0, 0, 1) + + case AFMOVS: + return LDSTR9S(2, 1, 1) + + case AFMOVD: + return LDSTR9S(3, 1, 1) + } + + c.ctxt.Diag("bad opldr9 %v\n%v", a, p) + return 0 +} + +func (c *ctxt7) opstr9(p *obj.Prog, a obj.As) uint32 { + return LD2STR(c.opldr9(p, a)) +} + +func (c *ctxt7) opldrpp(p *obj.Prog, a obj.As) uint32 { + switch a { + case AMOVD: + return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */ + + case AMOVW: + return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVWU: + return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + + case AMOVH: + return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVHU: + return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + + case AMOVB: + return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVBU: + return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + + case AFMOVS: + return 2<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22 + + case AFMOVD: + return 3<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22 + + case APRFM: + return 0xf9<<24 | 2<<22 + + } + + c.ctxt.Diag("bad opldr %v\n%v", a, p) + return 0 +} + +// olsxrr attaches register operands to a load/store opcode supplied in o. +// The result either encodes a load of r from (r1+r2) or a store of r to (r1+r2). +func (c *ctxt7) olsxrr(p *obj.Prog, o int32, r int, r1 int, r2 int) uint32 { + o |= int32(r1&31) << 5 + o |= int32(r2&31) << 16 + o |= int32(r & 31) + return uint32(o) +} + +// opldrr returns the ARM64 opcode encoding corresponding to the obj.As opcode +// for load instruction with register offset. +// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm). +func (c *ctxt7) opldrr(p *obj.Prog, a obj.As, extension bool) uint32 { + OptionS := uint32(0x1a) + if extension { + OptionS = uint32(0) // option value and S value have been encoded into p.From.Offset. + } + switch a { + case AMOVD: + return OptionS<<10 | 0x3<<21 | 0x1f<<27 + case AMOVW: + return OptionS<<10 | 0x5<<21 | 0x17<<27 + case AMOVWU: + return OptionS<<10 | 0x3<<21 | 0x17<<27 + case AMOVH: + return OptionS<<10 | 0x5<<21 | 0x0f<<27 + case AMOVHU: + return OptionS<<10 | 0x3<<21 | 0x0f<<27 + case AMOVB: + return OptionS<<10 | 0x5<<21 | 0x07<<27 + case AMOVBU: + return OptionS<<10 | 0x3<<21 | 0x07<<27 + case AFMOVS: + return OptionS<<10 | 0x3<<21 | 0x17<<27 | 1<<26 + case AFMOVD: + return OptionS<<10 | 0x3<<21 | 0x1f<<27 | 1<<26 + } + c.ctxt.Diag("bad opldrr %v\n%v", a, p) + return 0 +} + +// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode +// for store instruction with register offset. +// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm). +func (c *ctxt7) opstrr(p *obj.Prog, a obj.As, extension bool) uint32 { + OptionS := uint32(0x1a) + if extension { + OptionS = uint32(0) // option value and S value have been encoded into p.To.Offset. + } + switch a { + case AMOVD: + return OptionS<<10 | 0x1<<21 | 0x1f<<27 + case AMOVW, AMOVWU: + return OptionS<<10 | 0x1<<21 | 0x17<<27 + case AMOVH, AMOVHU: + return OptionS<<10 | 0x1<<21 | 0x0f<<27 + case AMOVB, AMOVBU: + return OptionS<<10 | 0x1<<21 | 0x07<<27 + case AFMOVS: + return OptionS<<10 | 0x1<<21 | 0x17<<27 | 1<<26 + case AFMOVD: + return OptionS<<10 | 0x1<<21 | 0x1f<<27 | 1<<26 + } + c.ctxt.Diag("bad opstrr %v\n%v", a, p) + return 0 +} + +func (c *ctxt7) oaddi(p *obj.Prog, o1 int32, v int32, r int, rt int) uint32 { + if (v & 0xFFF000) != 0 { + if v&0xFFF != 0 { + c.ctxt.Diag("%v misuses oaddi", p) + } + v >>= 12 + o1 |= 1 << 22 + } + + o1 |= ((v & 0xFFF) << 10) | (int32(r&31) << 5) | int32(rt&31) + return uint32(o1) +} + +/* + * load a literal value into dr + */ +func (c *ctxt7) omovlit(as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 { + var o1 int32 + if p.Pool == nil { /* not in literal pool */ + c.aclass(a) + c.ctxt.Logf("omovlit add %d (%#x)\n", c.instoffset, uint64(c.instoffset)) + + /* TODO: could be clever, and use general constant builder */ + o1 = int32(c.opirr(p, AADD)) + + v := int32(c.instoffset) + if v != 0 && (v&0xFFF) == 0 { + v >>= 12 + o1 |= 1 << 22 /* shift, by 12 */ + } + + o1 |= ((v & 0xFFF) << 10) | (REGZERO & 31 << 5) | int32(dr&31) + } else { + fp, w := 0, 0 + switch as { + case AFMOVS: + fp = 1 + w = 0 /* 32-bit SIMD/FP */ + + case AFMOVD: + fp = 1 + w = 1 /* 64-bit SIMD/FP */ + + case AFMOVQ: + fp = 1 + w = 2 /* 128-bit SIMD/FP */ + + case AMOVD: + if p.Pool.As == ADWORD { + w = 1 /* 64-bit */ + } else if p.Pool.To.Offset < 0 { + w = 2 /* 32-bit, sign-extended to 64-bit */ + } else if p.Pool.To.Offset >= 0 { + w = 0 /* 32-bit, zero-extended to 64-bit */ + } else { + c.ctxt.Diag("invalid operand %v in %v", a, p) + } + + case AMOVBU, AMOVHU, AMOVWU: + w = 0 /* 32-bit, zero-extended to 64-bit */ + + case AMOVB, AMOVH, AMOVW: + w = 2 /* 32-bit, sign-extended to 64-bit */ + + default: + c.ctxt.Diag("invalid operation %v in %v", as, p) + } + + v := int32(c.brdist(p, 0, 19, 2)) + o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27) + o1 |= (v & 0x7FFFF) << 5 + o1 |= int32(dr & 31) + } + + return uint32(o1) +} + +// load a constant (MOVCON or BITCON) in a into rt +func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) { + if cls := oclass(a); cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0 { + // or $bitcon, REGZERO, rt + mode := 64 + var as1 obj.As + switch as { + case AMOVW: + as1 = AORRW + mode = 32 + case AMOVD: + as1 = AORR + } + o1 = c.opirr(p, as1) + o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31) + return o1 + } + + if as == AMOVW { + d := uint32(a.Offset) + s := movcon(int64(d)) + if s < 0 || 16*s >= 32 { + d = ^d + s = movcon(int64(d)) + if s < 0 || 16*s >= 32 { + c.ctxt.Diag("impossible 32-bit move wide: %#x\n%v", uint32(a.Offset), p) + } + o1 = c.opirr(p, AMOVNW) + } else { + o1 = c.opirr(p, AMOVZW) + } + o1 |= MOVCONST(int64(d), s, rt) + } + if as == AMOVD { + d := a.Offset + s := movcon(d) + if s < 0 || 16*s >= 64 { + d = ^d + s = movcon(d) + if s < 0 || 16*s >= 64 { + c.ctxt.Diag("impossible 64-bit move wide: %#x\n%v", uint64(a.Offset), p) + } + o1 = c.opirr(p, AMOVN) + } else { + o1 = c.opirr(p, AMOVZ) + } + o1 |= MOVCONST(d, s, rt) + } + return o1 +} + +// load a 32-bit/64-bit large constant (LCON or VCON) in a.Offset into rt +// put the instruction sequence in os and return the number of instructions. +func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uint32) (num uint8) { + switch as { + case AMOVW: + d := uint32(a.Offset) + // use MOVZW and MOVKW to load a constant to rt + os[0] = c.opirr(p, AMOVZW) + os[0] |= MOVCONST(int64(d), 0, rt) + os[1] = c.opirr(p, AMOVKW) + os[1] |= MOVCONST(int64(d), 1, rt) + return 2 + + case AMOVD: + d := a.Offset + dn := ^d + var immh [4]uint64 + var i int + zeroCount := int(0) + negCount := int(0) + for i = 0; i < 4; i++ { + immh[i] = uint64((d >> uint(i*16)) & 0xffff) + if immh[i] == 0 { + zeroCount++ + } else if immh[i] == 0xffff { + negCount++ + } + } + + if zeroCount == 4 || negCount == 4 { + c.ctxt.Diag("the immediate should be MOVCON: %v", p) + } + switch { + case zeroCount == 3: + // one MOVZ + for i = 0; i < 4; i++ { + if immh[i] != 0 { + os[0] = c.opirr(p, AMOVZ) + os[0] |= MOVCONST(d, i, rt) + break + } + } + return 1 + + case negCount == 3: + // one MOVN + for i = 0; i < 4; i++ { + if immh[i] != 0xffff { + os[0] = c.opirr(p, AMOVN) + os[0] |= MOVCONST(dn, i, rt) + break + } + } + return 1 + + case zeroCount == 2: + // one MOVZ and one MOVK + for i = 0; i < 4; i++ { + if immh[i] != 0 { + os[0] = c.opirr(p, AMOVZ) + os[0] |= MOVCONST(d, i, rt) + i++ + break + } + } + for ; i < 4; i++ { + if immh[i] != 0 { + os[1] = c.opirr(p, AMOVK) + os[1] |= MOVCONST(d, i, rt) + } + } + return 2 + + case negCount == 2: + // one MOVN and one MOVK + for i = 0; i < 4; i++ { + if immh[i] != 0xffff { + os[0] = c.opirr(p, AMOVN) + os[0] |= MOVCONST(dn, i, rt) + i++ + break + } + } + for ; i < 4; i++ { + if immh[i] != 0xffff { + os[1] = c.opirr(p, AMOVK) + os[1] |= MOVCONST(d, i, rt) + } + } + return 2 + + case zeroCount == 1: + // one MOVZ and two MOVKs + for i = 0; i < 4; i++ { + if immh[i] != 0 { + os[0] = c.opirr(p, AMOVZ) + os[0] |= MOVCONST(d, i, rt) + i++ + break + } + } + + for j := 1; i < 4; i++ { + if immh[i] != 0 { + os[j] = c.opirr(p, AMOVK) + os[j] |= MOVCONST(d, i, rt) + j++ + } + } + return 3 + + case negCount == 1: + // one MOVN and two MOVKs + for i = 0; i < 4; i++ { + if immh[i] != 0xffff { + os[0] = c.opirr(p, AMOVN) + os[0] |= MOVCONST(dn, i, rt) + i++ + break + } + } + + for j := 1; i < 4; i++ { + if immh[i] != 0xffff { + os[j] = c.opirr(p, AMOVK) + os[j] |= MOVCONST(d, i, rt) + j++ + } + } + return 3 + + default: + // one MOVZ and 3 MOVKs + os[0] = c.opirr(p, AMOVZ) + os[0] |= MOVCONST(d, 0, rt) + for i = 1; i < 4; i++ { + os[i] = c.opirr(p, AMOVK) + os[i] |= MOVCONST(d, i, rt) + } + return 4 + } + default: + return 0 + } +} + +func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 { + var b uint32 + o := c.opirr(p, a) + if (o & (1 << 31)) == 0 { + b = 32 + } else { + b = 64 + } + if r < 0 || uint32(r) >= b { + c.ctxt.Diag("illegal bit number\n%v", p) + } + o |= (uint32(r) & 0x3F) << 16 + if s < 0 || uint32(s) >= b { + c.ctxt.Diag("illegal bit number\n%v", p) + } + o |= (uint32(s) & 0x3F) << 10 + o |= (uint32(rf&31) << 5) | uint32(rt&31) + return o +} + +func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) uint32 { + var b uint32 + o := c.opirr(p, a) + if (o & (1 << 31)) != 0 { + b = 63 + } else { + b = 31 + } + if v < 0 || uint32(v) > b { + c.ctxt.Diag("illegal bit number\n%v", p) + } + o |= uint32(v) << 10 + o |= uint32(rn&31) << 5 + o |= uint32(rm&31) << 16 + o |= uint32(rt & 31) + return o +} + +/* genrate instruction encoding for LDP/LDPW/LDPSW/STP/STPW */ +func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uint32) uint32 { + wback := false + if o.scond == C_XPOST || o.scond == C_XPRE { + wback = true + } + switch p.As { + case ALDP, ALDPW, ALDPSW: + c.checkUnpredictable(p, true, wback, p.From.Reg, p.To.Reg, int16(p.To.Offset)) + case ASTP, ASTPW: + if wback == true { + c.checkUnpredictable(p, false, true, p.To.Reg, p.From.Reg, int16(p.From.Offset)) + } + case AFLDPD, AFLDPS: + c.checkUnpredictable(p, true, false, p.From.Reg, p.To.Reg, int16(p.To.Offset)) + } + var ret uint32 + // check offset + switch p.As { + case AFLDPD, AFSTPD: + if vo < -512 || vo > 504 || vo%8 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 8 + ret = 1<<30 | 1<<26 + case ALDP, ASTP: + if vo < -512 || vo > 504 || vo%8 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 8 + ret = 2 << 30 + case AFLDPS, AFSTPS: + if vo < -256 || vo > 252 || vo%4 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 4 + ret = 1 << 26 + case ALDPW, ASTPW: + if vo < -256 || vo > 252 || vo%4 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 4 + ret = 0 + case ALDPSW: + if vo < -256 || vo > 252 || vo%4 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 4 + ret = 1 << 30 + default: + c.ctxt.Diag("invalid instruction %v\n", p) + } + // check register pair + switch p.As { + case AFLDPD, AFLDPS, AFSTPD, AFSTPS: + if rl < REG_F0 || REG_F31 < rl || rh < REG_F0 || REG_F31 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + case ALDP, ALDPW, ALDPSW: + if rl < REG_R0 || REG_R30 < rl || rh < REG_R0 || REG_R30 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + case ASTP, ASTPW: + if rl < REG_R0 || REG_R31 < rl || rh < REG_R0 || REG_R31 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + } + // other conditional flag bits + switch o.scond { + case C_XPOST: + ret |= 1 << 23 + case C_XPRE: + ret |= 3 << 23 + default: + ret |= 2 << 23 + } + ret |= 5<<27 | (ldp&1)<<22 | uint32(vo&0x7f)<<15 | (rh&31)<<10 | (rbase&31)<<5 | (rl & 31) + return ret +} + +func (c *ctxt7) maskOpvldvst(p *obj.Prog, o1 uint32) uint32 { + if p.As == AVLD1 || p.As == AVST1 { + return o1 + } + + o1 &^= 0xf000 // mask out "opcode" field (bit 12-15) + switch p.As { + case AVLD1R, AVLD2R: + o1 |= 0xC << 12 + case AVLD3R, AVLD4R: + o1 |= 0xE << 12 + case AVLD2, AVST2: + o1 |= 8 << 12 + case AVLD3, AVST3: + o1 |= 4 << 12 + case AVLD4, AVST4: + default: + c.ctxt.Diag("unsupported instruction:%v\n", p.As) + } + return o1 +} + +/* + * size in log2(bytes) + */ +func movesize(a obj.As) int { + switch a { + case AMOVD: + return 3 + + case AMOVW, AMOVWU: + return 2 + + case AMOVH, AMOVHU: + return 1 + + case AMOVB, AMOVBU: + return 0 + + case AFMOVS: + return 2 + + case AFMOVD: + return 3 + + default: + return -1 + } +} + +// rm is the Rm register value, o is the extension, amount is the left shift value. +func roff(rm int16, o uint32, amount int16) uint32 { + return uint32(rm&31)<<16 | o<<13 | uint32(amount)<<10 +} + +// encRegShiftOrExt returns the encoding of shifted/extended register, Rx<> 5) & 7 + rm = r & 31 + switch { + case REG_UXTB <= r && r < REG_UXTH: + return roff(rm, 0, num) + case REG_UXTH <= r && r < REG_UXTW: + return roff(rm, 1, num) + case REG_UXTW <= r && r < REG_UXTX: + if a.Type == obj.TYPE_MEM { + if num == 0 { + return roff(rm, 2, 2) + } else { + return roff(rm, 2, 6) + } + } else { + return roff(rm, 2, num) + } + case REG_UXTX <= r && r < REG_SXTB: + return roff(rm, 3, num) + case REG_SXTB <= r && r < REG_SXTH: + return roff(rm, 4, num) + case REG_SXTH <= r && r < REG_SXTW: + return roff(rm, 5, num) + case REG_SXTW <= r && r < REG_SXTX: + if a.Type == obj.TYPE_MEM { + if num == 0 { + return roff(rm, 6, 2) + } else { + return roff(rm, 6, 6) + } + } else { + return roff(rm, 6, num) + } + case REG_SXTX <= r && r < REG_SPECIAL: + if a.Type == obj.TYPE_MEM { + if num == 0 { + return roff(rm, 7, 2) + } else { + return roff(rm, 7, 6) + } + } else { + return roff(rm, 7, num) + } + case REG_LSL <= r && r < (REG_LSL+1<<8): + return roff(rm, 3, 6) + default: + c.ctxt.Diag("unsupported register extension type.") + } + + return 0 +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/doc.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/doc.go new file mode 100644 index 0000000..7515217 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/doc.go @@ -0,0 +1,249 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package arm64 implements an ARM64 assembler. Go assembly syntax is different from GNU ARM64 +syntax, but we can still follow the general rules to map between them. + +Instructions mnemonics mapping rules + +1. Most instructions use width suffixes of instruction names to indicate operand width rather than +using different register names. + + Examples: + ADC R24, R14, R12 <=> adc x12, x24 + ADDW R26->24, R21, R15 <=> add w15, w21, w26, asr #24 + FCMPS F2, F3 <=> fcmp s3, s2 + FCMPD F2, F3 <=> fcmp d3, d2 + FCVTDH F2, F3 <=> fcvt h3, d2 + +2. Go uses .P and .W suffixes to indicate post-increment and pre-increment. + + Examples: + MOVD.P -8(R10), R8 <=> ldr x8, [x10],#-8 + MOVB.W 16(R16), R10 <=> ldrsb x10, [x16,#16]! + MOVBU.W 16(R16), R10 <=> ldrb x10, [x16,#16]! + +3. Go uses a series of MOV instructions as load and store. + +64-bit variant ldr, str, stur => MOVD; +32-bit variant str, stur, ldrsw => MOVW; +32-bit variant ldr => MOVWU; +ldrb => MOVBU; ldrh => MOVHU; +ldrsb, sturb, strb => MOVB; +ldrsh, sturh, strh => MOVH. + +4. Go moves conditions into opcode suffix, like BLT. + +5. Go adds a V prefix for most floating-point and SIMD instructions, except cryptographic extension +instructions and floating-point(scalar) instructions. + + Examples: + VADD V5.H8, V18.H8, V9.H8 <=> add v9.8h, v18.8h, v5.8h + VLD1.P (R6)(R11), [V31.D1] <=> ld1 {v31.1d}, [x6], x11 + VFMLA V29.S2, V20.S2, V14.S2 <=> fmla v14.2s, v20.2s, v29.2s + AESD V22.B16, V19.B16 <=> aesd v19.16b, v22.16b + SCVTFWS R3, F16 <=> scvtf s17, w6 + +6. Align directive + +Go asm supports the PCALIGN directive, which indicates that the next instruction should be aligned +to a specified boundary by padding with NOOP instruction. The alignment value supported on arm64 +must be a power of 2 and in the range of [8, 2048]. + + Examples: + PCALIGN $16 + MOVD $2, R0 // This instruction is aligned with 16 bytes. + PCALIGN $1024 + MOVD $3, R1 // This instruction is aligned with 1024 bytes. + +PCALIGN also changes the function alignment. If a function has one or more PCALIGN directives, +its address will be aligned to the same or coarser boundary, which is the maximum of all the +alignment values. + +In the following example, the function Add is aligned with 128 bytes. + Examples: + TEXT ·Add(SB),$40-16 + MOVD $2, R0 + PCALIGN $32 + MOVD $4, R1 + PCALIGN $128 + MOVD $8, R2 + RET + +On arm64, functions in Go are aligned to 16 bytes by default, we can also use PCALGIN to set the +function alignment. The functions that need to be aligned are preferably using NOFRAME and NOSPLIT +to avoid the impact of the prologues inserted by the assembler, so that the function address will +have the same alignment as the first hand-written instruction. + +In the following example, PCALIGN at the entry of the function Add will align its address to 2048 bytes. + + Examples: + TEXT ·Add(SB),NOSPLIT|NOFRAME,$0 + PCALIGN $2048 + MOVD $1, R0 + MOVD $1, R1 + RET + +Special Cases. + +(1) umov is written as VMOV. + +(2) br is renamed JMP, blr is renamed CALL. + +(3) No need to add "W" suffix: LDARB, LDARH, LDAXRB, LDAXRH, LDTRH, LDXRB, LDXRH. + +(4) In Go assembly syntax, NOP is a zero-width pseudo-instruction serves generic purpose, nothing +related to real ARM64 instruction. NOOP serves for the hardware nop instruction. NOOP is an alias of +HINT $0. + + Examples: + VMOV V13.B[1], R20 <=> mov x20, v13.b[1] + VMOV V13.H[1], R20 <=> mov w20, v13.h[1] + JMP (R3) <=> br x3 + CALL (R17) <=> blr x17 + LDAXRB (R19), R16 <=> ldaxrb w16, [x19] + NOOP <=> nop + + +Register mapping rules + +1. All basic register names are written as Rn. + +2. Go uses ZR as the zero register and RSP as the stack pointer. + +3. Bn, Hn, Dn, Sn and Qn instructions are written as Fn in floating-point instructions and as Vn +in SIMD instructions. + + +Argument mapping rules + +1. The operands appear in left-to-right assignment order. + +Go reverses the arguments of most instructions. + + Examples: + ADD R11.SXTB<<1, RSP, R25 <=> add x25, sp, w11, sxtb #1 + VADD V16, V19, V14 <=> add d14, d19, d16 + +Special Cases. + +(1) Argument order is the same as in the GNU ARM64 syntax: cbz, cbnz and some store instructions, +such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1. + + Examples: + MOVD R29, 384(R19) <=> str x29, [x19,#384] + MOVB.P R30, 30(R4) <=> strb w30, [x4],#30 + STLRH R21, (R19) <=> stlrh w21, [x19] + +(2) MADD, MADDW, MSUB, MSUBW, SMADDL, SMSUBL, UMADDL, UMSUBL , , , + + Examples: + MADD R2, R30, R22, R6 <=> madd x6, x22, x2, x30 + SMSUBL R10, R3, R17, R27 <=> smsubl x27, w17, w10, x3 + +(3) FMADDD, FMADDS, FMSUBD, FMSUBS, FNMADDD, FNMADDS, FNMSUBD, FNMSUBS , , , + + Examples: + FMADDD F30, F20, F3, F29 <=> fmadd d29, d3, d30, d20 + FNMSUBS F7, F25, F7, F22 <=> fnmsub s22, s7, s7, s25 + +(4) BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX $, , $, + + Examples: + BFIW $16, R20, $6, R0 <=> bfi w0, w20, #16, #6 + UBFIZ $34, R26, $5, R20 <=> ubfiz x20, x26, #34, #5 + +(5) FCCMPD, FCCMPS, FCCMPED, FCCMPES , Fm. Fn, $ + + Examples: + FCCMPD AL, F8, F26, $0 <=> fccmp d26, d8, #0x0, al + FCCMPS VS, F29, F4, $4 <=> fccmp s4, s29, #0x4, vs + FCCMPED LE, F20, F5, $13 <=> fccmpe d5, d20, #0xd, le + FCCMPES NE, F26, F10, $0 <=> fccmpe s10, s26, #0x0, ne + +(6) CCMN, CCMNW, CCMP, CCMPW , , $, $ + + Examples: + CCMP MI, R22, $12, $13 <=> ccmp x22, #0xc, #0xd, mi + CCMNW AL, R1, $11, $8 <=> ccmn w1, #0xb, #0x8, al + +(7) CCMN, CCMNW, CCMP, CCMPW , , , $ + + Examples: + CCMN VS, R13, R22, $10 <=> ccmn x13, x22, #0xa, vs + CCMPW HS, R19, R14, $11 <=> ccmp w19, w14, #0xb, cs + +(9) CSEL, CSELW, CSNEG, CSNEGW, CSINC, CSINCW , , , ; +FCSELD, FCSELS , , , + + Examples: + CSEL GT, R0, R19, R1 <=> csel x1, x0, x19, gt + CSNEGW GT, R7, R17, R8 <=> csneg w8, w7, w17, gt + FCSELD EQ, F15, F18, F16 <=> fcsel d16, d15, d18, eq + +(10) TBNZ, TBZ $, ,