зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1608941 - Bump cranelift to b01bee7c5269f72196b42e8bdd874425166bf429. r=bbouvier
Differential Revision: https://phabricator.services.mozilla.com/D60271 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1aa9918367
Коммит
6dd534025d
|
@ -40,7 +40,7 @@ rev = "8069f8f4189982e0b38fa6dc8993dd4fab41f728"
|
|||
[source."https://github.com/bytecodealliance/cranelift"]
|
||||
git = "https://github.com/bytecodealliance/cranelift"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
rev = "b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
|
||||
[source."https://github.com/badboy/failure"]
|
||||
git = "https://github.com/badboy/failure"
|
||||
|
|
|
@ -178,8 +178,8 @@ name = "baldrdash"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-wasm 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-wasm 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -635,41 +635,41 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-entity 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-bforest 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen-meta 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen-shared 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-entity 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-bforest 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-codegen-meta 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-codegen-shared 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-entity 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-entity 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen-shared 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-entity 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
|
@ -678,31 +678,31 @@ source = "git+https://github.com/PLSysSec/lucet_sandbox_compiler?rev=58498599272
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.51.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677#ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
version = "0.55.0"
|
||||
source = "git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429#b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-entity 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-frontend 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)",
|
||||
"cranelift-codegen 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-entity 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"cranelift-frontend 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmparser 0.47.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3800,6 +3800,11 @@ name = "target-lexicon"
|
|||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
|
@ -4291,7 +4296,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.39.2"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -4695,14 +4700,14 @@ dependencies = [
|
|||
"checksum coreaudio-sys-utils 0.1.0 (git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=acb90e9bf36e6e035ac6bbe51efa0a8825b5b6be)" = "<none>"
|
||||
"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
|
||||
"checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
|
||||
"checksum cranelift-bforest 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-codegen 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-codegen-meta 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-codegen-shared 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-bforest 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-codegen 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-codegen-meta 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-codegen-shared 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-entity 0.41.0 (git+https://github.com/PLSysSec/lucet_sandbox_compiler?rev=58498599272e23ef797bb4304d0f181d7455ca57)" = "<none>"
|
||||
"checksum cranelift-entity 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-frontend 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-wasm 0.51.0 (git+https://github.com/bytecodealliance/cranelift?rev=ec787eb281bb2e18e191508c17abe694e91f0677)" = "<none>"
|
||||
"checksum cranelift-entity 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-frontend 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum cranelift-wasm 0.55.0 (git+https://github.com/bytecodealliance/cranelift?rev=b01bee7c5269f72196b42e8bdd874425166bf429)" = "<none>"
|
||||
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
||||
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
|
@ -4966,6 +4971,7 @@ dependencies = [
|
|||
"checksum svg_fmt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c666f0fed8e1e20e057af770af9077d72f3d5a33157b8537c1475dd8ffd6d32b"
|
||||
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
|
||||
"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
|
||||
"checksum target-lexicon 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
|
||||
"checksum target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
|
@ -5018,7 +5024,7 @@ dependencies = [
|
|||
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
|
||||
"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
|
||||
"checksum warp 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "33857527c63bc514452f885d0a57019f28139c58fef2b3566016ecc0d44e5d24"
|
||||
"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82"
|
||||
"checksum wasmparser 0.47.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1add8db5a53a2f64f13418b241982c4ab533d7a9e1e8a5dcadccce633d8d393b"
|
||||
"checksum webrtc-sdp 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75fb1417c7262d8bdc0f0a2b0e32607675c9315dcbb6fccfdf75ece04e01326a"
|
||||
"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
|
|
@ -71,8 +71,8 @@ failure_derive = { git = "https://github.com/badboy/failure", rev = "64af847bc5f
|
|||
|
||||
[patch.crates-io.cranelift-codegen]
|
||||
git = "https://github.com/bytecodealliance/cranelift"
|
||||
rev = "ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
rev = "b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
|
||||
[patch.crates-io.cranelift-wasm]
|
||||
git = "https://github.com/bytecodealliance/cranelift"
|
||||
rev = "ec787eb281bb2e18e191508c17abe694e91f0677"
|
||||
rev = "b01bee7c5269f72196b42e8bdd874425166bf429"
|
||||
|
|
|
@ -13,8 +13,8 @@ name = "baldrdash"
|
|||
# cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
|
||||
# you should update the following $TOP_LEVEL/Cargo.toml file: look for the
|
||||
# revision (rev) hashes of both cranelift dependencies (codegen and wasm).
|
||||
cranelift-codegen = { version = "0.51", default-features = false }
|
||||
cranelift-wasm = "0.51"
|
||||
cranelift-codegen = { version = "0.55", default-features = false }
|
||||
cranelift-wasm = "0.55"
|
||||
log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] }
|
||||
env_logger = "0.6"
|
||||
smallvec = "1.0"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"abc61ed8d3d7e08b1d8f5f92e60bb76d1917d2db5b797f82b9b9ff144e6ae4c4","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"59933214e5213d003d98c6fa5f22c3c863557640189588d989ff0335b006af9a","src/map.rs":"a3b7f64cae7ec9c2a8038def315bcf90e8751552b1bc1c20b62fbb8c763866c4","src/node.rs":"28f7edd979f7b9712bc4ab30b0d2a1b8ad5485a4b1e8c09f3dcaf501b9b5ccd1","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"f6337b5417f7772e6878a160c1a40629199ff09997bdff18eb2a0ba770158600","src/set.rs":"281eb8b5ead1ffd395946464d881f9bb0e7fb61092aed701d72d2314b5f80994"},"package":null}
|
||||
{"files":{"Cargo.toml":"d47e794d642207dbd9f09c345a5d35382cd0a426c510fded00422bde9f1c5fb7","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"59933214e5213d003d98c6fa5f22c3c863557640189588d989ff0335b006af9a","src/map.rs":"a3b7f64cae7ec9c2a8038def315bcf90e8751552b1bc1c20b62fbb8c763866c4","src/node.rs":"28f7edd979f7b9712bc4ab30b0d2a1b8ad5485a4b1e8c09f3dcaf501b9b5ccd1","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"f6337b5417f7772e6878a160c1a40629199ff09997bdff18eb2a0ba770158600","src/set.rs":"281eb8b5ead1ffd395946464d881f9bb0e7fb61092aed701d72d2314b5f80994"},"package":null}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "A forest of B+-trees"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
@ -12,7 +12,7 @@ keywords = ["btree", "forest", "set", "map"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.51.0", default-features = false }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.55.0", default-features = false }
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"65c94041eeaee1397206bacf6777b9f51cedae6e5309e6a0ceaf3a1a3c82f4ea","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"8fdd17d9d8c4bd0cf535599a40d7da0e5bf27fdcef817cd55ab7c580c8eb6a6c","src/cdsl/cpu_modes.rs":"7ceb99df347faf5e69b34a7e0d691e9c148d15587df09e99d46a7d37238d8d06","src/cdsl/encodings.rs":"d884a564815a03c23369bcf31d13b122ae5ba84d0c80eda9312f0c0a829bf794","src/cdsl/formats.rs":"63e638305aa3ca6dd409ddf0e5e9605eeac1cc2631103e42fc6cbc87703d9b63","src/cdsl/instructions.rs":"6ad4c75e2bf634475b6a57feb1582f39dd8e670680f68f66218274ad96b6b3f4","src/cdsl/isa.rs":"ccabd6848b69eb069c10db61c7e7f86080777495714bb53d03e663c40541be94","src/cdsl/mod.rs":"0aa827923bf4c45e5ee2359573bd863e00f474acd532739f49dcd74a27553882","src/cdsl/operands.rs":"1c3411504de9c83112ff48e0ff1cfbb2e4ba5a9a15c1716f411ef31a4df59899","src/cdsl/recipes.rs":"a3b4c49488762864856f9fb181df70650fceea07219d093f3c952229c67d35e1","src/cdsl/regs.rs":"05f93ab8504ee82d7cc9811a5b40e5cd004c327577b4c0b3dd957fc422f3c013","src/cdsl/settings.rs":"e6fd9a31925743b93b11f09c9c8271bab6aa2430aa053a2601957b4487df7d77","src/cdsl/type_inference.rs":"1efca8a095ffc899b7527bda6b9d9378c73d7283f8dceaa4819e8af599f8be21","src/cdsl/types.rs":"763cb82b1d8ceb6be682ed6c71c8c98cab686151d177aad6d8f8ef92a37c5639","src/cdsl/typevar.rs":"52f7242a35805a82baf2c788c3eb392e2fba0fcbf47f047f32eba81f34487c7e","src/cdsl/xform.rs":"55da0c3f2403147b535ab6ae5d69c623fbe839edecf2a3af1de84420cd58402d","src/default_map.rs":"101bb0282a124f9c921f6bd095f529e8753621450d783c3273b0b0394c2c5c03","src/error.rs":"e9b11b2feb2d867b94c8810fdc5a6c4e0d9131604a0bfa5340ff2639a55100b4","src/gen_binemit.rs":"515e243420b30d1e01f8ea630282d9b6d78a715e1951f3f20392e19a48164442","src/gen_encodings.rs":"f00cded6b68a9b48c9e3cd39a8b6f0ba136f4062c8f8666109158a72c62c3ed1","src/gen_inst.rs":"fac99641622591c0529c0ef789dd83290a624fc674c91a959f426696f82044de","src/gen_legalizer.rs":"7a68c2b9fd77b6420ecb10539d9af0520374e4f2e30d5a345d98dafde157e6bd","src/gen_registers.rs":"3628949229c1cb5179ec5f655b9a1ddd0504ba74ffb9fb23741c85c9154b696f","src/gen_settings.rs":"f3cc3d31f6cc898f30606caf084f0de220db2d3b1b5e5e4145fa7c9a9a1597e2","src/gen_types.rs":"f6c090e1646a43bf2fe81ae0a7029cc6f7dc6d43285368f56d86c35a21c469a6","src/isa/arm32/mod.rs":"8e09ec1b3caf2d22dce8517b37c356047bfce9a6dea712467d867ed05c4bedaf","src/isa/arm64/mod.rs":"b01f030925d3f2af37d7df1b4a800eb7f0d24f74a46e9154fd8b6752643eb2d5","src/isa/mod.rs":"136141f99f217ba42b9e3f7f47238ab19cc974bb3bef2e2df7f7b5a683989d46","src/isa/riscv/encodings.rs":"8abb1968d917588bc5fc5f5be6dd66bdec23ac456ba65f8138237c8e891e843c","src/isa/riscv/mod.rs":"a7b461a30bbfbc1e3b33645422ff40d5b1761c30cb5d4a8aa12e9a3b7f7aee51","src/isa/riscv/recipes.rs":"c9424cffed54cc4d328879a4613b9f6a2c2b7cde7e6e17b4fccd5f661aaf92f2","src/isa/x86/encodings.rs":"71ba4d1cca1480437baecf1fe55ef8f9d759e540a697b5e09a2489567dfa8c26","src/isa/x86/instructions.rs":"e4a92f2b707e0a9af0317041eb9a8bc58a8bedcdbbe35f54dcfaf05699a50675","src/isa/x86/legalize.rs":"0624341293bc91f77a2bdc69c04a89a483ba18cc263058b92879b88127035c79","src/isa/x86/mod.rs":"49f0bc05898d1d8565e692ec2550855de15fd6cffa3b5b6e0f8d502cd813e306","src/isa/x86/opcodes.rs":"643bae64cd4050814adfb856046cf650979bec5d251a9d9a6e11bafb5a603c43","src/isa/x86/recipes.rs":"971277543466e91be6b41c1735d81ca2752c175ac079d7c7ab8694c87cab56fd","src/isa/x86/registers.rs":"e24c9487f4c257b1089dac6bca0106cc673db77292cd000ca8e0c7e0d0103f63","src/isa/x86/settings.rs":"7f6266cd5098115ac24caea3be07a18c590c07b8cfe5f0912af3ed1d0d288330","src/lib.rs":"2491b0e74078914cb89d1778fa8174daf723fe76aaf7fed18741237d68f6df32","src/shared/entities.rs":"911b396da11188bd510de004956596f150e27540edd351c74028f99f5f3c79c5","src/shared/formats.rs":"d8cf211c392ec3c54d0101ef31b700c3222bc8e80b69a04b244953e449770336","src/shared/immediates.rs":"e4a57657f6af9853794804eb41c01204a2c13a632f44f55d90e156a4b98c5f65","src/shared/instructions.rs":"cef3be79dfe3d1c2d0c4eef91cca2852ec5454c1e6bc326d8b64ade622da0ef2","src/shared/legalize.rs":"73e1b42743c324104f5a34120e1598146ce4ee7393137ecb5391b768c61f2605","src/shared/mod.rs":"bc497c14d083c29eefe4935cff9cd1bd138c071bc50f787248727a3858dc69f3","src/shared/settings.rs":"5775bb6b760ed9f54370b2ab0ae6bc020cafc6ad1369e90fec6144375641c27f","src/shared/types.rs":"4702df132f4b5d70cc9411ec5221ba0b1bd4479252274e0223ae57b6d0331247","src/srcgen.rs":"dcfc159c8599270f17e6a978c4be255abca51556b5ef0da497faec4a4a1e62ce","src/unique_table.rs":"31aa54330ca4786af772d32e8cb6158b6504b88fa93fe177bf0c6cbe545a8d35"},"package":null}
|
||||
{"files":{"Cargo.toml":"eecaf15fdc0f1a78dce08dae1fc6c529da7638f1bb2ea7c007741df27973b6d7","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"8fdd17d9d8c4bd0cf535599a40d7da0e5bf27fdcef817cd55ab7c580c8eb6a6c","src/cdsl/cpu_modes.rs":"7ceb99df347faf5e69b34a7e0d691e9c148d15587df09e99d46a7d37238d8d06","src/cdsl/encodings.rs":"d884a564815a03c23369bcf31d13b122ae5ba84d0c80eda9312f0c0a829bf794","src/cdsl/formats.rs":"63e638305aa3ca6dd409ddf0e5e9605eeac1cc2631103e42fc6cbc87703d9b63","src/cdsl/instructions.rs":"6ad4c75e2bf634475b6a57feb1582f39dd8e670680f68f66218274ad96b6b3f4","src/cdsl/isa.rs":"ccabd6848b69eb069c10db61c7e7f86080777495714bb53d03e663c40541be94","src/cdsl/mod.rs":"0aa827923bf4c45e5ee2359573bd863e00f474acd532739f49dcd74a27553882","src/cdsl/operands.rs":"1c3411504de9c83112ff48e0ff1cfbb2e4ba5a9a15c1716f411ef31a4df59899","src/cdsl/recipes.rs":"80b7cd87332229b569e38086ceee8d557e679b9a32ad2e50bdb15c33337c3418","src/cdsl/regs.rs":"05f93ab8504ee82d7cc9811a5b40e5cd004c327577b4c0b3dd957fc422f3c013","src/cdsl/settings.rs":"e6fd9a31925743b93b11f09c9c8271bab6aa2430aa053a2601957b4487df7d77","src/cdsl/type_inference.rs":"1efca8a095ffc899b7527bda6b9d9378c73d7283f8dceaa4819e8af599f8be21","src/cdsl/types.rs":"763cb82b1d8ceb6be682ed6c71c8c98cab686151d177aad6d8f8ef92a37c5639","src/cdsl/typevar.rs":"52f7242a35805a82baf2c788c3eb392e2fba0fcbf47f047f32eba81f34487c7e","src/cdsl/xform.rs":"55da0c3f2403147b535ab6ae5d69c623fbe839edecf2a3af1de84420cd58402d","src/default_map.rs":"101bb0282a124f9c921f6bd095f529e8753621450d783c3273b0b0394c2c5c03","src/error.rs":"e9b11b2feb2d867b94c8810fdc5a6c4e0d9131604a0bfa5340ff2639a55100b4","src/gen_binemit.rs":"515e243420b30d1e01f8ea630282d9b6d78a715e1951f3f20392e19a48164442","src/gen_encodings.rs":"f00cded6b68a9b48c9e3cd39a8b6f0ba136f4062c8f8666109158a72c62c3ed1","src/gen_inst.rs":"fac99641622591c0529c0ef789dd83290a624fc674c91a959f426696f82044de","src/gen_legalizer.rs":"7a68c2b9fd77b6420ecb10539d9af0520374e4f2e30d5a345d98dafde157e6bd","src/gen_registers.rs":"3628949229c1cb5179ec5f655b9a1ddd0504ba74ffb9fb23741c85c9154b696f","src/gen_settings.rs":"f3cc3d31f6cc898f30606caf084f0de220db2d3b1b5e5e4145fa7c9a9a1597e2","src/gen_types.rs":"f6c090e1646a43bf2fe81ae0a7029cc6f7dc6d43285368f56d86c35a21c469a6","src/isa/arm32/mod.rs":"8e09ec1b3caf2d22dce8517b37c356047bfce9a6dea712467d867ed05c4bedaf","src/isa/arm64/mod.rs":"b01f030925d3f2af37d7df1b4a800eb7f0d24f74a46e9154fd8b6752643eb2d5","src/isa/mod.rs":"136141f99f217ba42b9e3f7f47238ab19cc974bb3bef2e2df7f7b5a683989d46","src/isa/riscv/encodings.rs":"8abb1968d917588bc5fc5f5be6dd66bdec23ac456ba65f8138237c8e891e843c","src/isa/riscv/mod.rs":"a7b461a30bbfbc1e3b33645422ff40d5b1761c30cb5d4a8aa12e9a3b7f7aee51","src/isa/riscv/recipes.rs":"c9424cffed54cc4d328879a4613b9f6a2c2b7cde7e6e17b4fccd5f661aaf92f2","src/isa/x86/encodings.rs":"ddb3b4c6f9b742ac5fb67136acd60062e16cdffb4dbdd2a309c2155feb63e23d","src/isa/x86/instructions.rs":"e4a92f2b707e0a9af0317041eb9a8bc58a8bedcdbbe35f54dcfaf05699a50675","src/isa/x86/legalize.rs":"fca4a2729fbefded71effb7517c63a3da3648f8ab68968ef014cfc5d5f631cc7","src/isa/x86/mod.rs":"49f0bc05898d1d8565e692ec2550855de15fd6cffa3b5b6e0f8d502cd813e306","src/isa/x86/opcodes.rs":"643bae64cd4050814adfb856046cf650979bec5d251a9d9a6e11bafb5a603c43","src/isa/x86/recipes.rs":"02cff98d27e852410bea7fb035510f78b15e77d133f745d4f052dbbc54a32e44","src/isa/x86/registers.rs":"e24c9487f4c257b1089dac6bca0106cc673db77292cd000ca8e0c7e0d0103f63","src/isa/x86/settings.rs":"9087cd57da2852b689bddc296639f9b9e1caa30e8185798891079da8d9340b53","src/lib.rs":"2491b0e74078914cb89d1778fa8174daf723fe76aaf7fed18741237d68f6df32","src/shared/entities.rs":"911b396da11188bd510de004956596f150e27540edd351c74028f99f5f3c79c5","src/shared/formats.rs":"d8cf211c392ec3c54d0101ef31b700c3222bc8e80b69a04b244953e449770336","src/shared/immediates.rs":"e4a57657f6af9853794804eb41c01204a2c13a632f44f55d90e156a4b98c5f65","src/shared/instructions.rs":"3eaa255634ae32a653fa16be82573d6a5912c766ce92589f13b81867b774a74e","src/shared/legalize.rs":"73e1b42743c324104f5a34120e1598146ce4ee7393137ecb5391b768c61f2605","src/shared/mod.rs":"bc497c14d083c29eefe4935cff9cd1bd138c071bc50f787248727a3858dc69f3","src/shared/settings.rs":"cda96c9599d49b82e5cd43c7d0fd53a197fa8dadcc56dc33566ac47fdd6da607","src/shared/types.rs":"4702df132f4b5d70cc9411ec5221ba0b1bd4479252274e0223ae57b6d0331247","src/srcgen.rs":"dcfc159c8599270f17e6a978c4be255abca51556b5ef0da497faec4a4a1e62ce","src/unique_table.rs":"31aa54330ca4786af772d32e8cb6158b6504b88fa93fe177bf0c6cbe545a8d35"},"package":null}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "cranelift-codegen-meta"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "Metaprogram for cranelift-codegen code generator library"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
|
@ -9,8 +9,8 @@ readme = "README.md"
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen-shared = { path = "../shared", version = "0.51.0" }
|
||||
cranelift-entity = { path = "../../cranelift-entity", version = "0.51.0" }
|
||||
cranelift-codegen-shared = { path = "../shared", version = "0.55.0" }
|
||||
cranelift-entity = { path = "../../cranelift-entity", version = "0.55.0" }
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
|
|
@ -172,7 +172,7 @@ pub(crate) struct EncodingRecipeBuilder {
|
|||
pub base_size: u64,
|
||||
pub operands_in: Option<Vec<OperandConstraint>>,
|
||||
pub operands_out: Option<Vec<OperandConstraint>>,
|
||||
compute_size: Option<&'static str>,
|
||||
pub compute_size: Option<&'static str>,
|
||||
pub branch_range: Option<BranchRange>,
|
||||
pub emit: Option<String>,
|
||||
clobbers_flags: Option<bool>,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -40,7 +40,6 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
let fmax = insts.by_name("fmax");
|
||||
let fmin = insts.by_name("fmin");
|
||||
let fneg = insts.by_name("fneg");
|
||||
let fsub = insts.by_name("fsub");
|
||||
let iadd = insts.by_name("iadd");
|
||||
let icmp = insts.by_name("icmp");
|
||||
let iconst = insts.by_name("iconst");
|
||||
|
@ -48,6 +47,7 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
let ineg = insts.by_name("ineg");
|
||||
let insertlane = insts.by_name("insertlane");
|
||||
let ishl = insts.by_name("ishl");
|
||||
let ishl_imm = insts.by_name("ishl_imm");
|
||||
let isub = insts.by_name("isub");
|
||||
let popcnt = insts.by_name("popcnt");
|
||||
let raw_bitcast = insts.by_name("raw_bitcast");
|
||||
|
@ -335,6 +335,7 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
let uimm8_zero = Literal::constant(&imm.uimm8, 0x00);
|
||||
let uimm8_one = Literal::constant(&imm.uimm8, 0x01);
|
||||
let u128_zeroes = constant(vec![0x00; 16]);
|
||||
let u128_ones = constant(vec![0xff; 16]);
|
||||
let b = var("b");
|
||||
let c = var("c");
|
||||
let d = var("d");
|
||||
|
@ -405,12 +406,11 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
}
|
||||
|
||||
// SIMD bnot
|
||||
let ones = constant(vec![0xff; 16]);
|
||||
for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
|
||||
let bnot = bnot.bind(vector(ty, sse_vector_size));
|
||||
narrow.legalize(
|
||||
def!(y = bnot(x)),
|
||||
vec![def!(a = vconst(ones)), def!(y = bxor(a, x))],
|
||||
vec![def!(a = vconst(u128_ones)), def!(y = bxor(a, x))],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -524,7 +524,11 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
let icmp_ = icmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(
|
||||
def!(c = icmp_(ugt, a, b)),
|
||||
vec![def!(x = x86_pmaxu(a, b)), def!(c = icmp(eq, a, x))],
|
||||
vec![
|
||||
def!(x = x86_pmaxu(a, b)),
|
||||
def!(y = icmp(eq, x, b)),
|
||||
def!(c = bnot(y)),
|
||||
],
|
||||
);
|
||||
let icmp_ = icmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(
|
||||
|
@ -548,11 +552,40 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
narrow.legalize(def!(c = icmp_(ule, a, b)), vec![def!(c = icmp(uge, b, a))]);
|
||||
}
|
||||
|
||||
// SIMD fcmp greater-/less-than
|
||||
let gt = Literal::enumerator_for(&imm.floatcc, "gt");
|
||||
let lt = Literal::enumerator_for(&imm.floatcc, "lt");
|
||||
let ge = Literal::enumerator_for(&imm.floatcc, "ge");
|
||||
let le = Literal::enumerator_for(&imm.floatcc, "le");
|
||||
let ugt = Literal::enumerator_for(&imm.floatcc, "ugt");
|
||||
let ult = Literal::enumerator_for(&imm.floatcc, "ult");
|
||||
let uge = Literal::enumerator_for(&imm.floatcc, "uge");
|
||||
let ule = Literal::enumerator_for(&imm.floatcc, "ule");
|
||||
for ty in &[F32, F64] {
|
||||
let fcmp_ = fcmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(def!(c = fcmp_(gt, a, b)), vec![def!(c = fcmp(lt, b, a))]);
|
||||
let fcmp_ = fcmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(def!(c = fcmp_(ge, a, b)), vec![def!(c = fcmp(le, b, a))]);
|
||||
let fcmp_ = fcmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(def!(c = fcmp_(ult, a, b)), vec![def!(c = fcmp(ugt, b, a))]);
|
||||
let fcmp_ = fcmp.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(def!(c = fcmp_(ule, a, b)), vec![def!(c = fcmp(uge, b, a))]);
|
||||
}
|
||||
|
||||
for ty in &[F32, F64] {
|
||||
let fneg = fneg.bind(vector(*ty, sse_vector_size));
|
||||
let lane_type_as_int = LaneType::int_from_bits(LaneType::from(*ty).lane_bits() as u16);
|
||||
let uimm8_shift = Literal::constant(&imm.uimm8, lane_type_as_int.lane_bits() as i64 - 1);
|
||||
let vconst = vconst.bind(vector(lane_type_as_int, sse_vector_size));
|
||||
let bitcast_to_float = raw_bitcast.bind(vector(*ty, sse_vector_size));
|
||||
narrow.legalize(
|
||||
def!(b = fneg(a)),
|
||||
vec![def!(c = vconst(u128_zeroes)), def!(b = fsub(c, a))],
|
||||
vec![
|
||||
def!(c = vconst(u128_ones)),
|
||||
def!(d = ishl_imm(c, uimm8_shift)), // Create a mask of all 0s except the MSB.
|
||||
def!(e = bitcast_to_float(d)), // Cast mask to the floating-point type.
|
||||
def!(b = bxor(a, e)), // Flip the MSB.
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -565,7 +598,7 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
|
|||
narrow.legalize(
|
||||
def!(b = fabs(a)),
|
||||
vec![
|
||||
def!(c = vconst(ones)),
|
||||
def!(c = vconst(u128_ones)),
|
||||
def!(d = ushr_imm(c, uimm8_one)), // Create a mask of all 1s except the MSB.
|
||||
def!(e = bitcast_to_float(d)), // Cast mask to the floating-point type.
|
||||
def!(b = band(a, e)), // Unset the MSB.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -59,16 +59,16 @@ pub(crate) fn define(shared: &SettingGroup) -> SettingGroup {
|
|||
// back in the shared SettingGroup, and use it in x86 instruction predicates.
|
||||
|
||||
let is_pic = shared.get_bool("is_pic");
|
||||
let allones_funcaddrs = shared.get_bool("allones_funcaddrs");
|
||||
let emit_all_ones_funcaddrs = shared.get_bool("emit_all_ones_funcaddrs");
|
||||
settings.add_predicate("is_pic", predicate!(is_pic));
|
||||
settings.add_predicate("not_is_pic", predicate!(!is_pic));
|
||||
settings.add_predicate(
|
||||
"all_ones_funcaddrs_and_not_is_pic",
|
||||
predicate!(allones_funcaddrs && !is_pic),
|
||||
predicate!(emit_all_ones_funcaddrs && !is_pic),
|
||||
);
|
||||
settings.add_predicate(
|
||||
"not_all_ones_funcaddrs_and_not_is_pic",
|
||||
predicate!(!allones_funcaddrs && !is_pic),
|
||||
predicate!(!emit_all_ones_funcaddrs && !is_pic),
|
||||
);
|
||||
|
||||
// Presets corresponding to x86 CPUs.
|
||||
|
|
|
@ -11,6 +11,476 @@ use crate::shared::formats::Formats;
|
|||
use crate::shared::types;
|
||||
use crate::shared::{entities::EntityRefs, immediates::Immediates};
|
||||
|
||||
#[inline(never)]
|
||||
fn define_control_flow(
|
||||
ig: &mut InstructionGroupBuilder,
|
||||
formats: &Formats,
|
||||
imm: &Immediates,
|
||||
entities: &EntityRefs,
|
||||
) {
|
||||
let EBB = &Operand::new("EBB", &entities.ebb).with_doc("Destination extended basic block");
|
||||
let args = &Operand::new("args", &entities.varargs).with_doc("EBB arguments");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump",
|
||||
r#"
|
||||
Jump.
|
||||
|
||||
Unconditionally jump to an extended basic block, passing the specified
|
||||
EBB arguments. The number and types of arguments must match the
|
||||
destination EBB.
|
||||
"#,
|
||||
&formats.jump,
|
||||
)
|
||||
.operands_in(vec![EBB, args])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"fallthrough",
|
||||
r#"
|
||||
Fall through to the next EBB.
|
||||
|
||||
This is the same as `jump`, except the destination EBB must be
|
||||
the next one in the layout.
|
||||
|
||||
Jumps are turned into fall-through instructions by the branch
|
||||
relaxation pass. There is no reason to use this instruction outside
|
||||
that pass.
|
||||
"#,
|
||||
&formats.jump,
|
||||
)
|
||||
.operands_in(vec![EBB, args])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
let Testable = &TypeVar::new(
|
||||
"Testable",
|
||||
"A scalar boolean or integer type",
|
||||
TypeSetBuilder::new()
|
||||
.ints(Interval::All)
|
||||
.bools(Interval::All)
|
||||
.build(),
|
||||
);
|
||||
|
||||
{
|
||||
let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brz",
|
||||
r#"
|
||||
Branch when zero.
|
||||
|
||||
If ``c`` is a `b1` value, take the branch when ``c`` is false. If
|
||||
``c`` is an integer value, take the branch when ``c = 0``.
|
||||
"#,
|
||||
&formats.branch,
|
||||
)
|
||||
.operands_in(vec![c, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brnz",
|
||||
r#"
|
||||
Branch when non-zero.
|
||||
|
||||
If ``c`` is a `b1` value, take the branch when ``c`` is true. If
|
||||
``c`` is an integer value, take the branch when ``c != 0``.
|
||||
"#,
|
||||
&formats.branch,
|
||||
)
|
||||
.operands_in(vec![c, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
let iB = &TypeVar::new(
|
||||
"iB",
|
||||
"A scalar integer type",
|
||||
TypeSetBuilder::new().ints(Interval::All).build(),
|
||||
);
|
||||
let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
|
||||
let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into();
|
||||
|
||||
{
|
||||
let Cond = &Operand::new("Cond", &imm.intcc);
|
||||
let x = &Operand::new("x", iB);
|
||||
let y = &Operand::new("y", iB);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"br_icmp",
|
||||
r#"
|
||||
Compare scalar integers and branch.
|
||||
|
||||
Compare ``x`` and ``y`` in the same way as the `icmp` instruction
|
||||
and take the branch if the condition is true:
|
||||
|
||||
```text
|
||||
br_icmp ugt v1, v2, ebb4(v5, v6)
|
||||
```
|
||||
|
||||
is semantically equivalent to:
|
||||
|
||||
```text
|
||||
v10 = icmp ugt, v1, v2
|
||||
brnz v10, ebb4(v5, v6)
|
||||
```
|
||||
|
||||
Some RISC architectures like MIPS and RISC-V provide instructions that
|
||||
implement all or some of the condition codes. The instruction can also
|
||||
be used to represent *macro-op fusion* on architectures like Intel's.
|
||||
"#,
|
||||
&formats.branch_icmp,
|
||||
)
|
||||
.operands_in(vec![Cond, x, y, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
let f = &Operand::new("f", iflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brif",
|
||||
r#"
|
||||
Branch when condition is true in integer CPU flags.
|
||||
"#,
|
||||
&formats.branch_int,
|
||||
)
|
||||
.operands_in(vec![Cond, f, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let Cond = &Operand::new("Cond", &imm.floatcc);
|
||||
|
||||
let f = &Operand::new("f", fflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brff",
|
||||
r#"
|
||||
Branch when condition is true in floating point CPU flags.
|
||||
"#,
|
||||
&formats.branch_float,
|
||||
)
|
||||
.operands_in(vec![Cond, f, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let x = &Operand::new("x", iB).with_doc("index into jump table");
|
||||
let JT = &Operand::new("JT", &entities.jump_table);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"br_table",
|
||||
r#"
|
||||
Indirect branch via jump table.
|
||||
|
||||
Use ``x`` as an unsigned index into the jump table ``JT``. If a jump
|
||||
table entry is found, branch to the corresponding EBB. If no entry was
|
||||
found or the index is out-of-bounds, branch to the given default EBB.
|
||||
|
||||
Note that this branch instruction can't pass arguments to the targeted
|
||||
blocks. Split critical edges as needed to work around this.
|
||||
|
||||
Do not confuse this with "tables" in WebAssembly. ``br_table`` is for
|
||||
jump tables with destinations within the current function only -- think
|
||||
of a ``match`` in Rust or a ``switch`` in C. If you want to call a
|
||||
function in a dynamic library, that will typically use
|
||||
``call_indirect``.
|
||||
"#,
|
||||
&formats.branch_table,
|
||||
)
|
||||
.operands_in(vec![x, EBB, JT])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
let iAddr = &TypeVar::new(
|
||||
"iAddr",
|
||||
"An integer address type",
|
||||
TypeSetBuilder::new().ints(32..64).build(),
|
||||
);
|
||||
|
||||
{
|
||||
let x = &Operand::new("x", iAddr).with_doc("index into jump table");
|
||||
let addr = &Operand::new("addr", iAddr);
|
||||
let Size = &Operand::new("Size", &imm.uimm8).with_doc("Size in bytes");
|
||||
let JT = &Operand::new("JT", &entities.jump_table);
|
||||
let entry = &Operand::new("entry", iAddr).with_doc("entry of jump table");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump_table_entry",
|
||||
r#"
|
||||
Get an entry from a jump table.
|
||||
|
||||
Load a serialized ``entry`` from a jump table ``JT`` at a given index
|
||||
``addr`` with a specific ``Size``. The retrieved entry may need to be
|
||||
decoded after loading, depending upon the jump table type used.
|
||||
|
||||
Currently, the only type supported is entries which are relative to the
|
||||
base of the jump table.
|
||||
"#,
|
||||
&formats.branch_table_entry,
|
||||
)
|
||||
.operands_in(vec![x, addr, Size, JT])
|
||||
.operands_out(vec![entry])
|
||||
.can_load(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump_table_base",
|
||||
r#"
|
||||
Get the absolute base address of a jump table.
|
||||
|
||||
This is used for jump tables wherein the entries are stored relative to
|
||||
the base of jump table. In order to use these, generated code should first
|
||||
load an entry using ``jump_table_entry``, then use this instruction to add
|
||||
the relative base back to it.
|
||||
"#,
|
||||
&formats.branch_table_base,
|
||||
)
|
||||
.operands_in(vec![JT])
|
||||
.operands_out(vec![addr]),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"indirect_jump_table_br",
|
||||
r#"
|
||||
Branch indirectly via a jump table entry.
|
||||
|
||||
Unconditionally jump via a jump table entry that was previously loaded
|
||||
with the ``jump_table_entry`` instruction.
|
||||
"#,
|
||||
&formats.indirect_jump,
|
||||
)
|
||||
.operands_in(vec![addr, JT])
|
||||
.is_indirect_branch(true)
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"debugtrap",
|
||||
r#"
|
||||
Encodes an assembly debug trap.
|
||||
"#,
|
||||
&formats.nullary,
|
||||
)
|
||||
.other_side_effects(true)
|
||||
.can_load(true)
|
||||
.can_store(true),
|
||||
);
|
||||
|
||||
{
|
||||
let code = &Operand::new("code", &imm.trapcode);
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trap",
|
||||
r#"
|
||||
Terminate execution unconditionally.
|
||||
"#,
|
||||
&formats.trap,
|
||||
)
|
||||
.operands_in(vec![code])
|
||||
.can_trap(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapz",
|
||||
r#"
|
||||
Trap when zero.
|
||||
|
||||
if ``c`` is non-zero, execution continues at the following instruction.
|
||||
"#,
|
||||
&formats.cond_trap,
|
||||
)
|
||||
.operands_in(vec![c, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"resumable_trap",
|
||||
r#"
|
||||
A resumable trap.
|
||||
|
||||
This instruction allows non-conditional traps to be used as non-terminal instructions.
|
||||
"#,
|
||||
&formats.trap,
|
||||
)
|
||||
.operands_in(vec![code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapnz",
|
||||
r#"
|
||||
Trap when non-zero.
|
||||
|
||||
if ``c`` is zero, execution continues at the following instruction.
|
||||
"#,
|
||||
&formats.cond_trap,
|
||||
)
|
||||
.operands_in(vec![c, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let Cond = &Operand::new("Cond", &imm.intcc);
|
||||
let f = &Operand::new("f", iflags);
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapif",
|
||||
r#"
|
||||
Trap when condition is true in integer CPU flags.
|
||||
"#,
|
||||
&formats.int_cond_trap,
|
||||
)
|
||||
.operands_in(vec![Cond, f, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let Cond = &Operand::new("Cond", &imm.floatcc);
|
||||
let f = &Operand::new("f", fflags);
|
||||
let code = &Operand::new("code", &imm.trapcode);
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapff",
|
||||
r#"
|
||||
Trap when condition is true in floating point CPU flags.
|
||||
"#,
|
||||
&formats.float_cond_trap,
|
||||
)
|
||||
.operands_in(vec![Cond, f, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
}
|
||||
|
||||
let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"return",
|
||||
r#"
|
||||
Return from the function.
|
||||
|
||||
Unconditionally transfer control to the calling function, passing the
|
||||
provided return values. The list of return values must match the
|
||||
function signature's return types.
|
||||
"#,
|
||||
&formats.multiary,
|
||||
)
|
||||
.operands_in(vec![rvals])
|
||||
.is_return(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"fallthrough_return",
|
||||
r#"
|
||||
Return from the function by fallthrough.
|
||||
|
||||
This is a specialized instruction for use where one wants to append
|
||||
a custom epilogue, which will then perform the real return. This
|
||||
instruction has no encoding.
|
||||
"#,
|
||||
&formats.multiary,
|
||||
)
|
||||
.operands_in(vec![rvals])
|
||||
.is_return(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
let FN = &Operand::new("FN", &entities.func_ref)
|
||||
.with_doc("function to call, declared by `function`");
|
||||
let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
|
||||
let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"call",
|
||||
r#"
|
||||
Direct function call.
|
||||
|
||||
Call a function which has been declared in the preamble. The argument
|
||||
types must match the function's signature.
|
||||
"#,
|
||||
&formats.call,
|
||||
)
|
||||
.operands_in(vec![FN, args])
|
||||
.operands_out(vec![rvals])
|
||||
.is_call(true),
|
||||
);
|
||||
|
||||
let SIG = &Operand::new("SIG", &entities.sig_ref).with_doc("function signature");
|
||||
let callee = &Operand::new("callee", iAddr).with_doc("address of function to call");
|
||||
let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
|
||||
let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"call_indirect",
|
||||
r#"
|
||||
Indirect function call.
|
||||
|
||||
Call the function pointed to by `callee` with the given arguments. The
|
||||
called function must match the specified signature.
|
||||
|
||||
Note that this is different from WebAssembly's ``call_indirect``; the
|
||||
callee is a native address, rather than a table index. For WebAssembly,
|
||||
`table_addr` and `load` are used to obtain a native address
|
||||
from a table.
|
||||
"#,
|
||||
&formats.call_indirect,
|
||||
)
|
||||
.operands_in(vec![SIG, callee, args])
|
||||
.operands_out(vec![rvals])
|
||||
.is_call(true),
|
||||
);
|
||||
|
||||
let FN = &Operand::new("FN", &entities.func_ref)
|
||||
.with_doc("function to call, declared by `function`");
|
||||
let addr = &Operand::new("addr", iAddr);
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"func_addr",
|
||||
r#"
|
||||
Get the address of a function.
|
||||
|
||||
Compute the absolute address of a function declared in the preamble.
|
||||
The returned address can be used as a ``callee`` argument to
|
||||
`call_indirect`. This is also a method for calling functions that
|
||||
are too far away to be addressable by a direct `call`
|
||||
instruction.
|
||||
"#,
|
||||
&formats.func_addr,
|
||||
)
|
||||
.operands_in(vec![FN])
|
||||
.operands_out(vec![addr]),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub(crate) fn define(
|
||||
all_instructions: &mut AllInstructions,
|
||||
|
@ -20,6 +490,8 @@ pub(crate) fn define(
|
|||
) -> InstructionGroup {
|
||||
let mut ig = InstructionGroupBuilder::new(all_instructions);
|
||||
|
||||
define_control_flow(&mut ig, formats, imm, entities);
|
||||
|
||||
// Operand kind shorthands.
|
||||
let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
|
||||
let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into();
|
||||
|
@ -114,426 +586,6 @@ pub(crate) fn define(
|
|||
let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());
|
||||
|
||||
let addr = &Operand::new("addr", iAddr);
|
||||
let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
|
||||
let Cond = &Operand::new("Cond", &imm.intcc);
|
||||
let x = &Operand::new("x", iB);
|
||||
let y = &Operand::new("y", iB);
|
||||
let EBB = &Operand::new("EBB", &entities.ebb).with_doc("Destination extended basic block");
|
||||
let args = &Operand::new("args", &entities.varargs).with_doc("EBB arguments");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump",
|
||||
r#"
|
||||
Jump.
|
||||
|
||||
Unconditionally jump to an extended basic block, passing the specified
|
||||
EBB arguments. The number and types of arguments must match the
|
||||
destination EBB.
|
||||
"#,
|
||||
&formats.jump,
|
||||
)
|
||||
.operands_in(vec![EBB, args])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"fallthrough",
|
||||
r#"
|
||||
Fall through to the next EBB.
|
||||
|
||||
This is the same as `jump`, except the destination EBB must be
|
||||
the next one in the layout.
|
||||
|
||||
Jumps are turned into fall-through instructions by the branch
|
||||
relaxation pass. There is no reason to use this instruction outside
|
||||
that pass.
|
||||
"#,
|
||||
&formats.jump,
|
||||
)
|
||||
.operands_in(vec![EBB, args])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brz",
|
||||
r#"
|
||||
Branch when zero.
|
||||
|
||||
If ``c`` is a `b1` value, take the branch when ``c`` is false. If
|
||||
``c`` is an integer value, take the branch when ``c = 0``.
|
||||
"#,
|
||||
&formats.branch,
|
||||
)
|
||||
.operands_in(vec![c, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brnz",
|
||||
r#"
|
||||
Branch when non-zero.
|
||||
|
||||
If ``c`` is a `b1` value, take the branch when ``c`` is true. If
|
||||
``c`` is an integer value, take the branch when ``c != 0``.
|
||||
"#,
|
||||
&formats.branch,
|
||||
)
|
||||
.operands_in(vec![c, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"br_icmp",
|
||||
r#"
|
||||
Compare scalar integers and branch.
|
||||
|
||||
Compare ``x`` and ``y`` in the same way as the `icmp` instruction
|
||||
and take the branch if the condition is true:
|
||||
|
||||
```text
|
||||
br_icmp ugt v1, v2, ebb4(v5, v6)
|
||||
```
|
||||
|
||||
is semantically equivalent to:
|
||||
|
||||
```text
|
||||
v10 = icmp ugt, v1, v2
|
||||
brnz v10, ebb4(v5, v6)
|
||||
```
|
||||
|
||||
Some RISC architectures like MIPS and RISC-V provide instructions that
|
||||
implement all or some of the condition codes. The instruction can also
|
||||
be used to represent *macro-op fusion* on architectures like Intel's.
|
||||
"#,
|
||||
&formats.branch_icmp,
|
||||
)
|
||||
.operands_in(vec![Cond, x, y, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
let f = &Operand::new("f", iflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brif",
|
||||
r#"
|
||||
Branch when condition is true in integer CPU flags.
|
||||
"#,
|
||||
&formats.branch_int,
|
||||
)
|
||||
.operands_in(vec![Cond, f, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
let Cond = &Operand::new("Cond", &imm.floatcc);
|
||||
let f = &Operand::new("f", fflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brff",
|
||||
r#"
|
||||
Branch when condition is true in floating point CPU flags.
|
||||
"#,
|
||||
&formats.branch_float,
|
||||
)
|
||||
.operands_in(vec![Cond, f, EBB, args])
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
// The index into the br_table can be any type; legalizer will convert it to the right type.
|
||||
let x = &Operand::new("x", iB).with_doc("index into jump table");
|
||||
let entry = &Operand::new("entry", iAddr).with_doc("entry of jump table");
|
||||
let JT = &Operand::new("JT", &entities.jump_table);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"br_table",
|
||||
r#"
|
||||
Indirect branch via jump table.
|
||||
|
||||
Use ``x`` as an unsigned index into the jump table ``JT``. If a jump
|
||||
table entry is found, branch to the corresponding EBB. If no entry was
|
||||
found or the index is out-of-bounds, branch to the given default EBB.
|
||||
|
||||
Note that this branch instruction can't pass arguments to the targeted
|
||||
blocks. Split critical edges as needed to work around this.
|
||||
|
||||
Do not confuse this with "tables" in WebAssembly. ``br_table`` is for
|
||||
jump tables with destinations within the current function only -- think
|
||||
of a ``match`` in Rust or a ``switch`` in C. If you want to call a
|
||||
function in a dynamic library, that will typically use
|
||||
``call_indirect``.
|
||||
"#,
|
||||
&formats.branch_table,
|
||||
)
|
||||
.operands_in(vec![x, EBB, JT])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
// These are the instructions which br_table legalizes to: they perform address computations,
|
||||
// using pointer-sized integers, so their type variables are more constrained.
|
||||
let x = &Operand::new("x", iAddr).with_doc("index into jump table");
|
||||
let Size = &Operand::new("Size", &imm.uimm8).with_doc("Size in bytes");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump_table_entry",
|
||||
r#"
|
||||
Get an entry from a jump table.
|
||||
|
||||
Load a serialized ``entry`` from a jump table ``JT`` at a given index
|
||||
``addr`` with a specific ``Size``. The retrieved entry may need to be
|
||||
decoded after loading, depending upon the jump table type used.
|
||||
|
||||
Currently, the only type supported is entries which are relative to the
|
||||
base of the jump table.
|
||||
"#,
|
||||
&formats.branch_table_entry,
|
||||
)
|
||||
.operands_in(vec![x, addr, Size, JT])
|
||||
.operands_out(vec![entry])
|
||||
.can_load(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"jump_table_base",
|
||||
r#"
|
||||
Get the absolute base address of a jump table.
|
||||
|
||||
This is used for jump tables wherein the entries are stored relative to
|
||||
the base of jump table. In order to use these, generated code should first
|
||||
load an entry using ``jump_table_entry``, then use this instruction to add
|
||||
the relative base back to it.
|
||||
"#,
|
||||
&formats.branch_table_base,
|
||||
)
|
||||
.operands_in(vec![JT])
|
||||
.operands_out(vec![addr]),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"indirect_jump_table_br",
|
||||
r#"
|
||||
Branch indirectly via a jump table entry.
|
||||
|
||||
Unconditionally jump via a jump table entry that was previously loaded
|
||||
with the ``jump_table_entry`` instruction.
|
||||
"#,
|
||||
&formats.indirect_jump,
|
||||
)
|
||||
.operands_in(vec![addr, JT])
|
||||
.is_indirect_branch(true)
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"debugtrap",
|
||||
r#"
|
||||
Encodes an assembly debug trap.
|
||||
"#,
|
||||
&formats.nullary,
|
||||
)
|
||||
.other_side_effects(true)
|
||||
.can_load(true)
|
||||
.can_store(true),
|
||||
);
|
||||
|
||||
let code = &Operand::new("code", &imm.trapcode);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trap",
|
||||
r#"
|
||||
Terminate execution unconditionally.
|
||||
"#,
|
||||
&formats.trap,
|
||||
)
|
||||
.operands_in(vec![code])
|
||||
.can_trap(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapz",
|
||||
r#"
|
||||
Trap when zero.
|
||||
|
||||
if ``c`` is non-zero, execution continues at the following instruction.
|
||||
"#,
|
||||
&formats.cond_trap,
|
||||
)
|
||||
.operands_in(vec![c, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"resumable_trap",
|
||||
r#"
|
||||
A resumable trap.
|
||||
|
||||
This instruction allows non-conditional traps to be used as non-terminal instructions.
|
||||
"#,
|
||||
&formats.trap,
|
||||
)
|
||||
.operands_in(vec![code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapnz",
|
||||
r#"
|
||||
Trap when non-zero.
|
||||
|
||||
if ``c`` is zero, execution continues at the following instruction.
|
||||
"#,
|
||||
&formats.cond_trap,
|
||||
)
|
||||
.operands_in(vec![c, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let Cond = &Operand::new("Cond", &imm.intcc);
|
||||
let f = &Operand::new("f", iflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapif",
|
||||
r#"
|
||||
Trap when condition is true in integer CPU flags.
|
||||
"#,
|
||||
&formats.int_cond_trap,
|
||||
)
|
||||
.operands_in(vec![Cond, f, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let Cond = &Operand::new("Cond", &imm.floatcc);
|
||||
let f = &Operand::new("f", fflags);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"trapff",
|
||||
r#"
|
||||
Trap when condition is true in floating point CPU flags.
|
||||
"#,
|
||||
&formats.float_cond_trap,
|
||||
)
|
||||
.operands_in(vec![Cond, f, code])
|
||||
.can_trap(true),
|
||||
);
|
||||
|
||||
let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"return",
|
||||
r#"
|
||||
Return from the function.
|
||||
|
||||
Unconditionally transfer control to the calling function, passing the
|
||||
provided return values. The list of return values must match the
|
||||
function signature's return types.
|
||||
"#,
|
||||
&formats.multiary,
|
||||
)
|
||||
.operands_in(vec![rvals])
|
||||
.is_return(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"fallthrough_return",
|
||||
r#"
|
||||
Return from the function by fallthrough.
|
||||
|
||||
This is a specialized instruction for use where one wants to append
|
||||
a custom epilogue, which will then perform the real return. This
|
||||
instruction has no encoding.
|
||||
"#,
|
||||
&formats.multiary,
|
||||
)
|
||||
.operands_in(vec![rvals])
|
||||
.is_return(true)
|
||||
.is_terminator(true),
|
||||
);
|
||||
|
||||
let FN = &Operand::new("FN", &entities.func_ref)
|
||||
.with_doc("function to call, declared by `function`");
|
||||
let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"call",
|
||||
r#"
|
||||
Direct function call.
|
||||
|
||||
Call a function which has been declared in the preamble. The argument
|
||||
types must match the function's signature.
|
||||
"#,
|
||||
&formats.call,
|
||||
)
|
||||
.operands_in(vec![FN, args])
|
||||
.operands_out(vec![rvals])
|
||||
.is_call(true),
|
||||
);
|
||||
|
||||
let SIG = &Operand::new("SIG", &entities.sig_ref).with_doc("function signature");
|
||||
let callee = &Operand::new("callee", iAddr).with_doc("address of function to call");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"call_indirect",
|
||||
r#"
|
||||
Indirect function call.
|
||||
|
||||
Call the function pointed to by `callee` with the given arguments. The
|
||||
called function must match the specified signature.
|
||||
|
||||
Note that this is different from WebAssembly's ``call_indirect``; the
|
||||
callee is a native address, rather than a table index. For WebAssembly,
|
||||
`table_addr` and `load` are used to obtain a native address
|
||||
from a table.
|
||||
"#,
|
||||
&formats.call_indirect,
|
||||
)
|
||||
.operands_in(vec![SIG, callee, args])
|
||||
.operands_out(vec![rvals])
|
||||
.is_call(true),
|
||||
);
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"func_addr",
|
||||
r#"
|
||||
Get the address of a function.
|
||||
|
||||
Compute the absolute address of a function declared in the preamble.
|
||||
The returned address can be used as a ``callee`` argument to
|
||||
`call_indirect`. This is also a method for calling functions that
|
||||
are too far away to be addressable by a direct `call`
|
||||
instruction.
|
||||
"#,
|
||||
&formats.func_addr,
|
||||
)
|
||||
.operands_in(vec![FN])
|
||||
.operands_out(vec![addr]),
|
||||
);
|
||||
|
||||
let SS = &Operand::new("SS", &entities.stack_slot);
|
||||
let Offset = &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address");
|
||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) fn define() -> SettingGroup {
|
|||
);
|
||||
|
||||
settings.add_bool(
|
||||
"colocated_libcalls",
|
||||
"use_colocated_libcalls",
|
||||
r#"
|
||||
Use colocated libcalls.
|
||||
|
||||
|
@ -177,7 +177,7 @@ pub(crate) fn define() -> SettingGroup {
|
|||
// BaldrMonkey requires that not-yet-relocated function addresses be encoded
|
||||
// as all-ones bitpatterns.
|
||||
settings.add_bool(
|
||||
"allones_funcaddrs",
|
||||
"emit_all_ones_funcaddrs",
|
||||
"Emit not-yet-relocated function addresses as all-ones bit patterns.",
|
||||
false,
|
||||
);
|
||||
|
@ -185,7 +185,7 @@ pub(crate) fn define() -> SettingGroup {
|
|||
// Stack probing options.
|
||||
|
||||
settings.add_bool(
|
||||
"probestack_enabled",
|
||||
"enable_probestack",
|
||||
r#"
|
||||
Enable the use of stack probes, for calling conventions which support this
|
||||
functionality.
|
||||
|
@ -218,7 +218,7 @@ pub(crate) fn define() -> SettingGroup {
|
|||
// Jump table options.
|
||||
|
||||
settings.add_bool(
|
||||
"jump_tables_enabled",
|
||||
"enable_jump_tables",
|
||||
"Enable the use of jump tables in generated machine code.",
|
||||
true,
|
||||
);
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"3ccd54d6e48bdc6b58a65e52f139cf8edc2038b6c62aec12be6daab19d61d185","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/condcodes.rs":"b8d433b2217b86e172d25b6c65a3ce0cc8ca221062cad1b28b0c78d2159fbda9","src/constant_hash.rs":"ffc619f45aad62c6fdcb83553a05879691a72e9a0103375b2d6cc12d52cf72d0","src/constants.rs":"fed03a10a6316e06aa174091db6e7d1fbb5f73c82c31193012ec5ab52f1c603a","src/isa/mod.rs":"428a950eca14acbe783899ccb1aecf15027f8cbe205578308ebde203d10535f3","src/isa/x86/encoding_bits.rs":"b180e4319e10f0e1c229cd9a63b5af8bb63be86f8f98cf1aef203355746f51cd","src/isa/x86/mod.rs":"01ef4e4d7437f938badbe2137892183c1ac684da0f68a5bec7e06aad34f43b9b","src/lib.rs":"91f26f998f11fb9cb74d2ec171424e29badd417beef023674850ace57149c656"},"package":null}
|
||||
{"files":{"Cargo.toml":"4bd4ee47249d76fa655edfefd456fee8153b4f11f3fa10120540fefd1005d3f5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/condcodes.rs":"b8d433b2217b86e172d25b6c65a3ce0cc8ca221062cad1b28b0c78d2159fbda9","src/constant_hash.rs":"ffc619f45aad62c6fdcb83553a05879691a72e9a0103375b2d6cc12d52cf72d0","src/constants.rs":"fed03a10a6316e06aa174091db6e7d1fbb5f73c82c31193012ec5ab52f1c603a","src/isa/mod.rs":"428a950eca14acbe783899ccb1aecf15027f8cbe205578308ebde203d10535f3","src/isa/x86/encoding_bits.rs":"7e013fb804b13f9f83a0d517c6f5105856938d08ad378cc44a6fe6a59adef270","src/isa/x86/mod.rs":"01ef4e4d7437f938badbe2137892183c1ac684da0f68a5bec7e06aad34f43b9b","src/lib.rs":"91f26f998f11fb9cb74d2ec171424e29badd417beef023674850ace57149c656"},"package":null}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "For code shared between cranelift-codegen-meta and cranelift-codegen"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
|
|
|
@ -57,6 +57,22 @@ impl EncodingBits {
|
|||
new
|
||||
}
|
||||
|
||||
/// Returns a copy of the EncodingBits with the RRR bits set.
|
||||
#[inline]
|
||||
pub fn with_rrr(mut self, rrr: u8) -> Self {
|
||||
debug_assert_eq!(self.rrr(), 0);
|
||||
self.write(RRR, rrr.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a copy of the EncodingBits with the REX.W bit set.
|
||||
#[inline]
|
||||
pub fn with_rex_w(mut self) -> Self {
|
||||
debug_assert_eq!(self.rex_w(), 0);
|
||||
self.write(REX_W, 1);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the raw bits.
|
||||
#[inline]
|
||||
pub fn bits(self) -> u16 {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "Low-level code generator library"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
@ -13,13 +13,14 @@ build = "build.rs"
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen-shared = { path = "./shared", version = "0.51.0" }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.51.0" }
|
||||
cranelift-bforest = { path = "../cranelift-bforest", version = "0.51.0" }
|
||||
cranelift-codegen-shared = { path = "./shared", version = "0.55.0" }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.55.0" }
|
||||
cranelift-bforest = { path = "../cranelift-bforest", version = "0.55.0" }
|
||||
hashbrown = { version = "0.6", optional = true }
|
||||
target-lexicon = "0.9"
|
||||
target-lexicon = "0.10"
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
serde = { version = "1.0.94", features = ["derive"], optional = true }
|
||||
gimli = { version = "0.19.0", default-features = false, features = ["write"], optional = true }
|
||||
smallvec = { version = "1.0.0" }
|
||||
thiserror = "1.0.4"
|
||||
byteorder = { version = "1.3.2", default-features = false }
|
||||
|
@ -29,10 +30,10 @@ byteorder = { version = "1.3.2", default-features = false }
|
|||
# accomodated in `tests`.
|
||||
|
||||
[build-dependencies]
|
||||
cranelift-codegen-meta = { path = "meta", version = "0.51.0" }
|
||||
cranelift-codegen-meta = { path = "meta", version = "0.55.0" }
|
||||
|
||||
[features]
|
||||
default = ["std", "basic-blocks"]
|
||||
default = ["std", "basic-blocks", "unwind"]
|
||||
|
||||
# The "std" feature enables use of libstd. The "core" feature enables use
|
||||
# of some minimal std-like replacement libraries. At least one of these two
|
||||
|
@ -47,6 +48,9 @@ core = ["hashbrown"]
|
|||
# can significantly increase the size of the library.
|
||||
testing_hooks = []
|
||||
|
||||
# This enables unwind info generation functionality.
|
||||
unwind = ["gimli"]
|
||||
|
||||
# ISA targets for which we should build.
|
||||
# If no ISA targets are explicitly enabled, the ISA target for the host machine is enabled.
|
||||
x86 = []
|
||||
|
|
|
@ -155,6 +155,36 @@ pub trait CodeSink {
|
|||
fn add_stackmap(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa);
|
||||
}
|
||||
|
||||
/// Type of the frame unwind information.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum FrameUnwindKind {
|
||||
/// Windows fastcall unwinding (as in .pdata).
|
||||
Fastcall,
|
||||
/// FDE entry for libunwind (similar to .eh_frame format).
|
||||
Libunwind,
|
||||
}
|
||||
|
||||
/// Offset in frame unwind information buffer.
|
||||
pub type FrameUnwindOffset = usize;
|
||||
|
||||
/// Sink for frame unwind information.
|
||||
pub trait FrameUnwindSink {
|
||||
/// Get the current position.
|
||||
fn len(&self) -> FrameUnwindOffset;
|
||||
|
||||
/// Add bytes to the code section.
|
||||
fn bytes(&mut self, _: &[u8]);
|
||||
|
||||
/// Reserves bytes in the buffer.
|
||||
fn reserve(&mut self, _len: usize) {}
|
||||
|
||||
/// Add a relocation entry.
|
||||
fn reloc(&mut self, _: Reloc, _: FrameUnwindOffset);
|
||||
|
||||
/// Specified offset to main structure.
|
||||
fn set_entry_offset(&mut self, _: FrameUnwindOffset);
|
||||
}
|
||||
|
||||
/// Report a bad encoding error.
|
||||
#[cold]
|
||||
pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
//! single ISA instance.
|
||||
|
||||
use crate::binemit::{
|
||||
relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackmapSink,
|
||||
TrapSink,
|
||||
relax_branches, shrink_instructions, CodeInfo, FrameUnwindKind, FrameUnwindSink,
|
||||
MemoryCodeSink, RelocSink, StackmapSink, TrapSink,
|
||||
};
|
||||
use crate::dce::do_dce;
|
||||
use crate::dominator_tree::DominatorTree;
|
||||
|
@ -201,8 +201,13 @@ impl Context {
|
|||
///
|
||||
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
|
||||
/// This is a no-op if the function has no unwind information.
|
||||
pub fn emit_unwind_info(&self, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
|
||||
isa.emit_unwind_info(&self.func, mem);
|
||||
pub fn emit_unwind_info(
|
||||
&self,
|
||||
isa: &dyn TargetIsa,
|
||||
kind: FrameUnwindKind,
|
||||
sink: &mut dyn FrameUnwindSink,
|
||||
) {
|
||||
isa.emit_unwind_info(&self.func, kind, sink);
|
||||
}
|
||||
|
||||
/// Run the verifier on the function.
|
||||
|
|
|
@ -448,61 +448,6 @@ impl DominatorTree {
|
|||
}
|
||||
}
|
||||
|
||||
impl DominatorTree {
|
||||
/// When splitting an `Ebb` using `Layout::split_ebb`, you can use this method to update
|
||||
/// the dominator tree locally rather than recomputing it.
|
||||
///
|
||||
/// `old_ebb` is the `Ebb` before splitting, and `new_ebb` is the `Ebb` which now contains
|
||||
/// the second half of `old_ebb`. `split_jump_inst` is the terminator jump instruction of
|
||||
/// `old_ebb` that points to `new_ebb`.
|
||||
pub fn recompute_split_ebb(&mut self, old_ebb: Ebb, new_ebb: Ebb, split_jump_inst: Inst) {
|
||||
if !self.is_reachable(old_ebb) {
|
||||
// old_ebb is unreachable, it stays so and new_ebb is unreachable too
|
||||
self.nodes[new_ebb] = Default::default();
|
||||
return;
|
||||
}
|
||||
// We use the RPO comparison on the postorder list so we invert the operands of the
|
||||
// comparison
|
||||
let old_ebb_postorder_index = self
|
||||
.postorder
|
||||
.as_slice()
|
||||
.binary_search_by(|probe| self.rpo_cmp_ebb(old_ebb, *probe))
|
||||
.expect("the old ebb is not declared to the dominator tree");
|
||||
let new_ebb_rpo = self.insert_after_rpo(old_ebb, old_ebb_postorder_index, new_ebb);
|
||||
self.nodes[new_ebb] = DomNode {
|
||||
rpo_number: new_ebb_rpo,
|
||||
idom: Some(split_jump_inst).into(),
|
||||
};
|
||||
}
|
||||
|
||||
// Insert new_ebb just after ebb in the RPO. This function checks
|
||||
// if there is a gap in rpo numbers; if yes it returns the number in the gap and if
|
||||
// not it renumbers.
|
||||
fn insert_after_rpo(&mut self, ebb: Ebb, ebb_postorder_index: usize, new_ebb: Ebb) -> u32 {
|
||||
let ebb_rpo_number = self.nodes[ebb].rpo_number;
|
||||
let inserted_rpo_number = ebb_rpo_number + 1;
|
||||
// If there is no gaps in RPo numbers to insert this new number, we iterate
|
||||
// forward in RPO numbers and backwards in the postorder list of EBBs, renumbering the Ebbs
|
||||
// until we find a gap
|
||||
for (¤t_ebb, current_rpo) in self.postorder[0..ebb_postorder_index]
|
||||
.iter()
|
||||
.rev()
|
||||
.zip(inserted_rpo_number + 1..)
|
||||
{
|
||||
if self.nodes[current_ebb].rpo_number < current_rpo {
|
||||
// There is no gap, we renumber
|
||||
self.nodes[current_ebb].rpo_number = current_rpo;
|
||||
} else {
|
||||
// There is a gap, we stop the renumbering and exit
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: insert in constant time?
|
||||
self.postorder.insert(ebb_postorder_index, new_ebb);
|
||||
inserted_rpo_number
|
||||
}
|
||||
}
|
||||
|
||||
/// Optional pre-order information that can be computed for a dominator tree.
|
||||
///
|
||||
/// This data structure is computed from a `DominatorTree` and provides:
|
||||
|
@ -681,8 +626,6 @@ mod tests {
|
|||
use crate::flowgraph::ControlFlowGraph;
|
||||
use crate::ir::types::*;
|
||||
use crate::ir::{Function, InstBuilder, TrapCode};
|
||||
use crate::settings;
|
||||
use crate::verifier::{verify_context, VerifierErrors};
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
|
@ -886,64 +829,4 @@ mod tests {
|
|||
assert!(!dt.dominates(jmp21, ebb2, &cur.func.layout));
|
||||
assert!(dt.dominates(jmp21, jmp21, &cur.func.layout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn renumbering() {
|
||||
let mut func = Function::new();
|
||||
let entry = func.dfg.make_ebb();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let ebb100 = func.dfg.make_ebb();
|
||||
|
||||
let mut cur = FuncCursor::new(&mut func);
|
||||
|
||||
cur.insert_ebb(entry);
|
||||
cur.ins().jump(ebb0, &[]);
|
||||
|
||||
cur.insert_ebb(ebb0);
|
||||
let cond = cur.ins().iconst(I32, 0);
|
||||
let inst2 = cur.ins().brz(cond, ebb0, &[]);
|
||||
let inst3 = cur.ins().brz(cond, ebb0, &[]);
|
||||
let inst4 = cur.ins().brz(cond, ebb0, &[]);
|
||||
let inst5 = cur.ins().brz(cond, ebb0, &[]);
|
||||
cur.ins().jump(ebb100, &[]);
|
||||
cur.insert_ebb(ebb100);
|
||||
cur.ins().return_(&[]);
|
||||
|
||||
let mut cfg = ControlFlowGraph::with_function(cur.func);
|
||||
let mut dt = DominatorTree::with_function(cur.func, &cfg);
|
||||
|
||||
let ebb1 = cur.func.dfg.make_ebb();
|
||||
cur.func.layout.split_ebb(ebb1, inst2);
|
||||
cur.goto_bottom(ebb0);
|
||||
let middle_jump_inst = cur.ins().jump(ebb1, &[]);
|
||||
|
||||
dt.recompute_split_ebb(ebb0, ebb1, middle_jump_inst);
|
||||
|
||||
let ebb2 = cur.func.dfg.make_ebb();
|
||||
cur.func.layout.split_ebb(ebb2, inst3);
|
||||
cur.goto_bottom(ebb1);
|
||||
let middle_jump_inst = cur.ins().jump(ebb2, &[]);
|
||||
dt.recompute_split_ebb(ebb1, ebb2, middle_jump_inst);
|
||||
|
||||
let ebb3 = cur.func.dfg.make_ebb();
|
||||
cur.func.layout.split_ebb(ebb3, inst4);
|
||||
cur.goto_bottom(ebb2);
|
||||
let middle_jump_inst = cur.ins().jump(ebb3, &[]);
|
||||
dt.recompute_split_ebb(ebb2, ebb3, middle_jump_inst);
|
||||
|
||||
let ebb4 = cur.func.dfg.make_ebb();
|
||||
cur.func.layout.split_ebb(ebb4, inst5);
|
||||
cur.goto_bottom(ebb3);
|
||||
let middle_jump_inst = cur.ins().jump(ebb4, &[]);
|
||||
dt.recompute_split_ebb(ebb3, ebb4, middle_jump_inst);
|
||||
|
||||
cfg.compute(cur.func);
|
||||
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let mut errors = VerifierErrors::default();
|
||||
|
||||
verify_context(cur.func, &cfg, &dt, &flags, &mut errors).unwrap();
|
||||
|
||||
assert!(errors.0.is_empty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::isa::TargetIsa;
|
|||
use crate::packed_option::ReservedValue;
|
||||
use crate::write::write_operands;
|
||||
use crate::HashMap;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use core::iter;
|
||||
use core::mem;
|
||||
|
@ -776,6 +777,14 @@ impl DataFlowGraph {
|
|||
self.ebbs[ebb].params.as_slice(&self.value_lists)
|
||||
}
|
||||
|
||||
/// Get the types of the parameters on `ebb`.
|
||||
pub fn ebb_param_types(&self, ebb: Ebb) -> Vec<Type> {
|
||||
self.ebb_params(ebb)
|
||||
.iter()
|
||||
.map(|&v| self.value_type(v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Append a parameter with type `ty` to `ebb`.
|
||||
pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
|
||||
let param = self.values.next_key();
|
||||
|
|
|
@ -102,6 +102,24 @@ impl Signature {
|
|||
.count()
|
||||
> 1
|
||||
}
|
||||
|
||||
/// Collect the normal parameter types of the signature; see `[ArgumentPurpose::Normal]`.
|
||||
pub fn param_types(&self) -> Vec<Type> {
|
||||
self.params
|
||||
.iter()
|
||||
.filter(|ap| ap.purpose == ArgumentPurpose::Normal)
|
||||
.map(|ap| ap.value_type)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Collect the normal return types of the signature; see `[ArgumentPurpose::Normal]`.
|
||||
pub fn return_types(&self) -> Vec<Type> {
|
||||
self.returns
|
||||
.iter()
|
||||
.filter(|ap| ap.purpose == ArgumentPurpose::Normal)
|
||||
.map(|ap| ap.value_type)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type capable of displaying a `Signature` with correct register names.
|
||||
|
|
|
@ -56,7 +56,7 @@ pub struct FrameLayout {
|
|||
impl FrameLayout {
|
||||
/// Create instance of FrameLayout.
|
||||
pub fn new() -> Self {
|
||||
FrameLayout {
|
||||
Self {
|
||||
initial: vec![].into_boxed_slice(),
|
||||
instructions: HashMap::new(),
|
||||
}
|
||||
|
|
|
@ -253,6 +253,11 @@ impl Function {
|
|||
/// Starts collection of debug information.
|
||||
pub fn collect_debug_info(&mut self) {
|
||||
self.dfg.collect_debug_info();
|
||||
self.collect_frame_layout_info();
|
||||
}
|
||||
|
||||
/// Starts collection of frame layout information.
|
||||
pub fn collect_frame_layout_info(&mut self) {
|
||||
self.frame_layout = Some(FrameLayout::new());
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
|
|||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub enum LibCall {
|
||||
/// probe for stack overflow. These are emitted for functions which need
|
||||
/// when the `probestack_enabled` setting is true.
|
||||
/// when the `enable_probestack` setting is true.
|
||||
Probestack,
|
||||
/// ceil.f32
|
||||
CeilF32,
|
||||
|
@ -202,7 +202,7 @@ fn make_funcref(
|
|||
func.import_function(ExtFuncData {
|
||||
name: ExternalName::LibCall(libcall),
|
||||
signature: sigref,
|
||||
colocated: isa.flags().colocated_libcalls(),
|
||||
colocated: isa.flags().use_colocated_libcalls(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ use crate::settings::SetResult;
|
|||
use crate::timing;
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use target_lexicon::{triple, Architecture, PointerWidth, Triple};
|
||||
use thiserror::Error;
|
||||
|
@ -198,7 +197,7 @@ impl TargetFrontendConfig {
|
|||
|
||||
/// Methods that are specialized to a target ISA. Implies a Display trait that shows the
|
||||
/// shared flags, as well as any isa-specific flags.
|
||||
pub trait TargetIsa: fmt::Display + Sync {
|
||||
pub trait TargetIsa: fmt::Display + Send + Sync {
|
||||
/// Get the name of this ISA.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
|
@ -382,7 +381,12 @@ pub trait TargetIsa: fmt::Display + Sync {
|
|||
/// Emit unwind information for the given function.
|
||||
///
|
||||
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
|
||||
fn emit_unwind_info(&self, _func: &ir::Function, _mem: &mut Vec<u8>) {
|
||||
fn emit_unwind_info(
|
||||
&self,
|
||||
_func: &ir::Function,
|
||||
_kind: binemit::FrameUnwindKind,
|
||||
_sink: &mut dyn binemit::FrameUnwindSink,
|
||||
) {
|
||||
// No-op by default
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
//! x86 ABI implementation.
|
||||
|
||||
use super::super::settings as shared_settings;
|
||||
#[cfg(feature = "unwind")]
|
||||
use super::fde::emit_fde;
|
||||
use super::registers::{FPR, GPR, RU};
|
||||
use super::settings as isa_settings;
|
||||
#[cfg(feature = "unwind")]
|
||||
use super::unwind::UnwindInfo;
|
||||
use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
|
||||
#[cfg(feature = "unwind")]
|
||||
use crate::binemit::{FrameUnwindKind, FrameUnwindSink};
|
||||
use crate::cursor::{Cursor, CursorPosition, EncCursor};
|
||||
use crate::ir;
|
||||
use crate::ir::immediates::Imm64;
|
||||
|
@ -18,7 +23,6 @@ use crate::regalloc::RegisterSet;
|
|||
use crate::result::CodegenResult;
|
||||
use crate::stack_layout::layout_stack;
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::vec::Vec;
|
||||
use core::i32;
|
||||
use std::boxed::Box;
|
||||
use target_lexicon::{PointerWidth, Triple};
|
||||
|
@ -449,7 +453,7 @@ pub fn prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> Codege
|
|||
|
||||
fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
|
||||
debug_assert!(
|
||||
!isa.flags().probestack_enabled(),
|
||||
!isa.flags().enable_probestack(),
|
||||
"baldrdash does not expect cranelift to emit stack probes"
|
||||
);
|
||||
|
||||
|
@ -750,8 +754,7 @@ fn insert_common_prologue(
|
|||
|
||||
// Allocate stack frame storage.
|
||||
if stack_size > 0 {
|
||||
if isa.flags().probestack_enabled()
|
||||
&& stack_size > (1 << isa.flags().probestack_size_log2())
|
||||
if isa.flags().enable_probestack() && stack_size > (1 << isa.flags().probestack_size_log2())
|
||||
{
|
||||
// Emit a stack probe.
|
||||
let rax = RU::rax as RegUnit;
|
||||
|
@ -947,10 +950,25 @@ fn insert_common_epilogue(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn emit_unwind_info(func: &ir::Function, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
|
||||
// Assumption: RBP is being used as the frame pointer
|
||||
// In the future, Windows fastcall codegen should usually omit the frame pointer
|
||||
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
|
||||
info.emit(mem);
|
||||
#[cfg(feature = "unwind")]
|
||||
pub fn emit_unwind_info(
|
||||
func: &ir::Function,
|
||||
isa: &dyn TargetIsa,
|
||||
kind: FrameUnwindKind,
|
||||
sink: &mut dyn FrameUnwindSink,
|
||||
) {
|
||||
match kind {
|
||||
FrameUnwindKind::Fastcall => {
|
||||
// Assumption: RBP is being used as the frame pointer
|
||||
// In the future, Windows fastcall codegen should usually omit the frame pointer
|
||||
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
|
||||
info.emit(sink);
|
||||
}
|
||||
}
|
||||
FrameUnwindKind::Libunwind => {
|
||||
if func.frame_layout.is_some() {
|
||||
emit_fde(func, isa, sink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,12 @@ fn rex3(rm: RegUnit, reg: RegUnit, index: RegUnit) -> u8 {
|
|||
BASE_REX | b | (x << 1) | (r << 2)
|
||||
}
|
||||
|
||||
/// Determines whether a REX prefix should be emitted.
|
||||
#[inline]
|
||||
fn needs_rex(bits: u16, rex: u8) -> bool {
|
||||
rex != BASE_REX || EncodingBits::from(bits).rex_w() == 1
|
||||
}
|
||||
|
||||
// Emit a REX prefix.
|
||||
//
|
||||
// The R, X, and B bits are computed from registers using the functions above. The W bit is
|
||||
|
@ -68,7 +74,7 @@ fn rex3(rm: RegUnit, reg: RegUnit, index: RegUnit) -> u8 {
|
|||
fn rex_prefix<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(rex & 0xf8, BASE_REX);
|
||||
let w = EncodingBits::from(bits).rex_w();
|
||||
sink.put1(rex | (u8::from(w) << 3));
|
||||
sink.put1(rex | (w << 3));
|
||||
}
|
||||
|
||||
// Emit a single-byte opcode with no REX prefix.
|
||||
|
@ -80,11 +86,20 @@ fn put_op1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
|
||||
// Emit a single-byte opcode with REX prefix.
|
||||
fn put_rexop1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for Op1*");
|
||||
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for RexOp1*");
|
||||
rex_prefix(bits, rex, sink);
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
/// Emit a single-byte opcode with inferred REX prefix.
|
||||
fn put_dynrexop1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for DynRexOp1*");
|
||||
if needs_rex(bits, rex) {
|
||||
rex_prefix(bits, rex, sink);
|
||||
}
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Emit two-byte opcode: 0F XX
|
||||
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x8f00, 0x0400, "Invalid encoding bits for Op2*");
|
||||
|
@ -101,6 +116,20 @@ fn put_rexop2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
/// Emit two-byte opcode: 0F XX with inferred REX prefix.
|
||||
fn put_dynrexop2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(
|
||||
bits & 0x0f00,
|
||||
0x0400,
|
||||
"Invalid encoding bits for DynRexOp2*"
|
||||
);
|
||||
if needs_rex(bits, rex) {
|
||||
rex_prefix(bits, rex, sink);
|
||||
}
|
||||
sink.put1(0x0f);
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Emit single-byte opcode with mandatory prefix.
|
||||
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x8c00, 0, "Invalid encoding bits for Mp1*");
|
||||
|
@ -112,7 +141,7 @@ fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
|
||||
// Emit single-byte opcode with mandatory prefix and REX.
|
||||
fn put_rexmp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for Mp1*");
|
||||
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for RexMp1*");
|
||||
let enc = EncodingBits::from(bits);
|
||||
sink.put1(PREFIX[(enc.pp() - 1) as usize]);
|
||||
rex_prefix(bits, rex, sink);
|
||||
|
@ -131,7 +160,7 @@ fn put_mp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
|
||||
// Emit two-byte opcode (0F XX) with mandatory prefix and REX.
|
||||
fn put_rexmp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0c00, 0x0400, "Invalid encoding bits for Mp2*");
|
||||
debug_assert_eq!(bits & 0x0c00, 0x0400, "Invalid encoding bits for RexMp2*");
|
||||
let enc = EncodingBits::from(bits);
|
||||
sink.put1(PREFIX[(enc.pp() - 1) as usize]);
|
||||
rex_prefix(bits, rex, sink);
|
||||
|
@ -139,6 +168,22 @@ fn put_rexmp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
/// Emit two-byte opcode (0F XX) with mandatory prefix and inferred REX.
|
||||
fn put_dynrexmp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(
|
||||
bits & 0x0c00,
|
||||
0x0400,
|
||||
"Invalid encoding bits for DynRexMp2*"
|
||||
);
|
||||
let enc = EncodingBits::from(bits);
|
||||
sink.put1(PREFIX[(enc.pp() - 1) as usize]);
|
||||
if needs_rex(bits, rex) {
|
||||
rex_prefix(bits, rex, sink);
|
||||
}
|
||||
sink.put1(0x0f);
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Emit three-byte opcode (0F 3[8A] XX) with mandatory prefix.
|
||||
fn put_mp3<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x8800, 0x0800, "Invalid encoding bits for Mp3*");
|
||||
|
@ -152,7 +197,7 @@ fn put_mp3<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
|||
|
||||
// Emit three-byte opcode (0F 3[8A] XX) with mandatory prefix and REX
|
||||
fn put_rexmp3<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0800, 0x0800, "Invalid encoding bits for Mp3*");
|
||||
debug_assert_eq!(bits & 0x0800, 0x0800, "Invalid encoding bits for RexMp3*");
|
||||
let enc = EncodingBits::from(bits);
|
||||
sink.put1(PREFIX[(enc.pp() - 1) as usize]);
|
||||
rex_prefix(bits, rex, sink);
|
||||
|
|
|
@ -16,9 +16,20 @@ use crate::isa::{self, TargetIsa};
|
|||
use crate::predicates;
|
||||
use crate::regalloc::RegDiversions;
|
||||
|
||||
use cranelift_codegen_shared::isa::x86::EncodingBits;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/encoding-x86.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/legalize-x86.rs"));
|
||||
|
||||
/// Whether the REX prefix is needed for encoding extended registers (via REX.RXB).
|
||||
///
|
||||
/// Normal x86 instructions have only 3 bits for encoding a register.
|
||||
/// The REX prefix adds REX.R, REX,X, and REX.B bits, interpreted as fourth bits.
|
||||
pub fn is_extended_reg(reg: RegUnit) -> bool {
|
||||
// Extended registers have the fourth bit set.
|
||||
reg as u8 & 0b1000 != 0
|
||||
}
|
||||
|
||||
pub fn needs_sib_byte(reg: RegUnit) -> bool {
|
||||
reg == RU::r12 as RegUnit || reg == RU::rsp as RegUnit
|
||||
}
|
||||
|
@ -29,74 +40,179 @@ pub fn needs_sib_byte_or_offset(reg: RegUnit) -> bool {
|
|||
needs_sib_byte(reg) || needs_offset(reg)
|
||||
}
|
||||
|
||||
fn additional_size_if(
|
||||
fn test_input(
|
||||
op_index: usize,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
condition_func: fn(RegUnit) -> bool,
|
||||
) -> u8 {
|
||||
let addr_reg = divert.reg(func.dfg.inst_args(inst)[op_index], &func.locations);
|
||||
if condition_func(addr_reg) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
) -> bool {
|
||||
let in_reg = divert.reg(func.dfg.inst_args(inst)[op_index], &func.locations);
|
||||
condition_func(in_reg)
|
||||
}
|
||||
|
||||
fn size_plus_maybe_offset_for_in_reg_0(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
fn test_result(
|
||||
result_index: usize,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(0, inst, divert, func, needs_offset)
|
||||
condition_func: fn(RegUnit) -> bool,
|
||||
) -> bool {
|
||||
let out_reg = divert.reg(func.dfg.inst_results(inst)[result_index], &func.locations);
|
||||
condition_func(out_reg)
|
||||
}
|
||||
fn size_plus_maybe_offset_for_in_reg_1(
|
||||
|
||||
fn size_plus_maybe_offset_for_inreg_0(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(1, inst, divert, func, needs_offset)
|
||||
let needs_offset = test_input(0, inst, divert, func, needs_offset);
|
||||
sizing.base_size + if needs_offset { 1 } else { 0 }
|
||||
}
|
||||
fn size_plus_maybe_sib_for_in_reg_0(
|
||||
fn size_plus_maybe_offset_for_inreg_1(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(0, inst, divert, func, needs_sib_byte)
|
||||
let needs_offset = test_input(1, inst, divert, func, needs_offset);
|
||||
sizing.base_size + if needs_offset { 1 } else { 0 }
|
||||
}
|
||||
fn size_plus_maybe_sib_for_in_reg_1(
|
||||
fn size_plus_maybe_sib_for_inreg_0(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(1, inst, divert, func, needs_sib_byte)
|
||||
let needs_sib = test_input(0, inst, divert, func, needs_sib_byte);
|
||||
sizing.base_size + if needs_sib { 1 } else { 0 }
|
||||
}
|
||||
fn size_plus_maybe_sib_or_offset_for_in_reg_0(
|
||||
fn size_plus_maybe_sib_for_inreg_1(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(0, inst, divert, func, needs_sib_byte_or_offset)
|
||||
let needs_sib = test_input(1, inst, divert, func, needs_sib_byte);
|
||||
sizing.base_size + if needs_sib { 1 } else { 0 }
|
||||
}
|
||||
fn size_plus_maybe_sib_or_offset_for_in_reg_1(
|
||||
fn size_plus_maybe_sib_or_offset_for_inreg_0(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(1, inst, divert, func, needs_sib_byte_or_offset)
|
||||
let needs_sib_or_offset = test_input(0, inst, divert, func, needs_sib_byte_or_offset);
|
||||
sizing.base_size + if needs_sib_or_offset { 1 } else { 0 }
|
||||
}
|
||||
fn size_plus_maybe_sib_or_offset_for_inreg_1(
|
||||
sizing: &RecipeSizing,
|
||||
_enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_sib_or_offset = test_input(1, inst, divert, func, needs_sib_byte_or_offset);
|
||||
sizing.base_size + if needs_sib_or_offset { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, for use with one input reg.
|
||||
///
|
||||
/// A REX prefix is known to be emitted if either:
|
||||
/// 1. The EncodingBits specify that REX.W is to be set.
|
||||
/// 2. Registers are used that require REX.R or REX.B bits for encoding.
|
||||
fn size_with_inferred_rex_for_inreg0(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(0, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, based on the second operand.
|
||||
fn size_with_inferred_rex_for_inreg1(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(1, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, based on the third operand.
|
||||
fn size_with_inferred_rex_for_inreg2(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(2, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, for use with two input registers.
|
||||
///
|
||||
/// A REX prefix is known to be emitted if either:
|
||||
/// 1. The EncodingBits specify that REX.W is to be set.
|
||||
/// 2. Registers are used that require REX.R or REX.B bits for encoding.
|
||||
fn size_with_inferred_rex_for_inreg0_inreg1(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(0, inst, divert, func, is_extended_reg)
|
||||
|| test_input(1, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, based on a single
|
||||
/// input register and a single output register.
|
||||
fn size_with_inferred_rex_for_inreg0_outreg0(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(0, inst, divert, func, is_extended_reg)
|
||||
|| test_result(0, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Infers whether a dynamic REX prefix will be emitted, for use with CMOV.
|
||||
///
|
||||
/// CMOV uses 3 inputs, with the REX is inferred from reg1 and reg2.
|
||||
fn size_with_inferred_rex_for_cmov(
|
||||
sizing: &RecipeSizing,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
let needs_rex = (EncodingBits::from(enc.bits()).rex_w() != 0)
|
||||
|| test_input(1, inst, divert, func, is_extended_reg)
|
||||
|| test_input(2, inst, divert, func, is_extended_reg);
|
||||
sizing.base_size + if needs_rex { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// If the value's definition is a constant immediate, returns its unpacked value, or None
|
||||
|
|
|
@ -0,0 +1,354 @@
|
|||
//! Support for FDE data generation.
|
||||
|
||||
use crate::binemit::{FrameUnwindOffset, FrameUnwindSink, Reloc};
|
||||
use crate::ir::{FrameLayoutChange, Function};
|
||||
use crate::isa::{CallConv, RegUnit, TargetIsa};
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryInto;
|
||||
use gimli::write::{
|
||||
Address, CallFrameInstruction, CommonInformationEntry, EhFrame, EndianVec,
|
||||
FrameDescriptionEntry, FrameTable, Result, Writer,
|
||||
};
|
||||
use gimli::{Encoding, Format, LittleEndian, Register, X86_64};
|
||||
use std::ptr;
|
||||
|
||||
pub type FDERelocEntry = (FrameUnwindOffset, Reloc);
|
||||
|
||||
const FUNCTION_ENTRY_ADDRESS: Address = Address::Symbol {
|
||||
symbol: 0,
|
||||
addend: 0,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FDEWriter {
|
||||
vec: EndianVec<LittleEndian>,
|
||||
relocs: Vec<FDERelocEntry>,
|
||||
}
|
||||
|
||||
impl FDEWriter {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
vec: EndianVec::new(LittleEndian),
|
||||
relocs: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn into_vec_and_relocs(self) -> (Vec<u8>, Vec<FDERelocEntry>) {
|
||||
(self.vec.into_vec(), self.relocs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer for FDEWriter {
|
||||
type Endian = LittleEndian;
|
||||
fn endian(&self) -> Self::Endian {
|
||||
LittleEndian
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
}
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<()> {
|
||||
self.vec.write(bytes)
|
||||
}
|
||||
fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
|
||||
self.vec.write_at(offset, bytes)
|
||||
}
|
||||
fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
|
||||
match address {
|
||||
Address::Constant(_) => self.vec.write_address(address, size),
|
||||
Address::Symbol { .. } => {
|
||||
assert_eq!(address, FUNCTION_ENTRY_ADDRESS);
|
||||
let rt = match size {
|
||||
4 => Reloc::Abs4,
|
||||
8 => Reloc::Abs8,
|
||||
_ => {
|
||||
panic!("Unexpected address size at FDEWriter::write_address");
|
||||
}
|
||||
};
|
||||
self.relocs.push((self.vec.len().try_into().unwrap(), rt));
|
||||
self.vec.write_udata(0, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn return_address_reg(isa: &dyn TargetIsa) -> Register {
|
||||
assert!(isa.name() == "x86" && isa.pointer_bits() == 64);
|
||||
X86_64::RA
|
||||
}
|
||||
|
||||
fn map_reg(isa: &dyn TargetIsa, reg: RegUnit) -> Register {
|
||||
assert!(isa.name() == "x86" && isa.pointer_bits() == 64);
|
||||
// Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow
|
||||
const X86_GP_REG_MAP: [gimli::Register; 16] = [
|
||||
X86_64::RAX,
|
||||
X86_64::RCX,
|
||||
X86_64::RDX,
|
||||
X86_64::RBX,
|
||||
X86_64::RSP,
|
||||
X86_64::RBP,
|
||||
X86_64::RSI,
|
||||
X86_64::RDI,
|
||||
X86_64::R8,
|
||||
X86_64::R9,
|
||||
X86_64::R10,
|
||||
X86_64::R11,
|
||||
X86_64::R12,
|
||||
X86_64::R13,
|
||||
X86_64::R14,
|
||||
X86_64::R15,
|
||||
];
|
||||
const X86_XMM_REG_MAP: [gimli::Register; 16] = [
|
||||
X86_64::XMM0,
|
||||
X86_64::XMM1,
|
||||
X86_64::XMM2,
|
||||
X86_64::XMM3,
|
||||
X86_64::XMM4,
|
||||
X86_64::XMM5,
|
||||
X86_64::XMM6,
|
||||
X86_64::XMM7,
|
||||
X86_64::XMM8,
|
||||
X86_64::XMM9,
|
||||
X86_64::XMM10,
|
||||
X86_64::XMM11,
|
||||
X86_64::XMM12,
|
||||
X86_64::XMM13,
|
||||
X86_64::XMM14,
|
||||
X86_64::XMM15,
|
||||
];
|
||||
let reg_info = isa.register_info();
|
||||
let bank = reg_info.bank_containing_regunit(reg).unwrap();
|
||||
match bank.name {
|
||||
"IntRegs" => {
|
||||
// x86 GP registers have a weird mapping to DWARF registers, so we use a
|
||||
// lookup table.
|
||||
X86_GP_REG_MAP[(reg - bank.first_unit) as usize]
|
||||
}
|
||||
"FloatRegs" => X86_XMM_REG_MAP[(reg - bank.first_unit) as usize],
|
||||
_ => {
|
||||
panic!("unsupported register bank: {}", bank.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_cfi(
|
||||
isa: &dyn TargetIsa,
|
||||
change: &FrameLayoutChange,
|
||||
cfa_def_reg: &mut Register,
|
||||
cfa_def_offset: &mut i32,
|
||||
) -> Option<CallFrameInstruction> {
|
||||
Some(match change {
|
||||
FrameLayoutChange::CallFrameAddressAt { reg, offset } => {
|
||||
let mapped = map_reg(isa, *reg);
|
||||
let offset = (*offset) as i32;
|
||||
if mapped != *cfa_def_reg && offset != *cfa_def_offset {
|
||||
*cfa_def_reg = mapped;
|
||||
*cfa_def_offset = offset;
|
||||
CallFrameInstruction::Cfa(mapped, offset)
|
||||
} else if offset != *cfa_def_offset {
|
||||
*cfa_def_offset = offset;
|
||||
CallFrameInstruction::CfaOffset(offset)
|
||||
} else if mapped != *cfa_def_reg {
|
||||
*cfa_def_reg = mapped;
|
||||
CallFrameInstruction::CfaRegister(mapped)
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
FrameLayoutChange::RegAt { reg, cfa_offset } => {
|
||||
assert!(cfa_offset % -8 == 0);
|
||||
let cfa_offset = *cfa_offset as i32;
|
||||
let mapped = map_reg(isa, *reg);
|
||||
CallFrameInstruction::Offset(mapped, cfa_offset)
|
||||
}
|
||||
FrameLayoutChange::ReturnAddressAt { cfa_offset } => {
|
||||
assert!(cfa_offset % -8 == 0);
|
||||
let cfa_offset = *cfa_offset as i32;
|
||||
CallFrameInstruction::Offset(X86_64::RA, cfa_offset)
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates FDE structure from FrameLayout.
|
||||
pub fn emit_fde(func: &Function, isa: &dyn TargetIsa, sink: &mut dyn FrameUnwindSink) {
|
||||
assert!(isa.name() == "x86");
|
||||
|
||||
// Expecting function with System V prologue
|
||||
assert!(
|
||||
func.signature.call_conv == CallConv::Fast
|
||||
|| func.signature.call_conv == CallConv::Cold
|
||||
|| func.signature.call_conv == CallConv::SystemV
|
||||
);
|
||||
|
||||
assert!(func.frame_layout.is_some(), "expected func.frame_layout");
|
||||
let frame_layout = func.frame_layout.as_ref().unwrap();
|
||||
|
||||
let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
|
||||
ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase
|
||||
|
||||
let encinfo = isa.encoding_info();
|
||||
let mut last_offset = 0;
|
||||
let mut changes = Vec::new();
|
||||
for ebb in ebbs {
|
||||
for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
|
||||
let address_offset = (offset + size) as usize;
|
||||
assert!(last_offset <= address_offset);
|
||||
if let Some(cmds) = frame_layout.instructions.get(&inst) {
|
||||
for cmd in cmds.iter() {
|
||||
changes.push((address_offset, cmd.clone()));
|
||||
}
|
||||
}
|
||||
last_offset = address_offset;
|
||||
}
|
||||
}
|
||||
|
||||
let len = last_offset as u32;
|
||||
|
||||
let word_size = isa.pointer_bytes() as i32;
|
||||
|
||||
let encoding = Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 1,
|
||||
address_size: word_size as u8,
|
||||
};
|
||||
let mut frames = FrameTable::default();
|
||||
|
||||
let mut cfa_def_reg = return_address_reg(isa);
|
||||
let mut cfa_def_offset = 0i32;
|
||||
|
||||
let mut cie = CommonInformationEntry::new(
|
||||
encoding,
|
||||
/* code_alignment_factor = */ 1,
|
||||
/* data_alignment_factor = */ -word_size as i8,
|
||||
return_address_reg(isa),
|
||||
);
|
||||
for ch in frame_layout.initial.iter() {
|
||||
if let Some(cfi) = to_cfi(isa, ch, &mut cfa_def_reg, &mut cfa_def_offset) {
|
||||
cie.add_instruction(cfi);
|
||||
}
|
||||
}
|
||||
|
||||
let cie_id = frames.add_cie(cie);
|
||||
|
||||
let mut fde = FrameDescriptionEntry::new(FUNCTION_ENTRY_ADDRESS, len);
|
||||
|
||||
for (addr, ch) in changes.iter() {
|
||||
if let Some(cfi) = to_cfi(isa, ch, &mut cfa_def_reg, &mut cfa_def_offset) {
|
||||
fde.add_instruction((*addr) as u32, cfi);
|
||||
}
|
||||
}
|
||||
|
||||
frames.add_fde(cie_id, fde);
|
||||
|
||||
let mut eh_frame = EhFrame::from(FDEWriter::new());
|
||||
frames.write_eh_frame(&mut eh_frame).unwrap();
|
||||
|
||||
let (bytes, relocs) = eh_frame.clone().into_vec_and_relocs();
|
||||
|
||||
let unwind_start = sink.len();
|
||||
sink.bytes(&bytes);
|
||||
|
||||
for (off, r) in relocs {
|
||||
sink.reloc(r, off + unwind_start);
|
||||
}
|
||||
let fde_offset = unsafe { ptr::read::<u32>(bytes.as_ptr() as *const u32) } as usize + 4;
|
||||
sink.set_entry_offset(unwind_start + fde_offset);
|
||||
|
||||
// Need 0 marker for GCC unwind to end FDE "list".
|
||||
sink.bytes(&[0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::binemit::{FrameUnwindOffset, Reloc};
|
||||
use crate::cursor::{Cursor, FuncCursor};
|
||||
use crate::ir::{ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind};
|
||||
use crate::isa::{lookup, CallConv};
|
||||
use crate::settings::{builder, Flags};
|
||||
use crate::Context;
|
||||
use std::str::FromStr;
|
||||
use target_lexicon::triple;
|
||||
|
||||
struct SimpleUnwindSink(pub Vec<u8>, pub usize, pub Vec<(Reloc, usize)>);
|
||||
impl FrameUnwindSink for SimpleUnwindSink {
|
||||
fn len(&self) -> FrameUnwindOffset {
|
||||
self.0.len()
|
||||
}
|
||||
fn bytes(&mut self, b: &[u8]) {
|
||||
self.0.extend_from_slice(b);
|
||||
}
|
||||
fn reloc(&mut self, r: Reloc, off: FrameUnwindOffset) {
|
||||
self.2.push((r, off));
|
||||
}
|
||||
fn set_entry_offset(&mut self, off: FrameUnwindOffset) {
|
||||
self.1 = off;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_func() {
|
||||
let isa = lookup(triple!("x86_64"))
|
||||
.expect("expect x86 ISA")
|
||||
.finish(Flags::new(builder()));
|
||||
|
||||
let mut context = Context::for_function(create_function(
|
||||
CallConv::SystemV,
|
||||
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
|
||||
));
|
||||
context.func.collect_frame_layout_info();
|
||||
|
||||
context.compile(&*isa).expect("expected compilation");
|
||||
|
||||
let mut sink = SimpleUnwindSink(Vec::new(), 0, Vec::new());
|
||||
emit_fde(&context.func, &*isa, &mut sink);
|
||||
|
||||
assert_eq!(
|
||||
sink.0,
|
||||
vec![
|
||||
20, 0, 0, 0, // CIE len
|
||||
0, 0, 0, 0, // CIE marker
|
||||
1, // version
|
||||
0, // augmentation string
|
||||
1, // code aligment = 1
|
||||
120, // data alignment = -8
|
||||
16, // RA = r16
|
||||
0x0c, 0x07, 0x08, // DW_CFA_def_cfa r7, 8
|
||||
0x90, 0x01, // DW_CFA_offset r16, -8 * 1
|
||||
0, 0, 0, 0, 0, 0, // padding
|
||||
36, 0, 0, 0, // FDE len
|
||||
28, 0, 0, 0, // CIE offset
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // addr reloc
|
||||
16, 0, 0, 0, 0, 0, 0, 0, // function length
|
||||
0x42, // DW_CFA_advance_loc 2
|
||||
0x0e, 0x10, // DW_CFA_def_cfa_offset 16
|
||||
0x86, 0x02, // DW_CFA_offset r6, -8 * 2
|
||||
0x43, // DW_CFA_advance_loc 3
|
||||
0x0d, 0x06, // DW_CFA_def_cfa_register
|
||||
0x4a, // DW_CFA_advance_loc 10
|
||||
0x0c, 0x07, 0x08, // DW_CFA_def_cfa r7, 8
|
||||
0, 0, 0, 0, // padding
|
||||
0, 0, 0, 0, // End of FDEs
|
||||
]
|
||||
);
|
||||
assert_eq!(sink.1, 24);
|
||||
assert_eq!(sink.2.len(), 1);
|
||||
}
|
||||
|
||||
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
|
||||
let mut func =
|
||||
Function::with_name_signature(ExternalName::user(0, 0), Signature::new(call_conv));
|
||||
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_ebb(ebb0);
|
||||
pos.ins().return_(&[]);
|
||||
|
||||
if let Some(stack_slot) = stack_slot {
|
||||
func.stack_slots.push(stack_slot);
|
||||
}
|
||||
|
||||
func
|
||||
}
|
||||
}
|
|
@ -3,14 +3,19 @@
|
|||
mod abi;
|
||||
mod binemit;
|
||||
mod enc_tables;
|
||||
#[cfg(feature = "unwind")]
|
||||
mod fde;
|
||||
mod registers;
|
||||
pub mod settings;
|
||||
#[cfg(feature = "unwind")]
|
||||
mod unwind;
|
||||
|
||||
use super::super::settings as shared_settings;
|
||||
#[cfg(feature = "testing_hooks")]
|
||||
use crate::binemit::CodeSink;
|
||||
use crate::binemit::{emit_function, MemoryCodeSink};
|
||||
#[cfg(feature = "unwind")]
|
||||
use crate::binemit::{FrameUnwindKind, FrameUnwindSink};
|
||||
use crate::ir;
|
||||
use crate::isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
|
||||
use crate::isa::Builder as IsaBuilder;
|
||||
|
@ -20,7 +25,6 @@ use crate::result::CodegenResult;
|
|||
use crate::timing;
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use target_lexicon::{PointerWidth, Triple};
|
||||
|
||||
|
@ -157,8 +161,14 @@ impl TargetIsa for Isa {
|
|||
/// Emit unwind information for the given function.
|
||||
///
|
||||
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
|
||||
fn emit_unwind_info(&self, func: &ir::Function, mem: &mut Vec<u8>) {
|
||||
abi::emit_unwind_info(func, self, mem);
|
||||
#[cfg(feature = "unwind")]
|
||||
fn emit_unwind_info(
|
||||
&self,
|
||||
func: &ir::Function,
|
||||
kind: FrameUnwindKind,
|
||||
sink: &mut dyn FrameUnwindSink,
|
||||
) {
|
||||
abi::emit_unwind_info(func, self, kind, sink);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Unwind information for x64 Windows.
|
||||
|
||||
use super::registers::RU;
|
||||
use crate::binemit::FrameUnwindSink;
|
||||
use crate::ir::{Function, InstructionData, Opcode};
|
||||
use crate::isa::{CallConv, RegUnit, TargetIsa};
|
||||
use alloc::vec::Vec;
|
||||
|
@ -11,16 +12,20 @@ const SMALL_ALLOC_MAX_SIZE: u32 = 128;
|
|||
/// Maximum (inclusive) size of a "large" stack allocation that can represented in 16-bits
|
||||
const LARGE_ALLOC_16BIT_MAX_SIZE: u32 = 524280;
|
||||
|
||||
fn write_u16<T: ByteOrder>(mem: &mut Vec<u8>, v: u16) {
|
||||
let mut buf = [0; 2];
|
||||
T::write_u16(&mut buf, v);
|
||||
mem.extend(buf.iter());
|
||||
fn write_u8(sink: &mut dyn FrameUnwindSink, v: u8) {
|
||||
sink.bytes(&[v]);
|
||||
}
|
||||
|
||||
fn write_u32<T: ByteOrder>(mem: &mut Vec<u8>, v: u32) {
|
||||
fn write_u16<T: ByteOrder>(sink: &mut dyn FrameUnwindSink, v: u16) {
|
||||
let mut buf = [0; 2];
|
||||
T::write_u16(&mut buf, v);
|
||||
sink.bytes(&buf);
|
||||
}
|
||||
|
||||
fn write_u32<T: ByteOrder>(sink: &mut dyn FrameUnwindSink, v: u32) {
|
||||
let mut buf = [0; 4];
|
||||
T::write_u32(&mut buf, v);
|
||||
mem.extend(buf.iter());
|
||||
sink.bytes(&buf);
|
||||
}
|
||||
|
||||
/// The supported unwind codes for the x64 Windows ABI.
|
||||
|
@ -36,7 +41,7 @@ enum UnwindCode {
|
|||
}
|
||||
|
||||
impl UnwindCode {
|
||||
fn emit(&self, mem: &mut Vec<u8>) {
|
||||
fn emit(&self, sink: &mut dyn FrameUnwindSink) {
|
||||
enum UnwindOperation {
|
||||
PushNonvolatileRegister,
|
||||
LargeStackAlloc,
|
||||
|
@ -46,30 +51,37 @@ impl UnwindCode {
|
|||
|
||||
match self {
|
||||
Self::PushRegister { offset, reg } => {
|
||||
mem.push(*offset);
|
||||
mem.push(((*reg as u8) << 4) | (UnwindOperation::PushNonvolatileRegister as u8));
|
||||
write_u8(sink, *offset);
|
||||
write_u8(
|
||||
sink,
|
||||
((*reg as u8) << 4) | (UnwindOperation::PushNonvolatileRegister as u8),
|
||||
);
|
||||
}
|
||||
Self::StackAlloc { offset, size } => {
|
||||
// Stack allocations on Windows must be a multiple of 8 and be at least 1 slot
|
||||
assert!(*size >= 8);
|
||||
assert!((*size % 8) == 0);
|
||||
|
||||
mem.push(*offset);
|
||||
write_u8(sink, *offset);
|
||||
if *size <= SMALL_ALLOC_MAX_SIZE {
|
||||
mem.push(
|
||||
write_u8(
|
||||
sink,
|
||||
((((*size - 8) / 8) as u8) << 4) | UnwindOperation::SmallStackAlloc as u8,
|
||||
);
|
||||
} else if *size <= LARGE_ALLOC_16BIT_MAX_SIZE {
|
||||
mem.push(UnwindOperation::LargeStackAlloc as u8);
|
||||
write_u16::<LittleEndian>(mem, (*size / 8) as u16);
|
||||
write_u8(sink, UnwindOperation::LargeStackAlloc as u8);
|
||||
write_u16::<LittleEndian>(sink, (*size / 8) as u16);
|
||||
} else {
|
||||
mem.push((1 << 4) | (UnwindOperation::LargeStackAlloc as u8));
|
||||
write_u32::<LittleEndian>(mem, *size);
|
||||
write_u8(sink, (1 << 4) | (UnwindOperation::LargeStackAlloc as u8));
|
||||
write_u32::<LittleEndian>(sink, *size);
|
||||
}
|
||||
}
|
||||
Self::SetFramePointer { offset, sp_offset } => {
|
||||
mem.push(*offset);
|
||||
mem.push((*sp_offset << 4) | (UnwindOperation::SetFramePointer as u8));
|
||||
write_u8(sink, *offset);
|
||||
write_u8(
|
||||
sink,
|
||||
(*sp_offset << 4) | (UnwindOperation::SetFramePointer as u8),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -231,48 +243,49 @@ impl UnwindInfo {
|
|||
.fold(0, |nodes, c| nodes + c.node_count())
|
||||
}
|
||||
|
||||
pub fn emit(&self, mem: &mut Vec<u8>) {
|
||||
pub fn emit(&self, sink: &mut dyn FrameUnwindSink) {
|
||||
const UNWIND_INFO_VERSION: u8 = 1;
|
||||
|
||||
let size = self.size();
|
||||
let offset = mem.len();
|
||||
let offset = sink.len();
|
||||
|
||||
// Ensure the memory is 32-bit aligned
|
||||
assert_eq!(offset % 4, 0);
|
||||
|
||||
mem.reserve(offset + size);
|
||||
sink.reserve(offset + size);
|
||||
|
||||
let node_count = self.node_count();
|
||||
assert!(node_count <= 256);
|
||||
|
||||
mem.push((self.flags << 3) | UNWIND_INFO_VERSION);
|
||||
mem.push(self.prologue_size);
|
||||
mem.push(node_count as u8);
|
||||
write_u8(sink, (self.flags << 3) | UNWIND_INFO_VERSION);
|
||||
write_u8(sink, self.prologue_size);
|
||||
write_u8(sink, node_count as u8);
|
||||
|
||||
if let Some(reg) = self.frame_register {
|
||||
mem.push((self.frame_register_offset << 4) | reg as u8);
|
||||
write_u8(sink, (self.frame_register_offset << 4) | reg as u8);
|
||||
} else {
|
||||
mem.push(0);
|
||||
write_u8(sink, 0);
|
||||
}
|
||||
|
||||
// Unwind codes are written in reverse order (prologue offset descending)
|
||||
for code in self.unwind_codes.iter().rev() {
|
||||
code.emit(mem);
|
||||
code.emit(sink);
|
||||
}
|
||||
|
||||
// To keep a 32-bit alignment, emit 2 bytes of padding if there's an odd number of 16-bit nodes
|
||||
if (node_count & 1) == 1 {
|
||||
write_u16::<LittleEndian>(mem, 0);
|
||||
write_u16::<LittleEndian>(sink, 0);
|
||||
}
|
||||
|
||||
// Ensure the correct number of bytes was emitted
|
||||
assert_eq!(mem.len() - offset, size);
|
||||
assert_eq!(sink.len() - offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::binemit::{FrameUnwindOffset, Reloc};
|
||||
use crate::cursor::{Cursor, FuncCursor};
|
||||
use crate::ir::{ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind};
|
||||
use crate::isa::{lookup, CallConv};
|
||||
|
@ -281,6 +294,18 @@ mod tests {
|
|||
use std::str::FromStr;
|
||||
use target_lexicon::triple;
|
||||
|
||||
struct SimpleUnwindSink(pub Vec<u8>);
|
||||
impl FrameUnwindSink for SimpleUnwindSink {
|
||||
fn len(&self) -> FrameUnwindOffset {
|
||||
self.0.len()
|
||||
}
|
||||
fn bytes(&mut self, b: &[u8]) {
|
||||
self.0.extend_from_slice(b);
|
||||
}
|
||||
fn reloc(&mut self, _: Reloc, _: FrameUnwindOffset) {}
|
||||
fn set_entry_offset(&mut self, _: FrameUnwindOffset) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrong_calling_convention() {
|
||||
let isa = lookup(triple!("x86_64"))
|
||||
|
@ -336,11 +361,11 @@ mod tests {
|
|||
|
||||
assert_eq!(unwind.size(), 12);
|
||||
|
||||
let mut mem = Vec::new();
|
||||
unwind.emit(&mut mem);
|
||||
let mut sink = SimpleUnwindSink(Vec::new());
|
||||
unwind.emit(&mut sink);
|
||||
|
||||
assert_eq!(
|
||||
mem,
|
||||
sink.0,
|
||||
[
|
||||
0x01, // Version and flags (version 1, no flags)
|
||||
0x09, // Prologue size
|
||||
|
@ -400,11 +425,11 @@ mod tests {
|
|||
|
||||
assert_eq!(unwind.size(), 12);
|
||||
|
||||
let mut mem = Vec::new();
|
||||
unwind.emit(&mut mem);
|
||||
let mut sink = SimpleUnwindSink(Vec::new());
|
||||
unwind.emit(&mut sink);
|
||||
|
||||
assert_eq!(
|
||||
mem,
|
||||
sink.0,
|
||||
[
|
||||
0x01, // Version and flags (version 1, no flags)
|
||||
0x1B, // Prologue size
|
||||
|
@ -464,11 +489,11 @@ mod tests {
|
|||
|
||||
assert_eq!(unwind.size(), 16);
|
||||
|
||||
let mut mem = Vec::new();
|
||||
unwind.emit(&mut mem);
|
||||
let mut sink = SimpleUnwindSink(Vec::new());
|
||||
unwind.emit(&mut sink);
|
||||
|
||||
assert_eq!(
|
||||
mem,
|
||||
sink.0,
|
||||
[
|
||||
0x01, // Version and flags (version 1, no flags)
|
||||
0x1B, // Prologue size
|
||||
|
|
|
@ -191,7 +191,7 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is
|
|||
}
|
||||
|
||||
// Now that we've lowered all br_tables, we don't need the jump tables anymore.
|
||||
if !isa.flags().jump_tables_enabled() {
|
||||
if !isa.flags().enable_jump_tables() {
|
||||
pos.func.jump_tables.clear();
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ fn expand_br_table(
|
|||
cfg: &mut ControlFlowGraph,
|
||||
isa: &dyn TargetIsa,
|
||||
) {
|
||||
if isa.flags().jump_tables_enabled() {
|
||||
if isa.flags().enable_jump_tables() {
|
||||
expand_br_table_jt(inst, func, cfg, isa);
|
||||
} else {
|
||||
expand_br_table_conds(inst, func, cfg, isa);
|
||||
|
|
|
@ -384,7 +384,7 @@ mod tests {
|
|||
probestack_size_log2 = 12\n\
|
||||
enable_verifier = true\n\
|
||||
is_pic = false\n\
|
||||
colocated_libcalls = false\n\
|
||||
use_colocated_libcalls = false\n\
|
||||
avoid_div_traps = false\n\
|
||||
enable_float = true\n\
|
||||
enable_nan_canonicalization = false\n\
|
||||
|
@ -393,10 +393,10 @@ mod tests {
|
|||
enable_simd = false\n\
|
||||
enable_atomics = true\n\
|
||||
enable_safepoints = false\n\
|
||||
allones_funcaddrs = false\n\
|
||||
probestack_enabled = true\n\
|
||||
emit_all_ones_funcaddrs = false\n\
|
||||
enable_probestack = true\n\
|
||||
probestack_func_adjusts_sp = false\n\
|
||||
jump_tables_enabled = true\n"
|
||||
enable_jump_tables = true\n"
|
||||
);
|
||||
assert_eq!(f.opt_level(), super::OptLevel::None);
|
||||
assert_eq!(f.enable_simd(), false);
|
||||
|
|
|
@ -124,7 +124,8 @@ pub fn do_simple_gvn(func: &mut Function, domtree: &mut DominatorTree) {
|
|||
use crate::scoped_hash_map::Entry::*;
|
||||
match visible_values.entry(key) {
|
||||
Occupied(entry) => {
|
||||
debug_assert!(domtree.dominates(*entry.get(), inst, &func.layout));
|
||||
let layout = &func.layout;
|
||||
debug_assert!(domtree.dominates(*entry.get(), inst, layout));
|
||||
// If the redundant instruction is representing the current
|
||||
// scope, pick a new representative.
|
||||
let old = scope_stack.last_mut().unwrap();
|
||||
|
|
|
@ -1971,6 +1971,9 @@ impl<'a> Verifier<'a> {
|
|||
self.typecheck_function_signature(errors)?;
|
||||
|
||||
for ebb in self.func.layout.ebbs() {
|
||||
if self.func.layout.first_inst(ebb).is_none() {
|
||||
return errors.fatal((ebb, format!("{} cannot be empty", ebb)));
|
||||
}
|
||||
for inst in self.func.layout.ebb_insts(ebb) {
|
||||
self.ebb_integrity(ebb, inst, errors)?;
|
||||
self.instruction_integrity(inst, errors)?;
|
||||
|
@ -2117,4 +2120,18 @@ mod tests {
|
|||
"inst0 (v0, v1 = iconst.i32 42): has more result values than expected"
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_ebb() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
func.layout.append_ebb(ebb0);
|
||||
|
||||
let flags = &settings::Flags::new(settings::builder());
|
||||
let verifier = Verifier::new(&func, flags.into());
|
||||
let mut errors = VerifierErrors::default();
|
||||
let _ = verifier.run(&mut errors);
|
||||
|
||||
assert_err_with_msg!(errors, "ebb0 cannot be empty");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"6cf98e2d02e873cef38801f71a47ac39f7941bc702bd44cc54cc4a910d1bec54","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"69d539b72460c0aba1d30e0b72efb0c29d61558574d751c784794e14abf41352","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"0cd9145c1528f95ee7770765faa2f9a1051791144e2936789248b25fdfe06fc1","src/list.rs":"4bf609eb7cc7c000c18da746596d5fcc67eece3f919ee2d76e19f6ac371640d1","src/map.rs":"546b36be4cbbd2423bacbed69cbe114c63538c3f635e15284ab8e4223e717705","src/packed_option.rs":"dccb3dd6fc87eba0101de56417f21cab67a4394831df9fa41e3bbddb70cdf694","src/primary.rs":"30d5e2ab8427fd2b2c29da395812766049e3c40845cc887af3ee233dba91a063","src/set.rs":"dd04a4954863cc106e168a7d9a89bcebd1c4e045e7ef9ec1f0dadc0a8eaf919d","src/sparse.rs":"536e31fdcf64450526f5e5b85e97406c26b998bc7e0d8161b6b449c24265449f"},"package":null}
|
||||
{"files":{"Cargo.toml":"f996c9d9c38289ce69f727a9331594184be6b18b68f69343bf7ddf92a2241573","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"69d539b72460c0aba1d30e0b72efb0c29d61558574d751c784794e14abf41352","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"0cd9145c1528f95ee7770765faa2f9a1051791144e2936789248b25fdfe06fc1","src/list.rs":"4bf609eb7cc7c000c18da746596d5fcc67eece3f919ee2d76e19f6ac371640d1","src/map.rs":"546b36be4cbbd2423bacbed69cbe114c63538c3f635e15284ab8e4223e717705","src/packed_option.rs":"dccb3dd6fc87eba0101de56417f21cab67a4394831df9fa41e3bbddb70cdf694","src/primary.rs":"30d5e2ab8427fd2b2c29da395812766049e3c40845cc887af3ee233dba91a063","src/set.rs":"dd04a4954863cc106e168a7d9a89bcebd1c4e045e7ef9ec1f0dadc0a8eaf919d","src/sparse.rs":"536e31fdcf64450526f5e5b85e97406c26b998bc7e0d8161b6b449c24265449f"},"package":null}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-entity"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "Data structures using entity references as mapping keys"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"5564c8fe72dd80449647fcc8488f461f22b234929cfe534d13f600825d661d3f","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"c8ba698562fe845282e3118cd2a66656161c2babe61096c62fbc373ec5380753","src/lib.rs":"2a8efc913364bdb700268fb66a6132d2d48f3fe10fe80443fcf17d9480a0f167","src/ssa.rs":"3e4dd91c59e3e5acde2ec758fc1bc4c5783940bce8637b7b67b180cfab0007c3","src/switch.rs":"6a31c37ed9e93ee943b7e98e28646804497d64a5a6a55aa1924c5feb27b52dfa","src/variable.rs":"399437bd7d2ac11a7a748bad7dd1f6dac58824d374ec318f36367a9d077cc225"},"package":null}
|
||||
{"files":{"Cargo.toml":"fe6a59f44df0fa8aa9ad1de62e1c8559379b9e8ceb3545fb448fe48ff52360f5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"c8ba698562fe845282e3118cd2a66656161c2babe61096c62fbc373ec5380753","src/lib.rs":"2a8efc913364bdb700268fb66a6132d2d48f3fe10fe80443fcf17d9480a0f167","src/ssa.rs":"3e4dd91c59e3e5acde2ec758fc1bc4c5783940bce8637b7b67b180cfab0007c3","src/switch.rs":"6a31c37ed9e93ee943b7e98e28646804497d64a5a6a55aa1924c5feb27b52dfa","src/variable.rs":"399437bd7d2ac11a7a748bad7dd1f6dac58824d374ec318f36367a9d077cc225"},"package":null}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
description = "Cranelift IR builder helper"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
@ -11,8 +11,8 @@ readme = "README.md"
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.51.0", default-features = false }
|
||||
target-lexicon = "0.9"
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.55.0", default-features = false }
|
||||
target-lexicon = "0.10"
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
hashbrown = { version = "0.6", optional = true }
|
||||
smallvec = { version = "1.0.0" }
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"09183eb6dfd8a6d33a033b46c32f8f2eca2f052af135a7b0599ecc8d9409f38c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"f46f9c5df1b10bad0e87d9c2ad9f5e65bbb6749ac8843cd80ec357daa3b22c3e","src/code_translator.rs":"e60d0d35e54f2403101c4ed8af6202ae2d37cbaf63ebe21ccef6ef9ffa77ad72","src/environ/dummy.rs":"b918e7c7afd3be41d7b2b8587a1cb0119640508f475fc086f949a96d01b783d6","src/environ/mod.rs":"b6f33f619090ff497b4e22150d77a290f259716374ac2e377b73c47cd1dafe85","src/environ/spec.rs":"770b494bae5c50d6cc9e5e825e0455682f0d7e83373af0f231267ea394cc5aba","src/func_translator.rs":"0c18f09fa533b67f41ff1da9893eac8feabe9e7847620a5aa2c4ad0f2185afbb","src/lib.rs":"0dbbb3d5088799c3aaa94b083ca0c2f09906bd8fb36e9c0dd200b8122c50a8b6","src/module_translator.rs":"5e1bf9471d6f4f317bb2fb9b8697b5b08f7950520017c2869e69133e7f17a2b7","src/sections_translator.rs":"e9af588789b00c4e91e7a4bd87c7ea3c745dc1a5e00fc1f758ee8d9a46902a63","src/state/func_state.rs":"8394eb9b446fc286222b806c55689c19beb0a5b6c78c1d8dee7c19b0d5693661","src/state/mod.rs":"20014cb93615467b4d20321b52f67f66040417efcaa739a4804093bb559eed19","src/state/module_state.rs":"2f299b043deb806b48583fe54bbb46708f7d8a1454b7be0eb285568064e5a7f9","src/translation_utils.rs":"e3b56d34ab989e9e81a8b30b52fab11c886bfcb783b9c091d1a72ad35fdbe0d0","tests/wasm_testsuite.rs":"c1160bde8b0bd5d7d2eb5b6a066b60025dcebf758b1794fa32235c07e2fb2be2"},"package":null}
|
||||
{"files":{"Cargo.toml":"758e4396c31b66d601fb6fb684da102e50d0dbaa4405086f6c0c86b0c27fe03d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"f46f9c5df1b10bad0e87d9c2ad9f5e65bbb6749ac8843cd80ec357daa3b22c3e","src/code_translator.rs":"c6beac3cc13b5ed695d49a5a3dbd44569c2a4fd69e67abd613505d800fbbbfe5","src/environ/dummy.rs":"b918e7c7afd3be41d7b2b8587a1cb0119640508f475fc086f949a96d01b783d6","src/environ/mod.rs":"b6f33f619090ff497b4e22150d77a290f259716374ac2e377b73c47cd1dafe85","src/environ/spec.rs":"0c265a16f24c49c51cfd1d78754d90b7c7a5fa5512cfe555d5e10612ead6a9be","src/func_translator.rs":"cb5618e2ec62d28bdd7561cac0c58b591d904f7503f828c9a6887a70ab264e3d","src/lib.rs":"0dbbb3d5088799c3aaa94b083ca0c2f09906bd8fb36e9c0dd200b8122c50a8b6","src/module_translator.rs":"5e1bf9471d6f4f317bb2fb9b8697b5b08f7950520017c2869e69133e7f17a2b7","src/sections_translator.rs":"158631c43ee07a43790545201e2e597e4d71793e6f4a644851f9e5db4c0a2ef2","src/state/func_state.rs":"cc935f96a703769d075498ec2aa8fe191b8b9e3e5729e25eb409ffb82696d82e","src/state/mod.rs":"20014cb93615467b4d20321b52f67f66040417efcaa739a4804093bb559eed19","src/state/module_state.rs":"2f299b043deb806b48583fe54bbb46708f7d8a1454b7be0eb285568064e5a7f9","src/translation_utils.rs":"e3b56d34ab989e9e81a8b30b52fab11c886bfcb783b9c091d1a72ad35fdbe0d0","tests/wasm_testsuite.rs":"730304f139371e5ef3fd913ec271fc4db181869b447c6ed26c54313b5c31495c"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.51.0"
|
||||
version = "0.55.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Translator from WebAssembly to Cranelift IR"
|
||||
repository = "https://github.com/bytecodealliance/cranelift"
|
||||
|
@ -11,23 +11,23 @@ keywords = ["webassembly", "wasm"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmparser = { version = "0.39.2", default-features = false }
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.51.0", default-features = false }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.51.0" }
|
||||
cranelift-frontend = { path = "../cranelift-frontend", version = "0.51.0", default-features = false }
|
||||
wasmparser = { version = "0.47.0", default-features = false }
|
||||
cranelift-codegen = { path = "../cranelift-codegen", version = "0.55.0", default-features = false }
|
||||
cranelift-entity = { path = "../cranelift-entity", version = "0.55.0" }
|
||||
cranelift-frontend = { path = "../cranelift-frontend", version = "0.55.0", default-features = false }
|
||||
hashbrown = { version = "0.6", optional = true }
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
serde = { version = "1.0.94", features = ["derive"], optional = true }
|
||||
thiserror = "1.0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.9.1"
|
||||
target-lexicon = "0.9"
|
||||
wat = "1.0.7"
|
||||
target-lexicon = "0.10"
|
||||
|
||||
[features]
|
||||
default = ["std", "basic-blocks"]
|
||||
std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmparser/std"]
|
||||
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core", "wasmparser/core"]
|
||||
std = ["cranelift-codegen/std", "cranelift-frontend/std"]
|
||||
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]
|
||||
enable-serde = ["serde"]
|
||||
|
||||
# Temporary feature that enforces basic block semantics.
|
||||
|
|
|
@ -65,19 +65,19 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
* `get_local` and `set_local` are treated as non-SSA variables and will completely
|
||||
* disappear in the Cranelift Code
|
||||
***********************************************************************************/
|
||||
Operator::GetLocal { local_index } => {
|
||||
Operator::LocalGet { local_index } => {
|
||||
let val = builder.use_var(Variable::with_u32(*local_index));
|
||||
state.push1(val);
|
||||
let label = ValueLabel::from_u32(*local_index);
|
||||
builder.set_val_label(val, label);
|
||||
}
|
||||
Operator::SetLocal { local_index } => {
|
||||
Operator::LocalSet { local_index } => {
|
||||
let val = state.pop1();
|
||||
builder.def_var(Variable::with_u32(*local_index), val);
|
||||
let label = ValueLabel::from_u32(*local_index);
|
||||
builder.set_val_label(val, label);
|
||||
}
|
||||
Operator::TeeLocal { local_index } => {
|
||||
Operator::LocalTee { local_index } => {
|
||||
let val = state.peek1();
|
||||
builder.def_var(Variable::with_u32(*local_index), val);
|
||||
let label = ValueLabel::from_u32(*local_index);
|
||||
|
@ -86,7 +86,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
/********************************** Globals ****************************************
|
||||
* `get_global` and `set_global` are handled by the environment.
|
||||
***********************************************************************************/
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
let val = match state.get_global(builder.func, *global_index, environ)? {
|
||||
GlobalVariable::Const(val) => val,
|
||||
GlobalVariable::Memory { gv, offset, ty } => {
|
||||
|
@ -97,7 +97,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
};
|
||||
state.push1(val);
|
||||
}
|
||||
Operator::SetGlobal { global_index } => {
|
||||
Operator::GlobalSet { global_index } => {
|
||||
match state.get_global(builder.func, *global_index, environ)? {
|
||||
GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
|
||||
GlobalVariable::Memory { gv, offset, ty } => {
|
||||
|
@ -267,12 +267,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
}
|
||||
Operator::End => {
|
||||
let frame = state.control_stack.pop().unwrap();
|
||||
let next_ebb = frame.following_code();
|
||||
|
||||
if !builder.is_unreachable() || !builder.is_pristine() {
|
||||
let return_count = frame.num_return_values();
|
||||
builder
|
||||
.ins()
|
||||
.jump(frame.following_code(), state.peekn(return_count));
|
||||
let return_args = state.peekn_mut(return_count);
|
||||
let next_ebb_types = builder.func.dfg.ebb_param_types(next_ebb);
|
||||
bitcast_arguments(return_args, &next_ebb_types, builder);
|
||||
builder.ins().jump(frame.following_code(), return_args);
|
||||
// You might expect that if we just finished an `if` block that
|
||||
// didn't have a corresponding `else` block, then we would clean
|
||||
// up our duplicate set of parameters that we pushed earlier
|
||||
|
@ -280,16 +282,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
// since we truncate the stack back to the original height
|
||||
// below.
|
||||
}
|
||||
builder.switch_to_block(frame.following_code());
|
||||
builder.seal_block(frame.following_code());
|
||||
builder.switch_to_block(next_ebb);
|
||||
builder.seal_block(next_ebb);
|
||||
// If it is a loop we also have to seal the body loop block
|
||||
if let ControlStackFrame::Loop { header, .. } = frame {
|
||||
builder.seal_block(header)
|
||||
}
|
||||
state.stack.truncate(frame.original_stack_size());
|
||||
state
|
||||
.stack
|
||||
.extend_from_slice(builder.ebb_params(frame.following_code()));
|
||||
state.stack.extend_from_slice(builder.ebb_params(next_ebb));
|
||||
}
|
||||
/**************************** Branch instructions *********************************
|
||||
* The branch instructions all have as arguments a target nesting level, which
|
||||
|
@ -325,9 +325,17 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
};
|
||||
(return_count, frame.br_destination())
|
||||
};
|
||||
builder
|
||||
.ins()
|
||||
.jump(br_destination, state.peekn(return_count));
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_args = state.peekn_mut(return_count);
|
||||
let destination_types = builder.func.dfg.ebb_param_types(br_destination);
|
||||
bitcast_arguments(
|
||||
destination_args,
|
||||
&destination_types[..return_count],
|
||||
builder,
|
||||
);
|
||||
|
||||
builder.ins().jump(br_destination, destination_args);
|
||||
state.popn(return_count);
|
||||
state.reachable = false;
|
||||
}
|
||||
|
@ -406,7 +414,17 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
frame.set_branched_to_exit();
|
||||
frame.br_destination()
|
||||
};
|
||||
builder.ins().jump(real_dest_ebb, state.peekn(return_count));
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_args = state.peekn_mut(return_count);
|
||||
let destination_types = builder.func.dfg.ebb_param_types(real_dest_ebb);
|
||||
bitcast_arguments(
|
||||
destination_args,
|
||||
&destination_types[..return_count],
|
||||
builder,
|
||||
);
|
||||
|
||||
builder.ins().jump(real_dest_ebb, destination_args);
|
||||
}
|
||||
state.popn(return_count);
|
||||
}
|
||||
|
@ -420,10 +438,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
(return_count, frame.br_destination())
|
||||
};
|
||||
{
|
||||
let args = state.peekn(return_count);
|
||||
let return_args = state.peekn_mut(return_count);
|
||||
let return_types = &builder.func.signature.return_types();
|
||||
bitcast_arguments(return_args, &return_types, builder);
|
||||
match environ.return_mode() {
|
||||
ReturnMode::NormalReturns => builder.ins().return_(args),
|
||||
ReturnMode::FallthroughReturn => builder.ins().jump(br_destination, args),
|
||||
ReturnMode::NormalReturns => builder.ins().return_(return_args),
|
||||
ReturnMode::FallthroughReturn => {
|
||||
builder.ins().jump(br_destination, return_args)
|
||||
}
|
||||
};
|
||||
}
|
||||
state.popn(return_count);
|
||||
|
@ -436,11 +458,18 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
************************************************************************************/
|
||||
Operator::Call { function_index } => {
|
||||
let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before calling.
|
||||
let callee_signature =
|
||||
&builder.func.dfg.signatures[builder.func.dfg.ext_funcs[fref].signature];
|
||||
let args = state.peekn_mut(num_args);
|
||||
bitcast_arguments(args, &callee_signature.param_types(), builder);
|
||||
|
||||
let call = environ.translate_call(
|
||||
builder.cursor(),
|
||||
FuncIndex::from_u32(*function_index),
|
||||
fref,
|
||||
state.peekn(num_args),
|
||||
args,
|
||||
)?;
|
||||
let inst_results = builder.inst_results(call);
|
||||
debug_assert_eq!(
|
||||
|
@ -459,6 +488,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let (sigref, num_args) = state.get_indirect_sig(builder.func, *index, environ)?;
|
||||
let table = state.get_table(builder.func, *table_index, environ)?;
|
||||
let callee = state.pop1();
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before calling.
|
||||
let callee_signature = &builder.func.dfg.signatures[sigref];
|
||||
let args = state.peekn_mut(num_args);
|
||||
bitcast_arguments(args, &callee_signature.param_types(), builder);
|
||||
|
||||
let call = environ.translate_call_indirect(
|
||||
builder.cursor(),
|
||||
TableIndex::from_u32(*table_index),
|
||||
|
@ -639,11 +674,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let arg = state.pop1();
|
||||
state.push1(builder.ins().popcnt(arg));
|
||||
}
|
||||
Operator::I64ExtendSI32 => {
|
||||
Operator::I64ExtendI32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().sextend(I64, val));
|
||||
}
|
||||
Operator::I64ExtendUI32 => {
|
||||
Operator::I64ExtendI32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().uextend(I64, val));
|
||||
}
|
||||
|
@ -679,19 +714,19 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let arg = state.pop1();
|
||||
state.push1(builder.ins().fneg(arg));
|
||||
}
|
||||
Operator::F64ConvertUI64 | Operator::F64ConvertUI32 => {
|
||||
Operator::F64ConvertI64U | Operator::F64ConvertI32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_from_uint(F64, val));
|
||||
}
|
||||
Operator::F64ConvertSI64 | Operator::F64ConvertSI32 => {
|
||||
Operator::F64ConvertI64S | Operator::F64ConvertI32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_from_sint(F64, val));
|
||||
}
|
||||
Operator::F32ConvertSI64 | Operator::F32ConvertSI32 => {
|
||||
Operator::F32ConvertI64S | Operator::F32ConvertI32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_from_sint(F32, val));
|
||||
}
|
||||
Operator::F32ConvertUI64 | Operator::F32ConvertUI32 => {
|
||||
Operator::F32ConvertI64U | Operator::F32ConvertI32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_from_uint(F32, val));
|
||||
}
|
||||
|
@ -703,35 +738,35 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let val = state.pop1();
|
||||
state.push1(builder.ins().fdemote(F32, val));
|
||||
}
|
||||
Operator::I64TruncSF64 | Operator::I64TruncSF32 => {
|
||||
Operator::I64TruncF64S | Operator::I64TruncF32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_sint(I64, val));
|
||||
}
|
||||
Operator::I32TruncSF64 | Operator::I32TruncSF32 => {
|
||||
Operator::I32TruncF64S | Operator::I32TruncF32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_sint(I32, val));
|
||||
}
|
||||
Operator::I64TruncUF64 | Operator::I64TruncUF32 => {
|
||||
Operator::I64TruncF64U | Operator::I64TruncF32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_uint(I64, val));
|
||||
}
|
||||
Operator::I32TruncUF64 | Operator::I32TruncUF32 => {
|
||||
Operator::I32TruncF64U | Operator::I32TruncF32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_uint(I32, val));
|
||||
}
|
||||
Operator::I64TruncSSatF64 | Operator::I64TruncSSatF32 => {
|
||||
Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_sint_sat(I64, val));
|
||||
}
|
||||
Operator::I32TruncSSatF64 | Operator::I32TruncSSatF32 => {
|
||||
Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_sint_sat(I32, val));
|
||||
}
|
||||
Operator::I64TruncUSatF64 | Operator::I64TruncUSatF32 => {
|
||||
Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_uint_sat(I64, val));
|
||||
}
|
||||
Operator::I32TruncUSatF64 | Operator::I32TruncUSatF32 => {
|
||||
Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => {
|
||||
let val = state.pop1();
|
||||
state.push1(builder.ins().fcvt_to_uint_sat(I32, val));
|
||||
}
|
||||
|
@ -912,15 +947,21 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
Operator::F32Le | Operator::F64Le => {
|
||||
translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
|
||||
}
|
||||
Operator::TypedSelect { .. } => {
|
||||
return Err(wasm_unsupported!("proposed typed select operator {:?}", op))
|
||||
}
|
||||
Operator::RefNull => state.push1(builder.ins().null(environ.reference_type())),
|
||||
Operator::RefIsNull => {
|
||||
let arg = state.pop1();
|
||||
let val = builder.ins().is_null(arg);
|
||||
state.push1(val);
|
||||
}
|
||||
Operator::Wake { .. }
|
||||
| Operator::I32Wait { .. }
|
||||
| Operator::I64Wait { .. }
|
||||
Operator::RefFunc { .. } => {
|
||||
return Err(wasm_unsupported!("proposed ref operator {:?}", op))
|
||||
}
|
||||
Operator::AtomicNotify { .. }
|
||||
| Operator::I32AtomicWait { .. }
|
||||
| Operator::I64AtomicWait { .. }
|
||||
| Operator::I32AtomicLoad { .. }
|
||||
| Operator::I64AtomicLoad { .. }
|
||||
| Operator::I32AtomicLoad8U { .. }
|
||||
|
@ -937,54 +978,54 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
| Operator::I64AtomicStore32 { .. }
|
||||
| Operator::I32AtomicRmwAdd { .. }
|
||||
| Operator::I64AtomicRmwAdd { .. }
|
||||
| Operator::I32AtomicRmw8UAdd { .. }
|
||||
| Operator::I32AtomicRmw16UAdd { .. }
|
||||
| Operator::I64AtomicRmw8UAdd { .. }
|
||||
| Operator::I64AtomicRmw16UAdd { .. }
|
||||
| Operator::I64AtomicRmw32UAdd { .. }
|
||||
| Operator::I32AtomicRmw8AddU { .. }
|
||||
| Operator::I32AtomicRmw16AddU { .. }
|
||||
| Operator::I64AtomicRmw8AddU { .. }
|
||||
| Operator::I64AtomicRmw16AddU { .. }
|
||||
| Operator::I64AtomicRmw32AddU { .. }
|
||||
| Operator::I32AtomicRmwSub { .. }
|
||||
| Operator::I64AtomicRmwSub { .. }
|
||||
| Operator::I32AtomicRmw8USub { .. }
|
||||
| Operator::I32AtomicRmw16USub { .. }
|
||||
| Operator::I64AtomicRmw8USub { .. }
|
||||
| Operator::I64AtomicRmw16USub { .. }
|
||||
| Operator::I64AtomicRmw32USub { .. }
|
||||
| Operator::I32AtomicRmw8SubU { .. }
|
||||
| Operator::I32AtomicRmw16SubU { .. }
|
||||
| Operator::I64AtomicRmw8SubU { .. }
|
||||
| Operator::I64AtomicRmw16SubU { .. }
|
||||
| Operator::I64AtomicRmw32SubU { .. }
|
||||
| Operator::I32AtomicRmwAnd { .. }
|
||||
| Operator::I64AtomicRmwAnd { .. }
|
||||
| Operator::I32AtomicRmw8UAnd { .. }
|
||||
| Operator::I32AtomicRmw16UAnd { .. }
|
||||
| Operator::I64AtomicRmw8UAnd { .. }
|
||||
| Operator::I64AtomicRmw16UAnd { .. }
|
||||
| Operator::I64AtomicRmw32UAnd { .. }
|
||||
| Operator::I32AtomicRmw8AndU { .. }
|
||||
| Operator::I32AtomicRmw16AndU { .. }
|
||||
| Operator::I64AtomicRmw8AndU { .. }
|
||||
| Operator::I64AtomicRmw16AndU { .. }
|
||||
| Operator::I64AtomicRmw32AndU { .. }
|
||||
| Operator::I32AtomicRmwOr { .. }
|
||||
| Operator::I64AtomicRmwOr { .. }
|
||||
| Operator::I32AtomicRmw8UOr { .. }
|
||||
| Operator::I32AtomicRmw16UOr { .. }
|
||||
| Operator::I64AtomicRmw8UOr { .. }
|
||||
| Operator::I64AtomicRmw16UOr { .. }
|
||||
| Operator::I64AtomicRmw32UOr { .. }
|
||||
| Operator::I32AtomicRmw8OrU { .. }
|
||||
| Operator::I32AtomicRmw16OrU { .. }
|
||||
| Operator::I64AtomicRmw8OrU { .. }
|
||||
| Operator::I64AtomicRmw16OrU { .. }
|
||||
| Operator::I64AtomicRmw32OrU { .. }
|
||||
| Operator::I32AtomicRmwXor { .. }
|
||||
| Operator::I64AtomicRmwXor { .. }
|
||||
| Operator::I32AtomicRmw8UXor { .. }
|
||||
| Operator::I32AtomicRmw16UXor { .. }
|
||||
| Operator::I64AtomicRmw8UXor { .. }
|
||||
| Operator::I64AtomicRmw16UXor { .. }
|
||||
| Operator::I64AtomicRmw32UXor { .. }
|
||||
| Operator::I32AtomicRmw8XorU { .. }
|
||||
| Operator::I32AtomicRmw16XorU { .. }
|
||||
| Operator::I64AtomicRmw8XorU { .. }
|
||||
| Operator::I64AtomicRmw16XorU { .. }
|
||||
| Operator::I64AtomicRmw32XorU { .. }
|
||||
| Operator::I32AtomicRmwXchg { .. }
|
||||
| Operator::I64AtomicRmwXchg { .. }
|
||||
| Operator::I32AtomicRmw8UXchg { .. }
|
||||
| Operator::I32AtomicRmw16UXchg { .. }
|
||||
| Operator::I64AtomicRmw8UXchg { .. }
|
||||
| Operator::I64AtomicRmw16UXchg { .. }
|
||||
| Operator::I64AtomicRmw32UXchg { .. }
|
||||
| Operator::I32AtomicRmw8XchgU { .. }
|
||||
| Operator::I32AtomicRmw16XchgU { .. }
|
||||
| Operator::I64AtomicRmw8XchgU { .. }
|
||||
| Operator::I64AtomicRmw16XchgU { .. }
|
||||
| Operator::I64AtomicRmw32XchgU { .. }
|
||||
| Operator::I32AtomicRmwCmpxchg { .. }
|
||||
| Operator::I64AtomicRmwCmpxchg { .. }
|
||||
| Operator::I32AtomicRmw8UCmpxchg { .. }
|
||||
| Operator::I32AtomicRmw16UCmpxchg { .. }
|
||||
| Operator::I64AtomicRmw8UCmpxchg { .. }
|
||||
| Operator::I64AtomicRmw16UCmpxchg { .. }
|
||||
| Operator::I64AtomicRmw32UCmpxchg { .. }
|
||||
| Operator::Fence { .. } => {
|
||||
| Operator::I32AtomicRmw8CmpxchgU { .. }
|
||||
| Operator::I32AtomicRmw16CmpxchgU { .. }
|
||||
| Operator::I64AtomicRmw8CmpxchgU { .. }
|
||||
| Operator::I64AtomicRmw16CmpxchgU { .. }
|
||||
| Operator::I64AtomicRmw32CmpxchgU { .. }
|
||||
| Operator::AtomicFence { .. } => {
|
||||
return Err(wasm_unsupported!("proposed thread operator {:?}", op));
|
||||
}
|
||||
Operator::MemoryCopy => {
|
||||
|
@ -1039,7 +1080,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
table,
|
||||
)?);
|
||||
}
|
||||
Operator::TableCopy => {
|
||||
Operator::TableCopy { .. } => {
|
||||
// The WebAssembly MVP only supports one table and wasmparser will
|
||||
// ensure that the table index specified is zero.
|
||||
let dst_table_index = 0;
|
||||
|
@ -1060,7 +1101,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
len,
|
||||
)?;
|
||||
}
|
||||
Operator::TableInit { segment } => {
|
||||
Operator::TableInit { segment, table: _ } => {
|
||||
// The WebAssembly MVP only supports one table and we assume it here.
|
||||
let table_index = 0;
|
||||
let table = state.get_table(builder.func, table_index, environ)?;
|
||||
|
@ -1077,6 +1118,9 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
len,
|
||||
)?;
|
||||
}
|
||||
Operator::TableFill { .. } => {
|
||||
return Err(wasm_unsupported!("proposed table operator {:?}", op));
|
||||
}
|
||||
Operator::ElemDrop { segment } => {
|
||||
environ.translate_elem_drop(builder.cursor(), *segment)?;
|
||||
}
|
||||
|
@ -1183,6 +1227,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
|
||||
state.push1(builder.ins().imul(a, b))
|
||||
}
|
||||
Operator::V128AndNot => {
|
||||
let (a, b) = pop2_with_bitcast(state, type_of(op), builder);
|
||||
state.push1(builder.ins().band_not(a, b))
|
||||
}
|
||||
Operator::V128Not => {
|
||||
let a = state.pop1();
|
||||
state.push1(builder.ins().bnot(a));
|
||||
|
@ -1330,20 +1378,41 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
| Operator::I8x16ShrS
|
||||
| Operator::I8x16ShrU
|
||||
| Operator::I8x16Mul
|
||||
| Operator::I64x2Mul
|
||||
| Operator::I64x2ShrS
|
||||
| Operator::I32x4TruncSF32x4Sat
|
||||
| Operator::I32x4TruncUF32x4Sat
|
||||
| Operator::I64x2TruncSF64x2Sat
|
||||
| Operator::I64x2TruncUF64x2Sat
|
||||
| Operator::F32x4ConvertSI32x4
|
||||
| Operator::F32x4ConvertUI32x4
|
||||
| Operator::F64x2ConvertSI64x2
|
||||
| Operator::F64x2ConvertUI64x2 { .. }
|
||||
| Operator::I32x4TruncSatF32x4S
|
||||
| Operator::I32x4TruncSatF32x4U
|
||||
| Operator::I64x2TruncSatF64x2S
|
||||
| Operator::I64x2TruncSatF64x2U
|
||||
| Operator::F32x4ConvertI32x4S
|
||||
| Operator::F32x4ConvertI32x4U
|
||||
| Operator::F64x2ConvertI64x2S
|
||||
| Operator::F64x2ConvertI64x2U { .. }
|
||||
| Operator::I8x16NarrowI16x8S { .. }
|
||||
| Operator::I8x16NarrowI16x8U { .. }
|
||||
| Operator::I16x8NarrowI32x4S { .. }
|
||||
| Operator::I16x8NarrowI32x4U { .. }
|
||||
| Operator::I16x8WidenLowI8x16S { .. }
|
||||
| Operator::I16x8WidenHighI8x16S { .. }
|
||||
| Operator::I16x8WidenLowI8x16U { .. }
|
||||
| Operator::I16x8WidenHighI8x16U { .. }
|
||||
| Operator::I32x4WidenLowI16x8S { .. }
|
||||
| Operator::I32x4WidenHighI16x8S { .. }
|
||||
| Operator::I32x4WidenLowI16x8U { .. }
|
||||
| Operator::I32x4WidenHighI16x8U { .. }
|
||||
| Operator::V8x16Swizzle
|
||||
| Operator::I8x16LoadSplat { .. }
|
||||
| Operator::I16x8LoadSplat { .. }
|
||||
| Operator::I32x4LoadSplat { .. }
|
||||
| Operator::I64x2LoadSplat { .. } => {
|
||||
| Operator::V8x16LoadSplat { .. }
|
||||
| Operator::V16x8LoadSplat { .. }
|
||||
| Operator::V32x4LoadSplat { .. }
|
||||
| Operator::V64x2LoadSplat { .. }
|
||||
| Operator::I16x8Load8x8S { .. }
|
||||
| Operator::I16x8Load8x8U { .. }
|
||||
| Operator::I32x4Load16x4S { .. }
|
||||
| Operator::I32x4Load16x4U { .. }
|
||||
| Operator::I64x2Load32x2S { .. }
|
||||
| Operator::I64x2Load32x2U { .. }
|
||||
| Operator::I8x16RoundingAverageU { .. }
|
||||
| Operator::I16x8RoundingAverageU { .. } => {
|
||||
return Err(wasm_unsupported!("proposed SIMD operator {:?}", op));
|
||||
}
|
||||
};
|
||||
|
@ -1604,6 +1673,11 @@ fn translate_br_if(
|
|||
) {
|
||||
let val = state.pop1();
|
||||
let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_types = builder.func.dfg.ebb_param_types(br_destination);
|
||||
bitcast_arguments(inputs, &destination_types[..inputs.len()], builder);
|
||||
|
||||
builder.ins().brnz(val, br_destination, inputs);
|
||||
|
||||
#[cfg(feature = "basic-blocks")]
|
||||
|
@ -1618,7 +1692,7 @@ fn translate_br_if(
|
|||
fn translate_br_if_args(
|
||||
relative_depth: u32,
|
||||
state: &mut FuncTranslationState,
|
||||
) -> (ir::Ebb, &[ir::Value]) {
|
||||
) -> (ir::Ebb, &mut [ir::Value]) {
|
||||
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
||||
let (return_count, br_destination) = {
|
||||
let frame = &mut state.control_stack[i];
|
||||
|
@ -1632,7 +1706,7 @@ fn translate_br_if_args(
|
|||
};
|
||||
(return_count, frame.br_destination())
|
||||
};
|
||||
let inputs = state.peekn(return_count);
|
||||
let inputs = state.peekn_mut(return_count);
|
||||
(br_destination, inputs)
|
||||
}
|
||||
|
||||
|
@ -1644,6 +1718,7 @@ fn type_of(operator: &Operator) -> Type {
|
|||
| Operator::V128Const { .. }
|
||||
| Operator::V128Not
|
||||
| Operator::V128And
|
||||
| Operator::V128AndNot
|
||||
| Operator::V128Or
|
||||
| Operator::V128Xor
|
||||
| Operator::V128Bitselect => I8X16, // default type representing V128
|
||||
|
@ -1727,8 +1802,8 @@ fn type_of(operator: &Operator) -> Type {
|
|||
| Operator::I32x4Add
|
||||
| Operator::I32x4Sub
|
||||
| Operator::I32x4Mul
|
||||
| Operator::F32x4ConvertSI32x4
|
||||
| Operator::F32x4ConvertUI32x4 => I32X4,
|
||||
| Operator::F32x4ConvertI32x4S
|
||||
| Operator::F32x4ConvertI32x4U => I32X4,
|
||||
|
||||
Operator::I64x2Splat
|
||||
| Operator::I64x2ExtractLane { .. }
|
||||
|
@ -1741,8 +1816,8 @@ fn type_of(operator: &Operator) -> Type {
|
|||
| Operator::I64x2ShrU
|
||||
| Operator::I64x2Add
|
||||
| Operator::I64x2Sub
|
||||
| Operator::F64x2ConvertSI64x2
|
||||
| Operator::F64x2ConvertUI64x2 => I64X2,
|
||||
| Operator::F64x2ConvertI64x2S
|
||||
| Operator::F64x2ConvertI64x2U => I64X2,
|
||||
|
||||
Operator::F32x4Splat
|
||||
| Operator::F32x4ExtractLane { .. }
|
||||
|
@ -1762,8 +1837,8 @@ fn type_of(operator: &Operator) -> Type {
|
|||
| Operator::F32x4Div
|
||||
| Operator::F32x4Min
|
||||
| Operator::F32x4Max
|
||||
| Operator::I32x4TruncSF32x4Sat
|
||||
| Operator::I32x4TruncUF32x4Sat => F32X4,
|
||||
| Operator::I32x4TruncSatF32x4S
|
||||
| Operator::I32x4TruncSatF32x4U => F32X4,
|
||||
|
||||
Operator::F64x2Splat
|
||||
| Operator::F64x2ExtractLane { .. }
|
||||
|
@ -1783,11 +1858,12 @@ fn type_of(operator: &Operator) -> Type {
|
|||
| Operator::F64x2Div
|
||||
| Operator::F64x2Min
|
||||
| Operator::F64x2Max
|
||||
| Operator::I64x2TruncSF64x2Sat
|
||||
| Operator::I64x2TruncUF64x2Sat => F64X2,
|
||||
| Operator::I64x2TruncSatF64x2S
|
||||
| Operator::I64x2TruncSatF64x2U => F64X2,
|
||||
|
||||
_ => unimplemented!(
|
||||
"Currently only the SIMD instructions are translated to their return type: {:?}",
|
||||
"Currently only SIMD instructions are mapped to their return type; the \
|
||||
following instruction is not mapped: {:?}",
|
||||
operator
|
||||
),
|
||||
}
|
||||
|
@ -1795,7 +1871,7 @@ fn type_of(operator: &Operator) -> Type {
|
|||
|
||||
/// Some SIMD operations only operate on I8X16 in CLIF; this will convert them to that type by
|
||||
/// adding a raw_bitcast if necessary.
|
||||
fn optionally_bitcast_vector(
|
||||
pub fn optionally_bitcast_vector(
|
||||
value: Value,
|
||||
needed_type: Type,
|
||||
builder: &mut FunctionBuilder,
|
||||
|
@ -1831,3 +1907,28 @@ fn pop2_with_bitcast(
|
|||
let bitcast_b = optionally_bitcast_vector(b, needed_type, builder);
|
||||
(bitcast_a, bitcast_b)
|
||||
}
|
||||
|
||||
/// A helper for bitcasting a sequence of values (e.g. function arguments). If a value is a
|
||||
/// vector type that does not match its expected type, this will modify the value in place to point
|
||||
/// to the result of a `raw_bitcast`. This conversion is necessary to translate Wasm code that
|
||||
/// uses `V128` as function parameters (or implicitly in EBB parameters) and still use specific
|
||||
/// CLIF types (e.g. `I32X4`) in the function body.
|
||||
pub fn bitcast_arguments(
|
||||
arguments: &mut [Value],
|
||||
expected_types: &[Type],
|
||||
builder: &mut FunctionBuilder,
|
||||
) {
|
||||
assert_eq!(arguments.len(), expected_types.len());
|
||||
for (i, t) in expected_types.iter().enumerate() {
|
||||
if t.is_vector() {
|
||||
assert!(
|
||||
builder.func.dfg.value_type(arguments[i]).is_vector(),
|
||||
"unexpected type mismatch: expected {}, argument {} was actually of type {}",
|
||||
t,
|
||||
arguments[i],
|
||||
builder.func.dfg.value_type(arguments[i])
|
||||
);
|
||||
arguments[i] = optionally_bitcast_vector(arguments[i], *t, builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,12 @@ pub trait TargetEnvironment {
|
|||
/// IR. The function environment provides information about the WebAssembly module as well as the
|
||||
/// runtime environment.
|
||||
pub trait FuncEnvironment: TargetEnvironment {
|
||||
/// Is the given parameter of the given function a wasm-level parameter, as opposed to a hidden
|
||||
/// parameter added for use by the implementation?
|
||||
fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
|
||||
signature.params[index].purpose == ir::ArgumentPurpose::Normal
|
||||
}
|
||||
|
||||
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
|
||||
/// of the function body, rather than `return` instructions as needed? This is used by VMs
|
||||
/// to append custom epilogues.
|
||||
|
@ -302,6 +308,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||
/// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
|
||||
/// returned by `make_heap` for the same index. `seg_index` is the index of the segment to copy
|
||||
/// from.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn translate_memory_init(
|
||||
&mut self,
|
||||
pos: FuncCursor,
|
||||
|
@ -325,6 +332,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||
) -> WasmResult<ir::Value>;
|
||||
|
||||
/// Translate a `table.copy` WebAssembly instruction.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn translate_table_copy(
|
||||
&mut self,
|
||||
pos: FuncCursor,
|
||||
|
@ -338,6 +346,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||
) -> WasmResult<()>;
|
||||
|
||||
/// Translate a `table.init` WebAssembly instruction.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn translate_table_init(
|
||||
&mut self,
|
||||
pos: FuncCursor,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! function to Cranelift IR guided by a `FuncEnvironment` which provides information about the
|
||||
//! WebAssembly module and the runtime environment.
|
||||
|
||||
use crate::code_translator::translate_operator;
|
||||
use crate::code_translator::{bitcast_arguments, translate_operator};
|
||||
use crate::environ::{FuncEnvironment, ReturnMode, WasmResult};
|
||||
use crate::state::{FuncTranslationState, ModuleTranslationState};
|
||||
use crate::translation_utils::get_vmctx_value_label;
|
||||
|
@ -99,7 +99,7 @@ impl FuncTranslator {
|
|||
// `environ`. The callback functions may need to insert things in the entry block.
|
||||
builder.ensure_inserted_ebb();
|
||||
|
||||
let num_params = declare_wasm_parameters(&mut builder, entry_block);
|
||||
let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
|
||||
|
||||
// Set up the translation state with a single pushed control block representing the whole
|
||||
// function and its return values.
|
||||
|
@ -124,14 +124,18 @@ impl FuncTranslator {
|
|||
/// Declare local variables for the signature parameters that correspond to WebAssembly locals.
|
||||
///
|
||||
/// Return the number of local variables declared.
|
||||
fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> usize {
|
||||
fn declare_wasm_parameters<FE: FuncEnvironment + ?Sized>(
|
||||
builder: &mut FunctionBuilder,
|
||||
entry_block: Ebb,
|
||||
environ: &FE,
|
||||
) -> usize {
|
||||
let sig_len = builder.func.signature.params.len();
|
||||
let mut next_local = 0;
|
||||
for i in 0..sig_len {
|
||||
let param_type = builder.func.signature.params[i];
|
||||
// There may be additional special-purpose parameters following the normal WebAssembly
|
||||
// There may be additional special-purpose parameters in addition to the normal WebAssembly
|
||||
// signature parameters. For example, a `vmctx` pointer.
|
||||
if param_type.purpose == ir::ArgumentPurpose::Normal {
|
||||
if environ.is_wasm_parameter(&builder.func.signature, i) {
|
||||
// This is a normal WebAssembly signature parameter, so create a local for it.
|
||||
let local = Variable::new(next_local);
|
||||
builder.declare_var(local, param_type.value_type);
|
||||
|
@ -240,7 +244,11 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
|||
debug_assert!(builder.is_pristine());
|
||||
if !builder.is_unreachable() {
|
||||
match environ.return_mode() {
|
||||
ReturnMode::NormalReturns => builder.ins().return_(&state.stack),
|
||||
ReturnMode::NormalReturns => {
|
||||
let return_types = &builder.func.signature.return_types();
|
||||
bitcast_arguments(&mut state.stack, &return_types, builder);
|
||||
builder.ins().return_(&state.stack)
|
||||
}
|
||||
ReturnMode::FallthroughReturn => builder.ins().fallthrough_return(&state.stack),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! The special case of the initialize expressions for table elements offsets or global variables
|
||||
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
||||
//! interpreted on the fly.
|
||||
use crate::environ::{ModuleEnvironment, WasmResult};
|
||||
use crate::environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||
use crate::state::ModuleTranslationState;
|
||||
use crate::translation_utils::{
|
||||
tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||
|
@ -17,14 +17,15 @@ use crate::{wasm_unsupported, HashMap};
|
|||
use core::convert::TryFrom;
|
||||
use cranelift_codegen::ir::immediates::V128Imm;
|
||||
use cranelift_codegen::ir::{self, AbiParam, Signature};
|
||||
use cranelift_entity::packed_option::ReservedValue;
|
||||
use cranelift_entity::EntityRef;
|
||||
use std::vec::Vec;
|
||||
use wasmparser::{
|
||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind,
|
||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementKind,
|
||||
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
|
||||
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
||||
ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader,
|
||||
Operator, TableSectionReader, TypeSectionReader,
|
||||
Operator, TableSectionReader, Type, TypeSectionReader,
|
||||
};
|
||||
|
||||
/// Parses the Type section of the wasm module.
|
||||
|
@ -141,7 +142,13 @@ pub fn parse_function_section(
|
|||
functions: FunctionSectionReader,
|
||||
environ: &mut dyn ModuleEnvironment,
|
||||
) -> WasmResult<()> {
|
||||
environ.reserve_func_types(functions.get_count())?;
|
||||
let num_functions = functions.get_count();
|
||||
if num_functions == std::u32::MAX {
|
||||
// We reserve `u32::MAX` for our own use in cranelift-entity.
|
||||
return Err(WasmError::ImplLimitExceeded);
|
||||
}
|
||||
|
||||
environ.reserve_func_types(num_functions)?;
|
||||
|
||||
for entry in functions {
|
||||
let sigindex = entry?;
|
||||
|
@ -217,7 +224,7 @@ pub fn parse_global_section(
|
|||
GlobalInit::V128Const(V128Imm::from(value.bytes().to_vec().as_slice()))
|
||||
}
|
||||
Operator::RefNull => GlobalInit::RefNullConst,
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
|
||||
}
|
||||
ref s => {
|
||||
|
@ -286,7 +293,13 @@ pub fn parse_element_section<'data>(
|
|||
environ.reserve_table_elements(elements.get_count())?;
|
||||
|
||||
for entry in elements {
|
||||
let Element { kind, items } = entry?;
|
||||
let Element { kind, items, ty } = entry?;
|
||||
if ty != Type::AnyFunc {
|
||||
return Err(wasm_unsupported!(
|
||||
"unsupported table element type: {:?}",
|
||||
ty
|
||||
));
|
||||
}
|
||||
if let ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
|
@ -295,7 +308,7 @@ pub fn parse_element_section<'data>(
|
|||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
(Some(GlobalIndex::from_u32(global_index)), 0)
|
||||
}
|
||||
ref s => {
|
||||
|
@ -308,8 +321,11 @@ pub fn parse_element_section<'data>(
|
|||
let items_reader = items.get_items_reader()?;
|
||||
let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap());
|
||||
for item in items_reader {
|
||||
let x = item?;
|
||||
elems.push(FuncIndex::from_u32(x));
|
||||
let elem = match item? {
|
||||
ElementItem::Null => FuncIndex::reserved_value(),
|
||||
ElementItem::Func(index) => FuncIndex::from_u32(index),
|
||||
};
|
||||
elems.push(elem);
|
||||
}
|
||||
environ.declare_table_elements(
|
||||
TableIndex::from_u32(table_index),
|
||||
|
@ -318,10 +334,7 @@ pub fn parse_element_section<'data>(
|
|||
elems.into_boxed_slice(),
|
||||
)?
|
||||
} else {
|
||||
return Err(wasm_unsupported!(
|
||||
"unsupported passive elements section: {:?}",
|
||||
kind
|
||||
));
|
||||
return Err(wasm_unsupported!("unsupported passive elements section",));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -359,7 +372,7 @@ pub fn parse_data_section<'data>(
|
|||
let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
(Some(GlobalIndex::from_u32(global_index)), 0)
|
||||
}
|
||||
ref s => {
|
||||
|
@ -417,6 +430,11 @@ fn parse_function_name_subsection(
|
|||
let mut function_names = HashMap::new();
|
||||
for _ in 0..naming_reader.get_count() {
|
||||
let Naming { index, name } = naming_reader.read().ok()?;
|
||||
if index == std::u32::MAX {
|
||||
// We reserve `u32::MAX` for our own use in cranelift-entity.
|
||||
return None;
|
||||
}
|
||||
|
||||
if function_names
|
||||
.insert(FuncIndex::from_u32(index), name)
|
||||
.is_some()
|
||||
|
|
|
@ -306,31 +306,40 @@ impl FuncTranslationState {
|
|||
(v1, v2, v3)
|
||||
}
|
||||
|
||||
/// Helper to ensure the the stack size is at least as big as `n`; note that due to
|
||||
/// `debug_assert` this will not execute in non-optimized builds.
|
||||
#[inline]
|
||||
fn ensure_length_is_at_least(&self, n: usize) {
|
||||
debug_assert!(
|
||||
n <= self.stack.len(),
|
||||
"attempted to access {} values but stack only has {} values",
|
||||
n,
|
||||
self.stack.len()
|
||||
)
|
||||
}
|
||||
|
||||
/// Pop the top `n` values on the stack.
|
||||
///
|
||||
/// The popped values are not returned. Use `peekn` to look at them before popping.
|
||||
pub(crate) fn popn(&mut self, n: usize) {
|
||||
debug_assert!(
|
||||
n <= self.stack.len(),
|
||||
"popn({}) but stack only has {} values",
|
||||
n,
|
||||
self.stack.len()
|
||||
);
|
||||
self.ensure_length_is_at_least(n);
|
||||
let new_len = self.stack.len() - n;
|
||||
self.stack.truncate(new_len);
|
||||
}
|
||||
|
||||
/// Peek at the top `n` values on the stack in the order they were pushed.
|
||||
pub(crate) fn peekn(&self, n: usize) -> &[Value] {
|
||||
debug_assert!(
|
||||
n <= self.stack.len(),
|
||||
"peekn({}) but stack only has {} values",
|
||||
n,
|
||||
self.stack.len()
|
||||
);
|
||||
self.ensure_length_is_at_least(n);
|
||||
&self.stack[self.stack.len() - n..]
|
||||
}
|
||||
|
||||
/// Peek at the top `n` values on the stack in the order they were pushed.
|
||||
pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
|
||||
self.ensure_length_is_at_least(n);
|
||||
let len = self.stack.len();
|
||||
&mut self.stack[len - n..]
|
||||
}
|
||||
|
||||
/// Push a block on the control stack.
|
||||
pub(crate) fn push_block(
|
||||
&mut self,
|
||||
|
@ -465,7 +474,7 @@ impl FuncTranslationState {
|
|||
Occupied(entry) => Ok(*entry.get()),
|
||||
Vacant(entry) => {
|
||||
let sig = environ.make_indirect_sig(func, index)?;
|
||||
Ok(*entry.insert((sig, normal_args(&func.dfg.signatures[sig]))))
|
||||
Ok(*entry.insert((sig, num_wasm_parameters(environ, &func.dfg.signatures[sig]))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -486,17 +495,20 @@ impl FuncTranslationState {
|
|||
Vacant(entry) => {
|
||||
let fref = environ.make_direct_func(func, index)?;
|
||||
let sig = func.dfg.ext_funcs[fref].signature;
|
||||
Ok(*entry.insert((fref, normal_args(&func.dfg.signatures[sig]))))
|
||||
Ok(*entry.insert((
|
||||
fref,
|
||||
num_wasm_parameters(environ, &func.dfg.signatures[sig]),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Count the number of normal parameters in a signature.
|
||||
/// Exclude special-purpose parameters that represent runtime stuff and not WebAssembly arguments.
|
||||
fn normal_args(sig: &ir::Signature) -> usize {
|
||||
sig.params
|
||||
.iter()
|
||||
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
||||
fn num_wasm_parameters<FE: FuncEnvironment + ?Sized>(
|
||||
environ: &FE,
|
||||
signature: &ir::Signature,
|
||||
) -> usize {
|
||||
(0..signature.params.len())
|
||||
.filter(|index| environ.is_wasm_parameter(signature, *index))
|
||||
.count()
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ use std::io::prelude::*;
|
|||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use target_lexicon::triple;
|
||||
use wabt::{wat2wasm_with_features, Features, Wat2Wasm};
|
||||
|
||||
#[test]
|
||||
fn testsuite() {
|
||||
|
@ -47,15 +46,14 @@ fn use_fallthrough_return() {
|
|||
|
||||
#[test]
|
||||
fn use_name_section() {
|
||||
let wat = r#"
|
||||
let data = wat::parse_str(
|
||||
r#"
|
||||
(module $module_name
|
||||
(func $func_name (local $loc_name i32)
|
||||
)
|
||||
)"#;
|
||||
let data = Wat2Wasm::new()
|
||||
.write_debug_names(true)
|
||||
.convert(wat)
|
||||
.unwrap_or_else(|e| panic!("error converting wat to wasm: {:?}", e));
|
||||
)"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let flags = Flags::new(settings::builder());
|
||||
let triple = triple!("riscv64");
|
||||
|
@ -79,23 +77,13 @@ fn read_file(path: &Path) -> io::Result<Vec<u8>> {
|
|||
}
|
||||
|
||||
fn read_module(path: &Path) -> Vec<u8> {
|
||||
let mut features = Features::new();
|
||||
features.enable_all();
|
||||
match path.extension() {
|
||||
None => {
|
||||
panic!("the file extension is not wasm or wat");
|
||||
}
|
||||
Some(ext) => match ext.to_str() {
|
||||
Some("wasm") => read_file(path).expect("error reading wasm file"),
|
||||
Some("wat") => {
|
||||
let wat = read_file(path).expect("error reading wat file");
|
||||
match wat2wasm_with_features(&wat, features) {
|
||||
Ok(wasm) => wasm,
|
||||
Err(e) => {
|
||||
panic!("error converting wat to wasm: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some("wat") => wat::parse_file(path).expect("failed to parse wat"),
|
||||
None | Some(&_) => panic!("the file extension for {:?} is not wasm or wat", path),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.lock":"a1a162e6ce8fc2234a6ddf7090410006a1920ace8738772e32a5b50e4780c19d","Cargo.toml":"f3b545fa0f184fd0d3624e6e5c205fcbdf1ad0934a2e08406549ad53c2a62ac3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","build.rs":"723100e9cdc30cd8c48407233c2cffa10f5b10703a0a11bac1230d8b86e49ccf","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","newlist":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"4414353c30f25d44df6cc14f7f9eea9991222289c6aa662b74406f6923235970","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"9ccc0849cff06d8906dacbdc15136cc47fab85ccd795033ddfdde1397dfcfe32","src/triple.rs":"949bd83b043b53b18f643ebc3fbebbfe02a13998b787fda432a5d36aa27d20bd","test.sh":"22e3c630a6c84e90d5c70c367a6712be8eeca1e7682c00d1f65bf53e330e9191"},"package":"6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"}
|
|
@ -0,0 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.9.0"
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "target-lexicon"
|
||||
version = "0.9.0"
|
||||
authors = ["Dan Gohman <sunfish@mozilla.com>"]
|
||||
description = "Targeting utilities for compilers and related tools"
|
||||
documentation = "https://docs.rs/target-lexicon/"
|
||||
readme = "README.md"
|
||||
keywords = ["target", "host", "triple", "compiler", "jit"]
|
||||
categories = ["no-std"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/target-lexicon"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
std = []
|
||||
[badges.maintenance]
|
||||
status = "passively-maintained"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "CraneStation/target-lexicon"
|
|
@ -0,0 +1,220 @@
|
|||
|
||||
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.
|
||||
|
||||
|
||||
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
This is a library for managing targets for compilers and related tools.
|
||||
|
||||
Currently, the main feature is support for decoding "triples", which
|
||||
are strings that identify a particular target configuration. They're named
|
||||
"triples" because historically they contained three fields, though over time
|
||||
they've added additional fields. This library provides a `Triple` struct
|
||||
containing enums for each of fields of a triple. `Triple` implements
|
||||
`FromStr` and `fmt::Display` so it can be converted to and from the
|
||||
conventional string representation of a triple.
|
||||
|
||||
`Triple` also has functions for querying a triple's endianness,
|
||||
pointer bit width, and binary format.
|
||||
|
||||
And, `Triple` and the enum types have `host()` constructors, for targeting
|
||||
the host.
|
||||
|
||||
It supports all triples currently used by rustc and rustup.
|
||||
|
||||
It does not support reading JSON target files itself. To use it with a JSON
|
||||
target file, construct a `Triple` using the value of the "llvm-target" field.
|
|
@ -0,0 +1,162 @@
|
|||
//! build.rs file to obtain the host information.
|
||||
|
||||
// Allow dead code in triple.rs and targets.rs for our purposes here.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// Include triple.rs and targets.rs so we can parse the TARGET environment variable.
|
||||
mod triple {
|
||||
include!("src/triple.rs");
|
||||
}
|
||||
mod targets {
|
||||
include!("src/targets.rs");
|
||||
}
|
||||
|
||||
// Stub out `ParseError` to minimally support triple.rs and targets.rs.
|
||||
mod parse_error {
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
UnrecognizedArchitecture(String),
|
||||
UnrecognizedVendor(String),
|
||||
UnrecognizedOperatingSystem(String),
|
||||
UnrecognizedEnvironment(String),
|
||||
UnrecognizedBinaryFormat(String),
|
||||
UnrecognizedField(String),
|
||||
}
|
||||
}
|
||||
|
||||
use self::triple::Triple;
|
||||
|
||||
fn main() {
|
||||
let out_dir =
|
||||
PathBuf::from(env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"));
|
||||
let target = env::var("TARGET").expect("The TARGET environment variable must be set");
|
||||
let triple = Triple::from_str(&target).expect(&format!("Invalid target name: '{}'", target));
|
||||
let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs");
|
||||
write_host_rs(out, triple).expect("error writing host.rs");
|
||||
}
|
||||
|
||||
fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
||||
// The generated Debug implementation for the inner architecture variants
|
||||
// doesn't print the enum name qualifier, so import them here. There
|
||||
// shouldn't be any conflicts because these enums all share a namespace
|
||||
// in the triple string format.
|
||||
writeln!(out, "#[allow(unused_imports)]")?;
|
||||
writeln!(out, "use crate::Aarch64Architecture::*;")?;
|
||||
writeln!(out, "#[allow(unused_imports)]")?;
|
||||
writeln!(out, "use crate::ArmArchitecture::*;")?;
|
||||
writeln!(out)?;
|
||||
writeln!(out, "/// The `Triple` of the current host.")?;
|
||||
writeln!(out, "pub const HOST: Triple = Triple {{")?;
|
||||
writeln!(
|
||||
out,
|
||||
" architecture: Architecture::{:?},",
|
||||
triple.architecture
|
||||
)?;
|
||||
writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?;
|
||||
writeln!(
|
||||
out,
|
||||
" operating_system: OperatingSystem::{:?},",
|
||||
triple.operating_system
|
||||
)?;
|
||||
writeln!(
|
||||
out,
|
||||
" environment: Environment::{:?},",
|
||||
triple.environment
|
||||
)?;
|
||||
writeln!(
|
||||
out,
|
||||
" binary_format: BinaryFormat::{:?},",
|
||||
triple.binary_format
|
||||
)?;
|
||||
writeln!(out, "}};")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl Architecture {{")?;
|
||||
writeln!(out, " /// Return the architecture for the current host.")?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " Architecture::{:?}", triple.architecture)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl Vendor {{")?;
|
||||
writeln!(out, " /// Return the vendor for the current host.")?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " Vendor::{:?}", triple.vendor)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl OperatingSystem {{")?;
|
||||
writeln!(
|
||||
out,
|
||||
" /// Return the operating system for the current host."
|
||||
)?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(
|
||||
out,
|
||||
" OperatingSystem::{:?}",
|
||||
triple.operating_system
|
||||
)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl Environment {{")?;
|
||||
writeln!(out, " /// Return the environment for the current host.")?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " Environment::{:?}", triple.environment)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl BinaryFormat {{")?;
|
||||
writeln!(
|
||||
out,
|
||||
" /// Return the binary format for the current host."
|
||||
)?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " BinaryFormat::{:?}", triple.binary_format)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
||||
writeln!(out, "impl Triple {{")?;
|
||||
writeln!(out, " /// Return the triple for the current host.")?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " Self {{")?;
|
||||
writeln!(
|
||||
out,
|
||||
" architecture: Architecture::{:?},",
|
||||
triple.architecture
|
||||
)?;
|
||||
writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?;
|
||||
writeln!(
|
||||
out,
|
||||
" operating_system: OperatingSystem::{:?},",
|
||||
triple.operating_system
|
||||
)?;
|
||||
writeln!(
|
||||
out,
|
||||
" environment: Environment::{:?},",
|
||||
triple.environment
|
||||
)?;
|
||||
writeln!(
|
||||
out,
|
||||
" binary_format: BinaryFormat::{:?},",
|
||||
triple.binary_format
|
||||
)?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
extern crate target_lexicon;
|
||||
|
||||
use target_lexicon::HOST;
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
"{}",
|
||||
HOST.pointer_width()
|
||||
.expect("architecture should be known")
|
||||
.bytes()
|
||||
);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
extern crate target_lexicon;
|
||||
|
||||
use core::str::FromStr;
|
||||
use target_lexicon::{Triple, HOST};
|
||||
|
||||
fn main() {
|
||||
println!("The host triple is {}.", HOST);
|
||||
|
||||
let e = Triple::from_str("riscv32-unknown-unknown")
|
||||
.expect("expected to recognize the RISC-V target")
|
||||
.endianness()
|
||||
.expect("expected to know the endianness of RISC-V");
|
||||
println!("The endianness of RISC-V is {:?}.", e);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
rustup target list | sed 's/ (.*//' > list.txt
|
||||
rustc +nightly --print target-list >> list.txt
|
||||
cat list.txt | sort | uniq |sed 's/\(.*\)/ "\1",/' > sorted.txt
|
||||
rm list.txt
|
|
@ -0,0 +1,56 @@
|
|||
use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor};
|
||||
|
||||
// Include the implementations of the `HOST` object containing information
|
||||
// about the current host.
|
||||
include!(concat!(env!("OUT_DIR"), "/host.rs"));
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_linux() {
|
||||
use super::*;
|
||||
assert_eq!(OperatingSystem::host(), OperatingSystem::Linux);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[test]
|
||||
fn test_macos() {
|
||||
use super::*;
|
||||
assert_eq!(OperatingSystem::host(), OperatingSystem::Darwin);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_windows() {
|
||||
use super::*;
|
||||
assert_eq!(OperatingSystem::host(), OperatingSystem::Windows);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
#[test]
|
||||
fn test_ptr16() {
|
||||
use super::*;
|
||||
assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 16);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[test]
|
||||
fn test_ptr32() {
|
||||
use super::*;
|
||||
assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 32);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_ptr64() {
|
||||
use super::*;
|
||||
assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_object() {
|
||||
use super::*;
|
||||
assert_eq!(HOST, Triple::host());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//! Target triple support.
|
||||
|
||||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod host;
|
||||
mod parse_error;
|
||||
mod targets;
|
||||
#[macro_use]
|
||||
mod triple;
|
||||
|
||||
pub use self::host::HOST;
|
||||
pub use self::parse_error::ParseError;
|
||||
pub use self::targets::{
|
||||
Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, Environment, OperatingSystem,
|
||||
Vendor,
|
||||
};
|
||||
pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple};
|
|
@ -0,0 +1,34 @@
|
|||
use alloc::string::String;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
/// An error returned from parsing a triple.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ParseError {
|
||||
UnrecognizedArchitecture(String),
|
||||
UnrecognizedVendor(String),
|
||||
UnrecognizedOperatingSystem(String),
|
||||
UnrecognizedEnvironment(String),
|
||||
UnrecognizedBinaryFormat(String),
|
||||
UnrecognizedField(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ParseError::*;
|
||||
match self {
|
||||
UnrecognizedArchitecture(msg) => write!(fmt, "Unrecognized architecture: {}", msg),
|
||||
UnrecognizedVendor(msg) => write!(fmt, "Unrecognized vendor: {}", msg),
|
||||
UnrecognizedOperatingSystem(msg) => {
|
||||
write!(fmt, "Unrecognized operating system: {}", msg)
|
||||
}
|
||||
UnrecognizedEnvironment(msg) => write!(fmt, "Unrecognized environment: {}", msg),
|
||||
UnrecognizedBinaryFormat(msg) => write!(fmt, "Unrecognized binary format: {}", msg),
|
||||
UnrecognizedField(msg) => write!(fmt, "Unrecognized field: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ParseError {}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,369 @@
|
|||
// This file defines the `Triple` type and support code shared by all targets.
|
||||
|
||||
use crate::parse_error::ParseError;
|
||||
use crate::targets::{
|
||||
default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment,
|
||||
OperatingSystem, Vendor,
|
||||
};
|
||||
use alloc::borrow::ToOwned;
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
|
||||
/// The target memory endianness.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Endianness {
|
||||
Little,
|
||||
Big,
|
||||
}
|
||||
|
||||
/// The width of a pointer (in the default address space).
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum PointerWidth {
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
}
|
||||
|
||||
impl PointerWidth {
|
||||
/// Return the number of bits in a pointer.
|
||||
pub fn bits(self) -> u8 {
|
||||
match self {
|
||||
PointerWidth::U16 => 16,
|
||||
PointerWidth::U32 => 32,
|
||||
PointerWidth::U64 => 64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of bytes in a pointer.
|
||||
///
|
||||
/// For these purposes, there are 8 bits in a byte.
|
||||
pub fn bytes(self) -> u8 {
|
||||
match self {
|
||||
PointerWidth::U16 => 2,
|
||||
PointerWidth::U32 => 4,
|
||||
PointerWidth::U64 => 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The calling convention, which specifies things like which registers are
|
||||
/// used for passing arguments, which registers are callee-saved, and so on.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum CallingConvention {
|
||||
/// "System V", which is used on most Unix-like platfoms. Note that the
|
||||
/// specific conventions vary between hardware architectures; for example,
|
||||
/// x86-32's "System V" is entirely different from x86-64's "System V".
|
||||
SystemV,
|
||||
|
||||
/// The WebAssembly C ABI.
|
||||
/// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md
|
||||
WasmBasicCAbi,
|
||||
|
||||
/// "Windows Fastcall", which is used on Windows. Note that like "System V",
|
||||
/// this varies between hardware architectures. On x86-32 it describes what
|
||||
/// Windows documentation calls "fastcall", and on x86-64 it describes what
|
||||
/// Windows documentation often just calls the Windows x64 calling convention
|
||||
/// (though the compiler still recognizes "fastcall" as an alias for it).
|
||||
WindowsFastcall,
|
||||
}
|
||||
|
||||
/// A target "triple". Historically such things had three fields, though they've
|
||||
/// added additional fields over time.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Triple {
|
||||
/// The "architecture" (and sometimes the subarchitecture).
|
||||
pub architecture: Architecture,
|
||||
/// The "vendor" (whatever that means).
|
||||
pub vendor: Vendor,
|
||||
/// The "operating system" (sometimes also the environment).
|
||||
pub operating_system: OperatingSystem,
|
||||
/// The "environment" on top of the operating system (often omitted for
|
||||
/// operating systems with a single predominant environment).
|
||||
pub environment: Environment,
|
||||
/// The "binary format" (rarely used).
|
||||
pub binary_format: BinaryFormat,
|
||||
}
|
||||
|
||||
impl Triple {
|
||||
/// Return the endianness of this target's architecture.
|
||||
pub fn endianness(&self) -> Result<Endianness, ()> {
|
||||
self.architecture.endianness()
|
||||
}
|
||||
|
||||
/// Return the pointer width of this target's architecture.
|
||||
pub fn pointer_width(&self) -> Result<PointerWidth, ()> {
|
||||
self.architecture.pointer_width()
|
||||
}
|
||||
|
||||
/// Return the default calling convention for the given target triple.
|
||||
pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
|
||||
Ok(match self.operating_system {
|
||||
OperatingSystem::Bitrig
|
||||
| OperatingSystem::Cloudabi
|
||||
| OperatingSystem::Darwin
|
||||
| OperatingSystem::Dragonfly
|
||||
| OperatingSystem::Freebsd
|
||||
| OperatingSystem::Fuchsia
|
||||
| OperatingSystem::Haiku
|
||||
| OperatingSystem::Ios
|
||||
| OperatingSystem::L4re
|
||||
| OperatingSystem::Linux
|
||||
| OperatingSystem::MacOSX { .. }
|
||||
| OperatingSystem::Netbsd
|
||||
| OperatingSystem::Openbsd
|
||||
| OperatingSystem::Redox
|
||||
| OperatingSystem::Solaris => CallingConvention::SystemV,
|
||||
OperatingSystem::Windows => CallingConvention::WindowsFastcall,
|
||||
OperatingSystem::Nebulet
|
||||
| OperatingSystem::Emscripten
|
||||
| OperatingSystem::Wasi
|
||||
| OperatingSystem::Unknown => match self.architecture {
|
||||
Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
|
||||
_ => return Err(()),
|
||||
},
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Triple {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
architecture: Architecture::Unknown,
|
||||
vendor: Vendor::Unknown,
|
||||
operating_system: OperatingSystem::Unknown,
|
||||
environment: Environment::Unknown,
|
||||
binary_format: BinaryFormat::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Architecture {
|
||||
fn default() -> Self {
|
||||
Architecture::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Vendor {
|
||||
fn default() -> Self {
|
||||
Vendor::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OperatingSystem {
|
||||
fn default() -> Self {
|
||||
OperatingSystem::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Environment {
|
||||
fn default() -> Self {
|
||||
Environment::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BinaryFormat {
|
||||
fn default() -> Self {
|
||||
BinaryFormat::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Triple {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let implied_binary_format = default_binary_format(&self);
|
||||
|
||||
write!(f, "{}", self.architecture)?;
|
||||
if self.vendor == Vendor::Unknown
|
||||
&& ((self.operating_system == OperatingSystem::Linux
|
||||
&& (self.environment == Environment::Android
|
||||
|| self.environment == Environment::Androideabi
|
||||
|| self.environment == Environment::Kernel))
|
||||
|| self.operating_system == OperatingSystem::Fuchsia
|
||||
|| self.operating_system == OperatingSystem::Wasi
|
||||
|| (self.operating_system == OperatingSystem::None_
|
||||
&& (self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Armv7r)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase)
|
||||
|| self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain)
|
||||
|| self.architecture == Architecture::Msp430
|
||||
|| self.architecture == Architecture::X86_64)))
|
||||
{
|
||||
// As a special case, omit the vendor for Android, Fuchsia, Wasi, and sometimes
|
||||
// None_, depending on the hardware architecture. This logic is entirely
|
||||
// ad-hoc, and is just sufficient to handle the current set of recognized
|
||||
// triples.
|
||||
write!(f, "-{}", self.operating_system)?;
|
||||
} else {
|
||||
write!(f, "-{}-{}", self.vendor, self.operating_system)?;
|
||||
}
|
||||
if self.environment != Environment::Unknown {
|
||||
write!(f, "-{}", self.environment)?;
|
||||
}
|
||||
|
||||
if self.binary_format != implied_binary_format {
|
||||
write!(f, "-{}", self.binary_format)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Triple {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut parts = s.split('-');
|
||||
let mut result = Self::default();
|
||||
let mut current_part;
|
||||
|
||||
current_part = parts.next();
|
||||
if let Some(s) = current_part {
|
||||
if let Ok(architecture) = Architecture::from_str(s) {
|
||||
result.architecture = architecture;
|
||||
current_part = parts.next();
|
||||
} else {
|
||||
// Insist that the triple start with a valid architecture.
|
||||
return Err(ParseError::UnrecognizedArchitecture(s.to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
let mut has_vendor = false;
|
||||
let mut has_operating_system = false;
|
||||
if let Some(s) = current_part {
|
||||
if let Ok(vendor) = Vendor::from_str(s) {
|
||||
has_vendor = true;
|
||||
result.vendor = vendor;
|
||||
current_part = parts.next();
|
||||
}
|
||||
}
|
||||
|
||||
if !has_operating_system {
|
||||
if let Some(s) = current_part {
|
||||
if let Ok(operating_system) = OperatingSystem::from_str(s) {
|
||||
has_operating_system = true;
|
||||
result.operating_system = operating_system;
|
||||
current_part = parts.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut has_environment = false;
|
||||
if let Some(s) = current_part {
|
||||
if let Ok(environment) = Environment::from_str(s) {
|
||||
has_environment = true;
|
||||
result.environment = environment;
|
||||
current_part = parts.next();
|
||||
}
|
||||
}
|
||||
|
||||
let mut has_binary_format = false;
|
||||
if let Some(s) = current_part {
|
||||
if let Ok(binary_format) = BinaryFormat::from_str(s) {
|
||||
has_binary_format = true;
|
||||
result.binary_format = binary_format;
|
||||
current_part = parts.next();
|
||||
}
|
||||
}
|
||||
|
||||
// The binary format is frequently omitted; if that's the case here,
|
||||
// infer it from the other fields.
|
||||
if !has_binary_format {
|
||||
result.binary_format = default_binary_format(&result);
|
||||
}
|
||||
|
||||
if let Some(s) = current_part {
|
||||
Err(
|
||||
if !has_vendor && !has_operating_system && !has_environment && !has_binary_format {
|
||||
ParseError::UnrecognizedVendor(s.to_owned())
|
||||
} else if !has_operating_system && !has_environment && !has_binary_format {
|
||||
ParseError::UnrecognizedOperatingSystem(s.to_owned())
|
||||
} else if !has_environment && !has_binary_format {
|
||||
ParseError::UnrecognizedEnvironment(s.to_owned())
|
||||
} else if !has_binary_format {
|
||||
ParseError::UnrecognizedBinaryFormat(s.to_owned())
|
||||
} else {
|
||||
ParseError::UnrecognizedField(s.to_owned())
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenient syntax for triple literals.
|
||||
///
|
||||
/// This currently expands to code that just calls `Triple::from_str` and does
|
||||
/// an `expect`, though in the future it would be cool to use procedural macros
|
||||
/// or so to report errors at compile time instead.
|
||||
#[macro_export]
|
||||
macro_rules! triple {
|
||||
($str:tt) => {
|
||||
target_lexicon::Triple::from_str($str).expect("invalid triple literal")
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_errors() {
|
||||
assert_eq!(
|
||||
Triple::from_str(""),
|
||||
Err(ParseError::UnrecognizedArchitecture("".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("foo"),
|
||||
Err(ParseError::UnrecognizedArchitecture("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-foo"),
|
||||
Err(ParseError::UnrecognizedVendor("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-foo"),
|
||||
Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown-foo"),
|
||||
Err(ParseError::UnrecognizedEnvironment("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown-unknown-foo"),
|
||||
Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"),
|
||||
Err(ParseError::UnrecognizedField("foo".to_owned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults() {
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown"),
|
||||
Ok(Triple::default())
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown-unknown"),
|
||||
Ok(Triple::default())
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-unknown-unknown-unknown"),
|
||||
Ok(Triple::default())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_properties() {
|
||||
assert_eq!(Triple::default().endianness(), Err(()));
|
||||
assert_eq!(Triple::default().pointer_width(), Err(()));
|
||||
assert_eq!(Triple::default().default_calling_convention(), Err(()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
set -oeu pipefail
|
||||
|
||||
|
||||
for trip in wasm32-unknown-unknown wasm32-wasi arm-unknown-linux-gnueabi aarch64-unknown-linux-gnu; do
|
||||
echo TARGET $trip
|
||||
cargo build --target $trip --all
|
||||
cp target/$trip/debug/build/target-lexicon-*/out/host.rs host.rs
|
||||
rustfmt host.rs
|
||||
diff -u target/$trip/debug/build/target-lexicon-*/out/host.rs host.rs
|
||||
done
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.lock":"a1a162e6ce8fc2234a6ddf7090410006a1920ace8738772e32a5b50e4780c19d","Cargo.toml":"f3b545fa0f184fd0d3624e6e5c205fcbdf1ad0934a2e08406549ad53c2a62ac3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","build.rs":"723100e9cdc30cd8c48407233c2cffa10f5b10703a0a11bac1230d8b86e49ccf","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","newlist":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"4414353c30f25d44df6cc14f7f9eea9991222289c6aa662b74406f6923235970","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"9ccc0849cff06d8906dacbdc15136cc47fab85ccd795033ddfdde1397dfcfe32","src/triple.rs":"949bd83b043b53b18f643ebc3fbebbfe02a13998b787fda432a5d36aa27d20bd","test.sh":"22e3c630a6c84e90d5c70c367a6712be8eeca1e7682c00d1f65bf53e330e9191"},"package":"6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"}
|
||||
{"files":{"Cargo.lock":"8e4587915716186b38c3e202791d595629d132256f27ad6869069bcac7e85253","Cargo.toml":"e3f845dc9dbe5f658993b69b09cd6ee8c4e00ef4dcc9fb083be2346f51effd04","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","a":"0063b040e749e5cc9c82e682c67c53ae1830500f0c4aa85507b1ca4ed8454886","build.rs":"85d6a1b6392b56946f48c0ff1526736a37fe012951bf3855709da1d6cfb4baa0","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","host.rs":"331a7217b0b5fae0d7c37bd6f5e8caa2762a220c51fb23f5cf354fa76d91974a","newlist":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","sorted.txt":"ea6d3912b5d1eba7be33e99f1dd45953d80863dad75c5fc0ed1cd8020373b974","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"89986c98b9a04e0f1e957e0127e23a53048a1f0d597493723c4bba031c2ca32d","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"f2048f06e3e2151a8181d8c92651fa45e64b8bfdfd18ead4b6c18ee7c9fb9003","src/triple.rs":"4704266fec8763bc70d230aad3608bdb790b51e41149056daa2ce0d5fdaef5a3","test.sh":"4458bbd0ece260fe335054b53caeb57d9022258d9a07b6b44b994f6ce2ca82c6"},"package":"ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"}
|
|
@ -2,5 +2,5 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "target-lexicon"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
authors = ["Dan Gohman <sunfish@mozilla.com>"]
|
||||
description = "Targeting utilities for compilers and related tools"
|
||||
documentation = "https://docs.rs/target-lexicon/"
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
diff --git a/src/targets.rs b/src/targets.rs
|
||||
index 6ae570e..3aa1044 100644
|
||||
--- a/src/targets.rs
|
||||
+++ b/src/targets.rs
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file defines all the identifier enums and target-aware logic.
|
||||
|
||||
use crate::triple::{Endianness, PointerWidth, Triple};
|
||||
+use alloc::string::String;
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
|
||||
@@ -292,7 +293,7 @@ impl Aarch64Architecture {
|
||||
|
||||
/// The "vendor" field, which in practice is little more than an arbitrary
|
||||
/// modifier.
|
||||
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Vendor {
|
||||
Unknown,
|
||||
@@ -306,6 +307,7 @@ pub enum Vendor {
|
||||
Sun,
|
||||
Uwp,
|
||||
Wrs,
|
||||
+ Custom(String),
|
||||
}
|
||||
|
||||
/// The "operating system" field, which sometimes implies an environment, and
|
||||
@@ -717,6 +719,7 @@ impl fmt::Display for Vendor {
|
||||
Vendor::Sun => "sun",
|
||||
Vendor::Uwp => "uwp",
|
||||
Vendor::Wrs => "wrs",
|
||||
+ Vendor::Custom(ref name) => name,
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
@@ -738,7 +741,20 @@ impl FromStr for Vendor {
|
||||
"sun" => Vendor::Sun,
|
||||
"uwp" => Vendor::Uwp,
|
||||
"wrs" => Vendor::Wrs,
|
||||
- _ => return Err(()),
|
||||
+ custom => {
|
||||
+ use alloc::borrow::ToOwned;
|
||||
+ if Architecture::from_str(custom).is_ok()
|
||||
+ || OperatingSystem::from_str(custom).is_ok()
|
||||
+ || Environment::from_str(custom).is_ok()
|
||||
+ || BinaryFormat::from_str(custom).is_ok()
|
||||
+ {
|
||||
+ return Err(());
|
||||
+ }
|
||||
+ if custom.find(|c: char| !c.is_ascii_alphanumeric() && c != '_' && c != '.').is_some() {
|
||||
+ return Err(());
|
||||
+ }
|
||||
+ Vendor::Custom(custom.to_owned())
|
||||
+ }
|
||||
})
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ mod parse_error {
|
|||
}
|
||||
}
|
||||
|
||||
use self::targets::Vendor;
|
||||
use self::triple::Triple;
|
||||
|
||||
fn main() {
|
||||
|
@ -52,6 +53,8 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
|||
writeln!(out, "use crate::Aarch64Architecture::*;")?;
|
||||
writeln!(out, "#[allow(unused_imports)]")?;
|
||||
writeln!(out, "use crate::ArmArchitecture::*;")?;
|
||||
writeln!(out, "#[allow(unused_imports)]")?;
|
||||
writeln!(out, "use crate::CustomVendor;")?;
|
||||
writeln!(out)?;
|
||||
writeln!(out, "/// The `Triple` of the current host.")?;
|
||||
writeln!(out, "pub const HOST: Triple = Triple {{")?;
|
||||
|
@ -60,7 +63,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
|||
" architecture: Architecture::{:?},",
|
||||
triple.architecture
|
||||
)?;
|
||||
writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?;
|
||||
writeln!(out, " vendor: {},", vendor_display(&triple.vendor))?;
|
||||
writeln!(
|
||||
out,
|
||||
" operating_system: OperatingSystem::{:?},",
|
||||
|
@ -90,7 +93,7 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
|||
writeln!(out, "impl Vendor {{")?;
|
||||
writeln!(out, " /// Return the vendor for the current host.")?;
|
||||
writeln!(out, " pub const fn host() -> Self {{")?;
|
||||
writeln!(out, " Vendor::{:?}", triple.vendor)?;
|
||||
writeln!(out, " {}", vendor_display(&triple.vendor))?;
|
||||
writeln!(out, " }}")?;
|
||||
writeln!(out, "}}")?;
|
||||
writeln!(out)?;
|
||||
|
@ -138,7 +141,11 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
|||
" architecture: Architecture::{:?},",
|
||||
triple.architecture
|
||||
)?;
|
||||
writeln!(out, " vendor: Vendor::{:?},", triple.vendor)?;
|
||||
writeln!(
|
||||
out,
|
||||
" vendor: {},",
|
||||
vendor_display(&triple.vendor)
|
||||
)?;
|
||||
writeln!(
|
||||
out,
|
||||
" operating_system: OperatingSystem::{:?},",
|
||||
|
@ -160,3 +167,13 @@ fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vendor_display(vendor: &Vendor) -> String {
|
||||
match vendor {
|
||||
Vendor::Custom(custom) => format!(
|
||||
"Vendor::Custom(CustomVendor::Static({:?}))",
|
||||
custom.as_str()
|
||||
),
|
||||
known => format!("Vendor::{:?}", known),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#[allow(unused_imports)]
|
||||
use crate::Aarch64Architecture::*;
|
||||
#[allow(unused_imports)]
|
||||
use crate::ArmArchitecture::*;
|
||||
#[allow(unused_imports)]
|
||||
use crate::CustomVendor;
|
||||
|
||||
/// The `Triple` of the current host.
|
||||
pub const HOST: Triple = Triple {
|
||||
architecture: Architecture::Aarch64(Aarch64),
|
||||
vendor: Vendor::Unknown,
|
||||
operating_system: OperatingSystem::Linux,
|
||||
environment: Environment::Gnu,
|
||||
binary_format: BinaryFormat::Elf,
|
||||
};
|
||||
|
||||
impl Architecture {
|
||||
/// Return the architecture for the current host.
|
||||
pub const fn host() -> Self {
|
||||
Architecture::Aarch64(Aarch64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Vendor {
|
||||
/// Return the vendor for the current host.
|
||||
pub const fn host() -> Self {
|
||||
Vendor::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl OperatingSystem {
|
||||
/// Return the operating system for the current host.
|
||||
pub const fn host() -> Self {
|
||||
OperatingSystem::Linux
|
||||
}
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
/// Return the environment for the current host.
|
||||
pub const fn host() -> Self {
|
||||
Environment::Gnu
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryFormat {
|
||||
/// Return the binary format for the current host.
|
||||
pub const fn host() -> Self {
|
||||
BinaryFormat::Elf
|
||||
}
|
||||
}
|
||||
|
||||
impl Triple {
|
||||
/// Return the triple for the current host.
|
||||
pub const fn host() -> Self {
|
||||
Self {
|
||||
architecture: Architecture::Aarch64(Aarch64),
|
||||
vendor: Vendor::Unknown,
|
||||
operating_system: OperatingSystem::Linux,
|
||||
environment: Environment::Gnu,
|
||||
binary_format: BinaryFormat::Elf,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
"aarch64-apple-ios",
|
||||
"aarch64-fuchsia",
|
||||
"aarch64-linux-android",
|
||||
"aarch64-pc-windows-msvc",
|
||||
"aarch64-unknown-cloudabi",
|
||||
"aarch64-unknown-freebsd",
|
||||
"aarch64-unknown-hermit",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"aarch64-unknown-netbsd",
|
||||
"aarch64-unknown-none",
|
||||
"aarch64-unknown-none-softfloat",
|
||||
"aarch64-unknown-openbsd",
|
||||
"aarch64-unknown-redox",
|
||||
"aarch64-uwp-windows-msvc",
|
||||
"aarch64-wrs-vxworks",
|
||||
"armebv7r-none-eabi",
|
||||
"armebv7r-none-eabihf",
|
||||
"arm-linux-androideabi",
|
||||
"arm-unknown-linux-gnueabi",
|
||||
"arm-unknown-linux-gnueabihf",
|
||||
"arm-unknown-linux-musleabi",
|
||||
"arm-unknown-linux-musleabihf",
|
||||
"armv4t-unknown-linux-gnueabi",
|
||||
"armv5te-unknown-linux-gnueabi",
|
||||
"armv5te-unknown-linux-musleabi",
|
||||
"armv6-unknown-freebsd",
|
||||
"armv6-unknown-netbsd-eabihf",
|
||||
"armv7-apple-ios",
|
||||
"armv7-linux-androideabi",
|
||||
"armv7r-none-eabi",
|
||||
"armv7r-none-eabihf",
|
||||
"armv7s-apple-ios",
|
||||
"armv7-unknown-cloudabi-eabihf",
|
||||
"armv7-unknown-freebsd",
|
||||
"armv7-unknown-linux-gnueabi",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"armv7-unknown-linux-musleabi",
|
||||
"armv7-unknown-linux-musleabihf",
|
||||
"armv7-unknown-netbsd-eabihf",
|
||||
"armv7-wrs-vxworks-eabihf",
|
||||
"asmjs-unknown-emscripten",
|
||||
"hexagon-unknown-linux-musl",
|
||||
"i386-apple-ios",
|
||||
"i586-pc-windows-msvc",
|
||||
"i586-unknown-linux-gnu",
|
||||
"i586-unknown-linux-musl",
|
||||
"i686-apple-darwin",
|
||||
"i686-linux-android",
|
||||
"i686-pc-windows-gnu",
|
||||
"i686-pc-windows-msvc",
|
||||
"i686-unknown-cloudabi",
|
||||
"i686-unknown-dragonfly",
|
||||
"i686-unknown-freebsd",
|
||||
"i686-unknown-haiku",
|
||||
"i686-unknown-linux-gnu",
|
||||
"i686-unknown-linux-musl",
|
||||
"i686-unknown-netbsd",
|
||||
"i686-unknown-openbsd",
|
||||
"i686-unknown-uefi",
|
||||
"i686-uwp-windows-gnu",
|
||||
"i686-uwp-windows-msvc",
|
||||
"i686-wrs-vxworks",
|
||||
"mips64el-unknown-linux-gnuabi64",
|
||||
"mips64el-unknown-linux-muslabi64",
|
||||
"mips64-unknown-linux-gnuabi64",
|
||||
"mips64-unknown-linux-muslabi64",
|
||||
"mipsel-unknown-linux-gnu",
|
||||
"mipsel-unknown-linux-musl",
|
||||
"mipsel-unknown-linux-uclibc",
|
||||
"mipsisa32r6el-unknown-linux-gnu",
|
||||
"mipsisa32r6-unknown-linux-gnu",
|
||||
"mipsisa64r6el-unknown-linux-gnuabi64",
|
||||
"mipsisa64r6-unknown-linux-gnuabi64",
|
||||
"mips-unknown-linux-gnu",
|
||||
"mips-unknown-linux-musl",
|
||||
"mips-unknown-linux-uclibc",
|
||||
"msp430-none-elf",
|
||||
"nvptx64-nvidia-cuda",
|
||||
"powerpc64le-unknown-linux-gnu",
|
||||
"powerpc64le-unknown-linux-musl",
|
||||
"powerpc64-unknown-freebsd",
|
||||
"powerpc64-unknown-linux-gnu",
|
||||
"powerpc64-unknown-linux-musl",
|
||||
"powerpc64-wrs-vxworks",
|
||||
"powerpc-unknown-linux-gnu",
|
||||
"powerpc-unknown-linux-gnuspe",
|
||||
"powerpc-unknown-linux-musl",
|
||||
"powerpc-unknown-netbsd",
|
||||
"powerpc-wrs-vxworks",
|
||||
"powerpc-wrs-vxworks-spe",
|
||||
"riscv32imac-unknown-none-elf",
|
||||
"riscv32imc-unknown-none-elf",
|
||||
"riscv32i-unknown-none-elf",
|
||||
"riscv64gc-unknown-none-elf",
|
||||
"riscv64imac-unknown-none-elf",
|
||||
"s390x-unknown-linux-gnu",
|
||||
"sparc64-unknown-linux-gnu",
|
||||
"sparc64-unknown-netbsd",
|
||||
"sparc64-unknown-openbsd",
|
||||
"sparc-unknown-linux-gnu",
|
||||
"sparcv9-sun-solaris",
|
||||
"thumbv6m-none-eabi",
|
||||
"thumbv7a-pc-windows-msvc",
|
||||
"thumbv7em-none-eabi",
|
||||
"thumbv7em-none-eabihf",
|
||||
"thumbv7m-none-eabi",
|
||||
"thumbv7neon-linux-androideabi",
|
||||
"thumbv7neon-unknown-linux-gnueabihf",
|
||||
"thumbv7neon-unknown-linux-musleabihf",
|
||||
"thumbv8m.base-none-eabi",
|
||||
"thumbv8m.main-none-eabi",
|
||||
"thumbv8m.main-none-eabihf",
|
||||
"wasm32-unknown-emscripten",
|
||||
"wasm32-unknown-unknown",
|
||||
"wasm32-wasi",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-apple-ios",
|
||||
"x86_64-fortanix-unknown-sgx",
|
||||
"x86_64-fuchsia",
|
||||
"x86_64-linux-android",
|
||||
"x86_64-linux-kernel",
|
||||
"x86_64-pc-solaris",
|
||||
"x86_64-pc-windows-gnu",
|
||||
"x86_64-pc-windows-msvc",
|
||||
"x86_64-rumprun-netbsd",
|
||||
"x86_64-sun-solaris",
|
||||
"x86_64-unknown-cloudabi",
|
||||
"x86_64-unknown-dragonfly",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-haiku",
|
||||
"x86_64-unknown-hermit",
|
||||
"x86_64-unknown-l4re-uclibc",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-unknown-linux-gnux32",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"x86_64-unknown-netbsd",
|
||||
"x86_64-unknown-openbsd",
|
||||
"x86_64-unknown-redox",
|
||||
"x86_64-unknown-uefi",
|
||||
"x86_64-uwp-windows-gnu",
|
||||
"x86_64-uwp-windows-msvc",
|
||||
"x86_64-wrs-vxworks",
|
|
@ -28,7 +28,7 @@ mod triple;
|
|||
pub use self::host::HOST;
|
||||
pub use self::parse_error::ParseError;
|
||||
pub use self::targets::{
|
||||
Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, Environment, OperatingSystem,
|
||||
Vendor,
|
||||
Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, CustomVendor, Environment,
|
||||
OperatingSystem, Vendor,
|
||||
};
|
||||
pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple};
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// This file defines all the identifier enums and target-aware logic.
|
||||
|
||||
use crate::triple::{Endianness, PointerWidth, Triple};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::str::FromStr;
|
||||
|
||||
/// The "architecture" field, which in some cases also specifies a specific
|
||||
|
@ -290,9 +293,42 @@ impl Aarch64Architecture {
|
|||
}
|
||||
}
|
||||
|
||||
/// A string for a `Vendor::Custom` that can either be used in `const`
|
||||
/// contexts or hold dynamic strings.
|
||||
#[derive(Clone, Debug, Eq)]
|
||||
pub enum CustomVendor {
|
||||
/// An owned `String`. This supports the general case.
|
||||
Owned(Box<String>),
|
||||
/// A static `str`, so that `CustomVendor` can be constructed in `const`
|
||||
/// contexts.
|
||||
Static(&'static str),
|
||||
}
|
||||
|
||||
impl CustomVendor {
|
||||
/// Extracts a string slice.
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
CustomVendor::Owned(s) => s,
|
||||
CustomVendor::Static(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CustomVendor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for CustomVendor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
/// The "vendor" field, which in practice is little more than an arbitrary
|
||||
/// modifier.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Vendor {
|
||||
Unknown,
|
||||
|
@ -306,6 +342,15 @@ pub enum Vendor {
|
|||
Sun,
|
||||
Uwp,
|
||||
Wrs,
|
||||
|
||||
/// A custom vendor. "Custom" in this context means that the vendor is
|
||||
/// not specifically recognized by upstream Autotools, LLVM, Rust, or other
|
||||
/// relevant authorities on triple naming. It's useful for people building
|
||||
/// and using locally patched toolchains.
|
||||
///
|
||||
/// Outside of such patched environments, users of `target-lexicon` should
|
||||
/// treat `Custom` the same as `Unknown` and ignore the string.
|
||||
Custom(CustomVendor),
|
||||
}
|
||||
|
||||
/// The "operating system" field, which sometimes implies an environment, and
|
||||
|
@ -717,6 +762,7 @@ impl fmt::Display for Vendor {
|
|||
Vendor::Sun => "sun",
|
||||
Vendor::Uwp => "uwp",
|
||||
Vendor::Wrs => "wrs",
|
||||
Vendor::Custom(ref name) => name.as_str(),
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
|
@ -738,7 +784,43 @@ impl FromStr for Vendor {
|
|||
"sun" => Vendor::Sun,
|
||||
"uwp" => Vendor::Uwp,
|
||||
"wrs" => Vendor::Wrs,
|
||||
_ => return Err(()),
|
||||
custom => {
|
||||
use alloc::borrow::ToOwned;
|
||||
|
||||
// A custom vendor. Since triple syntax is so loosely defined,
|
||||
// be as conservative as we can to avoid potential ambiguities.
|
||||
// We err on the side of being too strict here, as we can
|
||||
// always relax it if needed.
|
||||
|
||||
// Don't allow empty string names.
|
||||
if custom.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Don't allow any other recognized name as a custom vendor,
|
||||
// since vendors can be omitted in some contexts.
|
||||
if Architecture::from_str(custom).is_ok()
|
||||
|| OperatingSystem::from_str(custom).is_ok()
|
||||
|| Environment::from_str(custom).is_ok()
|
||||
|| BinaryFormat::from_str(custom).is_ok()
|
||||
{
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Require the first character to be an ascii lowercase.
|
||||
if !custom.chars().nth(0).unwrap().is_ascii_lowercase() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Restrict the set of characters permitted in a custom vendor.
|
||||
if custom.chars().any(|c: char| {
|
||||
!(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '.')
|
||||
}) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Vendor::Custom(CustomVendor::Owned(Box::new(custom.to_owned())))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1120,4 +1202,87 @@ mod tests {
|
|||
assert_eq!(t.environment, Environment::Eabihf);
|
||||
assert_eq!(t.binary_format, BinaryFormat::Elf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_vendors() {
|
||||
// Test various invalid cases.
|
||||
assert!(Triple::from_str("x86_64--linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-42-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-__customvendor__-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-^-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64- -linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-CustomVendor-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-linux-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-x86_64-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-elf-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-gnu-linux").is_err());
|
||||
assert!(Triple::from_str("x86_64-linux-customvendor").is_err());
|
||||
assert!(Triple::from_str("customvendor").is_err());
|
||||
assert!(Triple::from_str("customvendor-x86_64").is_err());
|
||||
assert!(Triple::from_str("x86_64-").is_err());
|
||||
assert!(Triple::from_str("x86_64--").is_err());
|
||||
|
||||
// Test various Unicode things.
|
||||
assert!(
|
||||
Triple::from_str("x86_64-𝓬𝓾𝓼𝓽𝓸𝓶𝓿𝓮𝓷𝓭𝓸𝓻-linux").is_err(),
|
||||
"unicode font hazard"
|
||||
);
|
||||
assert!(
|
||||
Triple::from_str("x86_64-ćúśtőḿvéńdőŕ-linux").is_err(),
|
||||
"diacritical mark stripping hazard"
|
||||
);
|
||||
assert!(
|
||||
Triple::from_str("x86_64-customvendοr-linux").is_err(),
|
||||
"homoglyph hazard"
|
||||
);
|
||||
assert!(Triple::from_str("x86_64-customvendor-linux").is_ok());
|
||||
assert!(
|
||||
Triple::from_str("x86_64-ffi-linux").is_err(),
|
||||
"normalization hazard"
|
||||
);
|
||||
assert!(Triple::from_str("x86_64-ffi-linux").is_ok());
|
||||
assert!(
|
||||
Triple::from_str("x86_64-customvendor-linux").is_err(),
|
||||
"zero-width character hazard"
|
||||
);
|
||||
assert!(
|
||||
Triple::from_str("x86_64-customvendor-linux").is_err(),
|
||||
"BOM hazard"
|
||||
);
|
||||
|
||||
// Test some valid cases.
|
||||
let t = Triple::from_str("x86_64-customvendor-linux")
|
||||
.expect("can't parse target with custom vendor");
|
||||
assert_eq!(t.architecture, Architecture::X86_64);
|
||||
assert_eq!(
|
||||
t.vendor,
|
||||
Vendor::Custom(CustomVendor::Static("customvendor"))
|
||||
);
|
||||
assert_eq!(t.operating_system, OperatingSystem::Linux);
|
||||
assert_eq!(t.environment, Environment::Unknown);
|
||||
assert_eq!(t.binary_format, BinaryFormat::Elf);
|
||||
assert_eq!(t.to_string(), "x86_64-customvendor-linux");
|
||||
|
||||
let t =
|
||||
Triple::from_str("x86_64-customvendor").expect("can't parse target with custom vendor");
|
||||
assert_eq!(t.architecture, Architecture::X86_64);
|
||||
assert_eq!(
|
||||
t.vendor,
|
||||
Vendor::Custom(CustomVendor::Static("customvendor"))
|
||||
);
|
||||
assert_eq!(t.operating_system, OperatingSystem::Unknown);
|
||||
assert_eq!(t.environment, Environment::Unknown);
|
||||
assert_eq!(t.binary_format, BinaryFormat::Unknown);
|
||||
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-foo"),
|
||||
Ok(Triple {
|
||||
architecture: Architecture::Unknown,
|
||||
vendor: Vendor::Custom(CustomVendor::Static("foo")),
|
||||
operating_system: OperatingSystem::Unknown,
|
||||
environment: Environment::Unknown,
|
||||
binary_format: BinaryFormat::Unknown,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -322,10 +322,6 @@ mod tests {
|
|||
Triple::from_str("foo"),
|
||||
Err(ParseError::UnrecognizedArchitecture("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-foo"),
|
||||
Err(ParseError::UnrecognizedVendor("foo".to_owned()))
|
||||
);
|
||||
assert_eq!(
|
||||
Triple::from_str("unknown-unknown-foo"),
|
||||
Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned()))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
set -oeu pipefail
|
||||
|
||||
|
||||
cargo clean
|
||||
for trip in wasm32-unknown-unknown wasm32-wasi arm-unknown-linux-gnueabi aarch64-unknown-linux-gnu; do
|
||||
echo TARGET $trip
|
||||
cargo build --target $trip --all
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.lock":"c6fca2a5cc9f95e23b077b723dca051c28808b0bb99a2221104002026fcccae9","Cargo.toml":"bab0e452ba9beb0f5efd7f46a6e6d16e5e6b18751a014157a152b1aae37ed517","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"df9c5aa22ca3bcf6221c7e4297cd741cbbdfb39294b4ef28c4d382688395611a","benches/benchmark.rs":"951abd671bd1a5a33d09379b023de000e89fc5f99a5950f0b3b2f571021aa402","compare-master.sh":"165490eab36ef4eceb2913a6c5cdeff479a05e1e0119a7f4551b03dbcda51ad4","examples/dump.rs":"de2bbdba75e21b9ff92b32697b3d9941f8695b8f7e3a8dee8fc5d7f4c3a0649c","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"39e0a785a41e2513926ab140a1e07f38a6e898737d098d1d038ba5229e7c24b3","src/lib.rs":"a17f353162053e0e915a0e0d1f4d4ba86a7a8e4ff949c83faad004b707ac003f","src/limits.rs":"4e4f9b7ed1d26e7a6727e36b136015cd9f4e38f596b3c8f82236789f45905cae","src/operators_validator.rs":"12bb14c9e9fb7b20af8039aff0a6aaaa4a8af0c55ad3366fb6844758fda1f5a3","src/parser.rs":"c5afcf039a62952f4e674773416d4c4507711d10b4248ed3bce5e1223cc97034","src/primitives.rs":"65b7ddf0fb0bde4df0823a23ced952720e7dd8c4b630fdcd988096ccb8ea1379","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e31e1d819c0b10acf58b8975238554245defe36db1c3206683b056c52978fb21","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"188aa45a893f4d17df7633a3df6a32438b64e192e001ddcc50543e007b4f7db4","src/readers/module.rs":"311b877264bf9d035280cad0c61eb3640c15505c4da5e8ba45c7bf9e067abbd4","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"da43ee8afcb0c1d6e7f1e19e8a10143101f0c598b1e533a394c7397f43881a82","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"661dcb6ea83e0e066d14efc22f3939b1a935bc9681cc6d971bf0398038a0cf40","src/validator.rs":"4dfd7176fc1fced1730ecf6ee8c9225751a6ba3047862b9cfc8b151d9526a378","test-all.sh":"f36e3e9bf9c39456bab3ac170d3a09911becf2b7e0d0e2a58854ce1750da0d1f","test-no_std.sh":"f8bc939b378fe618b7ec6297152708e7c8740858eb94e5756464934a38796b8c"},"package":"e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82"}
|
||||
{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","Cargo.lock":"75d9e05f0cb74776829fd6880c7ef89f3018ffce6ebd49590cac9f0c37b1b8ea","Cargo.toml":"448969b263b876a461f5bfbe1609ab85d5f2e82b62659f17675e4d7446c77db4","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","ORG_CODE_OF_CONDUCT.md":"59c4c4435538496193cd73e89b2cd971d1011dba573158cf108abe6af6603e6b","README.md":"90c9b0e3dd91a63b6a8088b72200b3118fa0bbdf3320cd98609bd4cc4ef09902","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","benches/benchmark.rs":"951abd671bd1a5a33d09379b023de000e89fc5f99a5950f0b3b2f571021aa402","compare-master.sh":"165490eab36ef4eceb2913a6c5cdeff479a05e1e0119a7f4551b03dbcda51ad4","examples/dump.rs":"de2bbdba75e21b9ff92b32697b3d9941f8695b8f7e3a8dee8fc5d7f4c3a0649c","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"982458f41f2e58dec1b5b02f2eb9ea61d7d9e8da4168cafc600b689a36ca734a","src/lib.rs":"cdf3b945d35d451eaea690292d43b7705f61670b82bf251b463ff86c3640b6cc","src/limits.rs":"34e5cda95fb67669011ba95ca60f48fc777f3e3fa279ff68a1f2a072032a4abd","src/operators_validator.rs":"8f27e83b81d1445b3cfb4eef91ca2e5de3a5d295325339ac4ba0909fb8096876","src/parser.rs":"24018005521106118bc16a2234da3fb70d3d9f413801eb9c8ef8c61e374e06cf","src/primitives.rs":"f5b25a13a4e32fb48e927bb950360dd6af0d87200c17ebd2073811cae9552ce3","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e685af8a189f0cfa9f250c3fd221f9f14d20886f609c4c86a75c7408a106b8e0","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"ad0f49a8d2a6469d4a8a5695e60eb6f47be9c6e5994937b9ec9396f8c529fed6","src/readers/module.rs":"c2c4a0e22f7ae2102f1a96094c66faeefdbd87d42736a436f9b9f6387a525c75","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"53bf7ea87529980a3a3e1afd92ddf488ae4dc04a40cda39dbf548e4d20c8a55c","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"ff77788d9630c8d0218b9aa52bde8f3e738d130a22f192ac7257b71b8300bda9","src/validator.rs":"cf9c1a9cbb4b4544579789c1b524a2c9845619120c8141c0d360db1ffa58e2f9","test-all.sh":"f36e3e9bf9c39456bab3ac170d3a09911becf2b7e0d0e2a58854ce1750da0d1f"},"package":"1add8db5a53a2f64f13418b241982c4ab533d7a9e1e8a5dcadccce633d8d393b"}
|
|
@ -0,0 +1,49 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
*Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC].
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers 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, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[OCoC]: ORG_CODE_OF_CONDUCT.md
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[version]: https://www.contributor-covenant.org/version/1/4/
|
|
@ -1,30 +1,22 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.1.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -35,7 +27,7 @@ dependencies = [
|
|||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -48,14 +40,9 @@ name = "cast"
|
|||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -63,7 +50,7 @@ name = "clap"
|
|||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -73,15 +60,7 @@ name = "cloudabi"
|
|||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -94,18 +73,18 @@ dependencies = [
|
|||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -117,28 +96,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -155,7 +134,17 @@ name = "crossbeam-utils"
|
|||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -167,8 +156,8 @@ dependencies = [
|
|||
"bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -181,7 +170,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -190,21 +179,19 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.5.0"
|
||||
name = "hermit-abi"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -217,9 +204,14 @@ name = "lazy_static"
|
|||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.62"
|
||||
version = "0.2.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -227,41 +219,37 @@ name = "memchr"
|
|||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.1"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.10.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.3"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -272,7 +260,7 @@ name = "quote"
|
|||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -295,7 +283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -315,8 +303,8 @@ name = "rayon"
|
|||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -325,11 +313,11 @@ name = "rayon-core"
|
|||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -358,7 +346,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.0"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -389,35 +377,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.100"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.100"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.40"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.5"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -435,8 +423,8 @@ name = "tinytemplate"
|
|||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -449,27 +437,6 @@ name = "unicode-xid"
|
|||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wabt"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wabt-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.9"
|
||||
|
@ -482,11 +449,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.39.2"
|
||||
version = "0.47.0"
|
||||
dependencies = [
|
||||
"criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wast 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -517,40 +491,37 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
|
||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
|
||||
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62"
|
||||
"checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394"
|
||||
"checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e"
|
||||
"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
|
||||
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
|
||||
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
||||
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
|
||||
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
|
||||
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
|
||||
"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||
"checksum leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a"
|
||||
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
|
||||
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||
"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
|
||||
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
|
||||
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
|
||||
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
@ -561,22 +532,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
|
||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
|
||||
"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
|
||||
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
|
||||
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
|
||||
"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0"
|
||||
"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8"
|
||||
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
|
||||
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20"
|
||||
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693"
|
||||
"checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08"
|
||||
"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
|
||||
"checksum wast 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1de68310854a9840d39487701a8c1acccb5c9f9f2650d5fce3cdfe6650c372"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "wasmparser"
|
||||
version = "0.39.2"
|
||||
version = "0.47.0"
|
||||
authors = ["Yury Delendik <ydelendik@mozilla.com>"]
|
||||
exclude = ["fuzz/**/*", "tests/**/*", "testsuite/**/*"]
|
||||
description = "A simple event-driven library for parsing WebAssembly binary files.\n"
|
||||
|
@ -24,19 +24,13 @@ repository = "https://github.com/yurydelendik/wasmparser.rs"
|
|||
[[bench]]
|
||||
name = "benchmark"
|
||||
harness = false
|
||||
[dependencies.hashbrown]
|
||||
version = "0.5.0"
|
||||
optional = true
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.wabt]
|
||||
version = "0.9.2"
|
||||
[dev-dependencies.wast]
|
||||
version = "5.0.0"
|
||||
|
||||
[features]
|
||||
core = ["hashbrown"]
|
||||
default = ["std"]
|
||||
deterministic = []
|
||||
std = []
|
||||
[badges.travis-ci]
|
||||
repository = "yurydelendik/wasmparser.rs"
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
# Bytecode Alliance Organizational Code of Conduct (OCoC)
|
||||
|
||||
*Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
## Preamble
|
||||
|
||||
The Bytecode Alliance (BA) welcomes involvement from organizations,
|
||||
including commercial organizations. This document is an
|
||||
*organizational* code of conduct, intended particularly to provide
|
||||
guidance to commercial organizations. It is distinct from the
|
||||
[Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not
|
||||
replace the ICoC. This OCoC applies to any group of people acting in
|
||||
concert as a BA member or as a participant in BA activities, whether
|
||||
or not that group is formally incorporated in some jurisdiction.
|
||||
|
||||
The code of conduct described below is not a set of rigid rules, and
|
||||
we did not write it to encompass every conceivable scenario that might
|
||||
arise. For example, it is theoretically possible there would be times
|
||||
when asserting patents is in the best interest of the BA community as
|
||||
a whole. In such instances, consult with the BA, strive for
|
||||
consensus, and interpret these rules with an intent that is generous
|
||||
to the community the BA serves.
|
||||
|
||||
While we may revise these guidelines from time to time based on
|
||||
real-world experience, overall they are based on a simple principle:
|
||||
|
||||
*Bytecode Alliance members should observe the distinction between
|
||||
public community functions and private functions — especially
|
||||
commercial ones — and should ensure that the latter support, or at
|
||||
least do not harm, the former.*
|
||||
|
||||
## Guidelines
|
||||
|
||||
* **Do not cause confusion about Wasm standards or interoperability.**
|
||||
|
||||
Having an interoperable WebAssembly core is a high priority for
|
||||
the BA, and members should strive to preserve that core. It is fine
|
||||
to develop additional non-standard features or APIs, but they
|
||||
should always be clearly distinguished from the core interoperable
|
||||
Wasm.
|
||||
|
||||
Treat the WebAssembly name and any BA-associated names with
|
||||
respect, and follow BA trademark and branding guidelines. If you
|
||||
distribute a customized version of software originally produced by
|
||||
the BA, or if you build a product or service using BA-derived
|
||||
software, use names that clearly distinguish your work from the
|
||||
original. (You should still provide proper attribution to the
|
||||
original, of course, wherever such attribution would normally be
|
||||
given.)
|
||||
|
||||
Further, do not use the WebAssembly name or BA-associated names in
|
||||
other public namespaces in ways that could cause confusion, e.g.,
|
||||
in company names, names of commercial service offerings, domain
|
||||
names, publicly-visible social media accounts or online service
|
||||
accounts, etc. It may sometimes be reasonable, however, to
|
||||
register such a name in a new namespace and then immediately donate
|
||||
control of that account to the BA, because that would help the project
|
||||
maintain its identity.
|
||||
|
||||
* **Do not restrict contributors.** If your company requires
|
||||
employees or contractors to sign non-compete agreements, those
|
||||
agreements must not prevent people from participating in the BA or
|
||||
contributing to related projects.
|
||||
|
||||
This does not mean that all non-compete agreements are incompatible
|
||||
with this code of conduct. For example, a company may restrict an
|
||||
employee's ability to solicit the company's customers. However, an
|
||||
agreement must not block any form of technical or social
|
||||
participation in BA activities, including but not limited to the
|
||||
implementation of particular features.
|
||||
|
||||
The accumulation of experience and expertise in individual persons,
|
||||
who are ultimately free to direct their energy and attention as
|
||||
they decide, is one of the most important drivers of progress in
|
||||
open source projects. A company that limits this freedom may hinder
|
||||
the success of the BA's efforts.
|
||||
|
||||
* **Do not use patents as offensive weapons.** If any BA participant
|
||||
prevents the adoption or development of BA technologies by
|
||||
asserting its patents, that undermines the purpose of the
|
||||
coalition. The collaboration fostered by the BA cannot include
|
||||
members who act to undermine its work.
|
||||
|
||||
* **Practice responsible disclosure** for security vulnerabilities.
|
||||
Use designated, non-public reporting channels to disclose technical
|
||||
vulnerabilities, and give the project a reasonable period to
|
||||
respond, remediate, and patch.
|
||||
|
||||
Vulnerability reporters may patch their company's own offerings, as
|
||||
long as that patching does not significantly delay the reporting of
|
||||
the vulnerability. Vulnerability information should never be used
|
||||
for unilateral commercial advantage. Vendors may legitimately
|
||||
compete on the speed and reliability with which they deploy
|
||||
security fixes, but withholding vulnerability information damages
|
||||
everyone in the long run by risking harm to the BA project's
|
||||
reputation and to the security of all users.
|
||||
|
||||
* **Respect the letter and spirit of open source practice.** While
|
||||
there is not space to list here all possible aspects of standard
|
||||
open source practice, some examples will help show what we mean:
|
||||
|
||||
* Abide by all applicable open source license terms. Do not engage
|
||||
in copyright violation or misattribution of any kind.
|
||||
|
||||
* Do not claim others' ideas or designs as your own.
|
||||
|
||||
* When others engage in publicly visible work (e.g., an upcoming
|
||||
demo that is coordinated in a public issue tracker), do not
|
||||
unilaterally announce early releases or early demonstrations of
|
||||
that work ahead of their schedule in order to secure private
|
||||
advantage (such as marketplace advantage) for yourself.
|
||||
|
||||
The BA reserves the right to determine what constitutes good open
|
||||
source practices and to take action as it deems appropriate to
|
||||
encourage, and if necessary enforce, such practices.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of organizational behavior in violation of the OCoC may
|
||||
be reported by contacting the Bytecode Alliance CoC team at
|
||||
[report@bytecodealliance.org](mailto:report@bytecodealliance.org). The
|
||||
CoC team will review and investigate all complaints, and will respond
|
||||
in a way that it deems appropriate to the circumstances. The CoC team
|
||||
is obligated to maintain confidentiality with regard to the reporter of
|
||||
an incident. Further details of specific enforcement policies may be
|
||||
posted separately.
|
||||
|
||||
When the BA deems an organization in violation of this OCoC, the BA
|
||||
will, at its sole discretion, determine what action to take. The BA
|
||||
will decide what type, degree, and duration of corrective action is
|
||||
needed, if any, before a violating organization can be considered for
|
||||
membership (if it was not already a member) or can have its membership
|
||||
reinstated (if it was a member and the BA canceled its membership due
|
||||
to the violation).
|
||||
|
||||
In practice, the BA's first approach will be to start a conversation,
|
||||
with punitive enforcement used only as a last resort. Violations
|
||||
often turn out to be unintentional and swiftly correctable with all
|
||||
parties acting in good faith.
|
|
@ -1,5 +1,7 @@
|
|||
# The WebAssembly binary file decoder in Rust
|
||||
|
||||
**A [Bytecode Alliance](https://bytecodealliance.org/) project**
|
||||
|
||||
[![Build Status](https://travis-ci.org/yurydelendik/wasmparser.rs.svg?branch=master)](https://travis-ci.org/yurydelendik/wasmparser.rs)
|
||||
[![crates.io link](https://img.shields.io/crates/v/wasmparser.svg)](https://crates.io/crates/wasmparser)
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# Security Policy
|
||||
|
||||
Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that.
|
||||
|
||||
## Scope
|
||||
|
||||
If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us.
|
||||
|
||||
## How to Submit a Report
|
||||
|
||||
To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team.
|
||||
|
||||
## Safe Harbor
|
||||
|
||||
The Bytecode Alliance supports safe harbor for security researchers who:
|
||||
|
||||
* Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services.
|
||||
* Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information.
|
||||
* Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party.
|
||||
|
||||
We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you.
|
||||
|
||||
Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy.
|
||||
|
||||
## Preferences
|
||||
|
||||
* Please provide detailed reports with reproducible steps and a clearly defined impact.
|
||||
* Submit one vulnerability per report.
|
||||
* Social engineering (e.g. phishing, vishing, smishing) is prohibited.
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::convert::TryInto;
|
||||
use std::str;
|
||||
use std::vec::Vec;
|
||||
|
||||
|
@ -38,36 +39,43 @@ fn is_name_prefix(name: &str, prefix: &'static str) -> bool {
|
|||
name.starts_with(prefix)
|
||||
}
|
||||
|
||||
const WASM_MAGIC_NUMBER: u32 = 0x6d736100;
|
||||
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||
const WASM_EXPERIMENTAL_VERSION: u32 = 0xd;
|
||||
const WASM_SUPPORTED_VERSION: u32 = 0x1;
|
||||
|
||||
pub struct SectionHeader<'a> {
|
||||
pub(crate) struct SectionHeader<'a> {
|
||||
pub code: SectionCode<'a>,
|
||||
pub payload_start: usize,
|
||||
pub payload_len: usize,
|
||||
}
|
||||
|
||||
/// Bytecode range in the WebAssembly module.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Range {
|
||||
/// The start bound of the range.
|
||||
pub start: usize,
|
||||
/// The end bound of the range.
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
impl Range {
|
||||
/// Constructs a new instance of `Range`.
|
||||
///
|
||||
/// # Panics
|
||||
/// If `start` is greater than `end`.
|
||||
pub fn new(start: usize, end: usize) -> Range {
|
||||
assert!(start <= end);
|
||||
Range { start, end }
|
||||
}
|
||||
|
||||
/// Returns a new slice between `start` and `end - 1` from `data`.
|
||||
pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] {
|
||||
&data[self.start..self.end]
|
||||
}
|
||||
}
|
||||
|
||||
/// A binary reader of the WebAssembly structures and types.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BinaryReader<'a> {
|
||||
pub(crate) buffer: &'a [u8],
|
||||
pub(crate) position: usize,
|
||||
|
@ -94,6 +102,7 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Constructs a `BinaryReader` with an explicit starting offset.
|
||||
pub fn new_with_offset(data: &[u8], original_offset: usize) -> BinaryReader {
|
||||
BinaryReader {
|
||||
buffer: data,
|
||||
|
@ -106,6 +115,7 @@ impl<'a> BinaryReader<'a> {
|
|||
self.original_offset + self.position
|
||||
}
|
||||
|
||||
/// Returns a range from the starting offset to the end of the buffer.
|
||||
pub fn range(&self) -> Range {
|
||||
Range {
|
||||
start: self.original_offset,
|
||||
|
@ -178,6 +188,7 @@ impl<'a> BinaryReader<'a> {
|
|||
-0x05 => Ok(Type::V128),
|
||||
-0x10 => Ok(Type::AnyFunc),
|
||||
-0x11 => Ok(Type::AnyRef),
|
||||
-0x12 => Ok(Type::NullRef),
|
||||
-0x20 => Ok(Type::Func),
|
||||
-0x40 => Ok(Type::EmptyBlockType),
|
||||
_ => Err(BinaryReaderError {
|
||||
|
@ -374,18 +385,26 @@ impl<'a> BinaryReader<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns whether the `BinaryReader` has reached the end of the file.
|
||||
pub fn eof(&self) -> bool {
|
||||
self.position >= self.buffer.len()
|
||||
}
|
||||
|
||||
/// Returns the `BinaryReader`'s current position.
|
||||
pub fn current_position(&self) -> usize {
|
||||
self.position
|
||||
}
|
||||
|
||||
/// Returns the number of bytes remaining in the `BinaryReader`.
|
||||
pub fn bytes_remaining(&self) -> usize {
|
||||
self.buffer.len() - self.position
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` `size` bytes, and returns a slice from the
|
||||
/// current position of `size` length.
|
||||
///
|
||||
/// # Errors
|
||||
/// If `size` exceeds the remaining length in `BinaryReader`.
|
||||
pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
|
||||
self.ensure_has_bytes(size)?;
|
||||
let start = self.position;
|
||||
|
@ -393,22 +412,38 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok(&self.buffer[start..self.position])
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` four bytes and returns a `u32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than four bytes remaining.
|
||||
pub fn read_u32(&mut self) -> Result<u32> {
|
||||
self.ensure_has_bytes(4)?;
|
||||
let b1 = u32::from(self.buffer[self.position]);
|
||||
let b2 = u32::from(self.buffer[self.position + 1]);
|
||||
let b3 = u32::from(self.buffer[self.position + 2]);
|
||||
let b4 = u32::from(self.buffer[self.position + 3]);
|
||||
let word = u32::from_le_bytes(
|
||||
self.buffer[self.position..self.position + 4]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
self.position += 4;
|
||||
Ok(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24))
|
||||
Ok(word)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` eight bytes and returns a `u64`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than eight bytes remaining.
|
||||
pub fn read_u64(&mut self) -> Result<u64> {
|
||||
let w1 = u64::from(self.read_u32()?);
|
||||
let w2 = u64::from(self.read_u32()?);
|
||||
Ok(w1 | (w2 << 32))
|
||||
self.ensure_has_bytes(8)?;
|
||||
let word = u64::from_le_bytes(
|
||||
self.buffer[self.position..self.position + 8]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
self.position += 8;
|
||||
Ok(word)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` a single byte, and returns the data as
|
||||
/// a `u32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has no bytes remaining.
|
||||
pub fn read_u8(&mut self) -> Result<u32> {
|
||||
self.ensure_has_byte()?;
|
||||
let b = u32::from(self.buffer[self.position]);
|
||||
|
@ -416,6 +451,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok(b)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to two bytes to parse a variable
|
||||
/// length integer as a `u8`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or two bytes remaining, or the
|
||||
/// integer is larger than eight bits.
|
||||
pub fn read_var_u8(&mut self) -> Result<u32> {
|
||||
// Optimization for single byte i32.
|
||||
let byte = self.read_u8()?;
|
||||
|
@ -433,6 +473,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes to parse a variable
|
||||
/// length integer as a `u32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to four bytes remaining, or
|
||||
/// the integer is larger than 32 bits.
|
||||
pub fn read_var_u32(&mut self) -> Result<u32> {
|
||||
// Optimization for single byte i32.
|
||||
let byte = self.read_u8()?;
|
||||
|
@ -460,6 +505,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes over a variable length 32
|
||||
/// bit integer, discarding the result.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to four bytes remaining, or
|
||||
/// the integer is larger than 32 bits.
|
||||
pub fn skip_var_32(&mut self) -> Result<()> {
|
||||
for _ in 0..5 {
|
||||
let byte = self.read_u8()?;
|
||||
|
@ -473,16 +523,26 @@ impl<'a> BinaryReader<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Alias method for `BinaryReader::skip_var_u32`.
|
||||
pub fn skip_type(&mut self) -> Result<()> {
|
||||
self.skip_var_32()
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` `len` bytes, skipping the result.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than `len` bytes remaining.
|
||||
pub fn skip_bytes(&mut self, len: usize) -> Result<()> {
|
||||
self.ensure_has_bytes(len)?;
|
||||
self.position += len;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` past a WebAssembly string. This method does
|
||||
/// not perform any utf-8 validation.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than four bytes, the string's length exceeds
|
||||
/// the remaining bytes, or the string length
|
||||
/// exceeds `limits::MAX_WASM_STRING_SIZE`.
|
||||
pub fn skip_string(&mut self) -> Result<()> {
|
||||
let len = self.read_var_u32()? as usize;
|
||||
if len > MAX_WASM_STRING_SIZE {
|
||||
|
@ -502,6 +562,11 @@ impl<'a> BinaryReader<'a> {
|
|||
self.position = position;
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes to parse a variable
|
||||
/// length integer as a `i32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to four bytes remaining, or
|
||||
/// the integer is larger than 32 bits.
|
||||
pub fn read_var_i32(&mut self) -> Result<i32> {
|
||||
// Optimization for single byte i32.
|
||||
let byte = self.read_u8()?;
|
||||
|
@ -534,6 +599,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok((result << ashift) >> ashift)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes to parse a variable
|
||||
/// length integer as a signed 33 bit integer, returned as a `i64`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to five bytes remaining, or
|
||||
/// the integer is larger than 33 bits.
|
||||
pub fn read_var_s33(&mut self) -> Result<i64> {
|
||||
// Optimization for single byte.
|
||||
let byte = self.read_u8()?;
|
||||
|
@ -551,7 +621,7 @@ impl<'a> BinaryReader<'a> {
|
|||
let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);
|
||||
if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Invalid var_i33",
|
||||
message: "Invalid var_s33",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
|
@ -566,6 +636,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok((result << ashift) >> ashift)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to eight bytes to parse a variable
|
||||
/// length integer as a 64 bit integer, returned as a `i64`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to eight bytes remaining, or
|
||||
/// the integer is larger than 64 bits.
|
||||
pub fn read_var_i64(&mut self) -> Result<i64> {
|
||||
let mut result: i64 = 0;
|
||||
let mut shift = 0;
|
||||
|
@ -592,16 +667,31 @@ impl<'a> BinaryReader<'a> {
|
|||
Ok((result << ashift) >> ashift)
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes to parse a variable
|
||||
/// length integer as a 32 bit floating point integer, returned as `Ieee32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to four bytes remaining, or
|
||||
/// the integer is larger than 32 bits.
|
||||
pub fn read_f32(&mut self) -> Result<Ieee32> {
|
||||
let value = self.read_u32()?;
|
||||
Ok(Ieee32(value))
|
||||
}
|
||||
|
||||
/// Advances the `BinaryReader` up to four bytes to parse a variable
|
||||
/// length integer as a 32 bit floating point integer, returned as `Ieee32`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than one or up to four bytes remaining, or
|
||||
/// the integer is larger than 32 bits.
|
||||
pub fn read_f64(&mut self) -> Result<Ieee64> {
|
||||
let value = self.read_u64()?;
|
||||
Ok(Ieee64(value))
|
||||
}
|
||||
|
||||
/// Reads a WebAssembly string from the module.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less than up to four bytes remaining, the string's
|
||||
/// length exceeds the remaining bytes, the string's length exceeds
|
||||
/// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8.
|
||||
pub fn read_string(&mut self) -> Result<&'a str> {
|
||||
let len = self.read_var_u32()? as usize;
|
||||
if len > MAX_WASM_STRING_SIZE {
|
||||
|
@ -617,9 +707,9 @@ impl<'a> BinaryReader<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn read_memarg_of_align(&mut self, align: u32) -> Result<MemoryImmediate> {
|
||||
fn read_memarg_of_align(&mut self, max_align: u32) -> Result<MemoryImmediate> {
|
||||
let imm = self.read_memarg()?;
|
||||
if align != imm.flags {
|
||||
if imm.flags > max_align {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Unexpected memarg alignment",
|
||||
offset: self.original_position() - 1,
|
||||
|
@ -631,16 +721,16 @@ impl<'a> BinaryReader<'a> {
|
|||
fn read_0xfe_operator(&mut self) -> Result<Operator<'a>> {
|
||||
let code = self.read_u8()? as u8;
|
||||
Ok(match code {
|
||||
0x00 => Operator::Wake {
|
||||
0x00 => Operator::AtomicNotify {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x01 => Operator::I32Wait {
|
||||
0x01 => Operator::I32AtomicWait {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x02 => Operator::I64Wait {
|
||||
0x02 => Operator::I64AtomicWait {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x03 => Operator::Fence {
|
||||
0x03 => Operator::AtomicFence {
|
||||
flags: self.read_u8()? as u8,
|
||||
},
|
||||
0x10 => Operator::I32AtomicLoad {
|
||||
|
@ -691,19 +781,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x1f => Operator::I64AtomicRmwAdd {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x20 => Operator::I32AtomicRmw8UAdd {
|
||||
0x20 => Operator::I32AtomicRmw8AddU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x21 => Operator::I32AtomicRmw16UAdd {
|
||||
0x21 => Operator::I32AtomicRmw16AddU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x22 => Operator::I64AtomicRmw8UAdd {
|
||||
0x22 => Operator::I64AtomicRmw8AddU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x23 => Operator::I64AtomicRmw16UAdd {
|
||||
0x23 => Operator::I64AtomicRmw16AddU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x24 => Operator::I64AtomicRmw32UAdd {
|
||||
0x24 => Operator::I64AtomicRmw32AddU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x25 => Operator::I32AtomicRmwSub {
|
||||
|
@ -712,19 +802,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x26 => Operator::I64AtomicRmwSub {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x27 => Operator::I32AtomicRmw8USub {
|
||||
0x27 => Operator::I32AtomicRmw8SubU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x28 => Operator::I32AtomicRmw16USub {
|
||||
0x28 => Operator::I32AtomicRmw16SubU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x29 => Operator::I64AtomicRmw8USub {
|
||||
0x29 => Operator::I64AtomicRmw8SubU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x2a => Operator::I64AtomicRmw16USub {
|
||||
0x2a => Operator::I64AtomicRmw16SubU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x2b => Operator::I64AtomicRmw32USub {
|
||||
0x2b => Operator::I64AtomicRmw32SubU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x2c => Operator::I32AtomicRmwAnd {
|
||||
|
@ -733,19 +823,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x2d => Operator::I64AtomicRmwAnd {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x2e => Operator::I32AtomicRmw8UAnd {
|
||||
0x2e => Operator::I32AtomicRmw8AndU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x2f => Operator::I32AtomicRmw16UAnd {
|
||||
0x2f => Operator::I32AtomicRmw16AndU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x30 => Operator::I64AtomicRmw8UAnd {
|
||||
0x30 => Operator::I64AtomicRmw8AndU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x31 => Operator::I64AtomicRmw16UAnd {
|
||||
0x31 => Operator::I64AtomicRmw16AndU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x32 => Operator::I64AtomicRmw32UAnd {
|
||||
0x32 => Operator::I64AtomicRmw32AndU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x33 => Operator::I32AtomicRmwOr {
|
||||
|
@ -754,19 +844,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x34 => Operator::I64AtomicRmwOr {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x35 => Operator::I32AtomicRmw8UOr {
|
||||
0x35 => Operator::I32AtomicRmw8OrU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x36 => Operator::I32AtomicRmw16UOr {
|
||||
0x36 => Operator::I32AtomicRmw16OrU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x37 => Operator::I64AtomicRmw8UOr {
|
||||
0x37 => Operator::I64AtomicRmw8OrU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x38 => Operator::I64AtomicRmw16UOr {
|
||||
0x38 => Operator::I64AtomicRmw16OrU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x39 => Operator::I64AtomicRmw32UOr {
|
||||
0x39 => Operator::I64AtomicRmw32OrU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x3a => Operator::I32AtomicRmwXor {
|
||||
|
@ -775,19 +865,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x3b => Operator::I64AtomicRmwXor {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x3c => Operator::I32AtomicRmw8UXor {
|
||||
0x3c => Operator::I32AtomicRmw8XorU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x3d => Operator::I32AtomicRmw16UXor {
|
||||
0x3d => Operator::I32AtomicRmw16XorU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x3e => Operator::I64AtomicRmw8UXor {
|
||||
0x3e => Operator::I64AtomicRmw8XorU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x3f => Operator::I64AtomicRmw16UXor {
|
||||
0x3f => Operator::I64AtomicRmw16XorU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x40 => Operator::I64AtomicRmw32UXor {
|
||||
0x40 => Operator::I64AtomicRmw32XorU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x41 => Operator::I32AtomicRmwXchg {
|
||||
|
@ -796,19 +886,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x42 => Operator::I64AtomicRmwXchg {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x43 => Operator::I32AtomicRmw8UXchg {
|
||||
0x43 => Operator::I32AtomicRmw8XchgU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x44 => Operator::I32AtomicRmw16UXchg {
|
||||
0x44 => Operator::I32AtomicRmw16XchgU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x45 => Operator::I64AtomicRmw8UXchg {
|
||||
0x45 => Operator::I64AtomicRmw8XchgU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x46 => Operator::I64AtomicRmw16UXchg {
|
||||
0x46 => Operator::I64AtomicRmw16XchgU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x47 => Operator::I64AtomicRmw32UXchg {
|
||||
0x47 => Operator::I64AtomicRmw32XchgU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0x48 => Operator::I32AtomicRmwCmpxchg {
|
||||
|
@ -817,19 +907,19 @@ impl<'a> BinaryReader<'a> {
|
|||
0x49 => Operator::I64AtomicRmwCmpxchg {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0x4a => Operator::I32AtomicRmw8UCmpxchg {
|
||||
0x4a => Operator::I32AtomicRmw8CmpxchgU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x4b => Operator::I32AtomicRmw16UCmpxchg {
|
||||
0x4b => Operator::I32AtomicRmw16CmpxchgU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x4c => Operator::I64AtomicRmw8UCmpxchg {
|
||||
0x4c => Operator::I64AtomicRmw8CmpxchgU {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0x4d => Operator::I64AtomicRmw16UCmpxchg {
|
||||
0x4d => Operator::I64AtomicRmw16CmpxchgU {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0x4e => Operator::I64AtomicRmw32UCmpxchg {
|
||||
0x4e => Operator::I64AtomicRmw32CmpxchgU {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
|
||||
|
@ -849,7 +939,7 @@ impl<'a> BinaryReader<'a> {
|
|||
} else {
|
||||
self.position = position;
|
||||
let idx = self.read_var_s33()?;
|
||||
if idx < 0 || idx > (core::u32::MAX as i64) {
|
||||
if idx < 0 || idx > (std::u32::MAX as i64) {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid function type",
|
||||
offset: position,
|
||||
|
@ -859,6 +949,10 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reads the next available `Operator`.
|
||||
/// # Errors
|
||||
/// If `BinaryReader` has less bytes remaining than required to parse
|
||||
/// the `Operator`.
|
||||
pub fn read_operator(&mut self) -> Result<Operator<'a>> {
|
||||
let code = self.read_u8()? as u8;
|
||||
Ok(match code {
|
||||
|
@ -894,19 +988,31 @@ impl<'a> BinaryReader<'a> {
|
|||
},
|
||||
0x1a => Operator::Drop,
|
||||
0x1b => Operator::Select,
|
||||
0x20 => Operator::GetLocal {
|
||||
0x1c => {
|
||||
let results = self.read_var_u32()?;
|
||||
if results != 1 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "bad number of results",
|
||||
offset: self.position,
|
||||
});
|
||||
}
|
||||
Operator::TypedSelect {
|
||||
ty: self.read_type()?,
|
||||
}
|
||||
}
|
||||
0x20 => Operator::LocalGet {
|
||||
local_index: self.read_var_u32()?,
|
||||
},
|
||||
0x21 => Operator::SetLocal {
|
||||
0x21 => Operator::LocalSet {
|
||||
local_index: self.read_var_u32()?,
|
||||
},
|
||||
0x22 => Operator::TeeLocal {
|
||||
0x22 => Operator::LocalTee {
|
||||
local_index: self.read_var_u32()?,
|
||||
},
|
||||
0x23 => Operator::GetGlobal {
|
||||
0x23 => Operator::GlobalGet {
|
||||
global_index: self.read_var_u32()?,
|
||||
},
|
||||
0x24 => Operator::SetGlobal {
|
||||
0x24 => Operator::GlobalSet {
|
||||
global_index: self.read_var_u32()?,
|
||||
},
|
||||
0x25 => Operator::TableGet {
|
||||
|
@ -1101,25 +1207,25 @@ impl<'a> BinaryReader<'a> {
|
|||
0xa5 => Operator::F64Max,
|
||||
0xa6 => Operator::F64Copysign,
|
||||
0xa7 => Operator::I32WrapI64,
|
||||
0xa8 => Operator::I32TruncSF32,
|
||||
0xa9 => Operator::I32TruncUF32,
|
||||
0xaa => Operator::I32TruncSF64,
|
||||
0xab => Operator::I32TruncUF64,
|
||||
0xac => Operator::I64ExtendSI32,
|
||||
0xad => Operator::I64ExtendUI32,
|
||||
0xae => Operator::I64TruncSF32,
|
||||
0xaf => Operator::I64TruncUF32,
|
||||
0xb0 => Operator::I64TruncSF64,
|
||||
0xb1 => Operator::I64TruncUF64,
|
||||
0xb2 => Operator::F32ConvertSI32,
|
||||
0xb3 => Operator::F32ConvertUI32,
|
||||
0xb4 => Operator::F32ConvertSI64,
|
||||
0xb5 => Operator::F32ConvertUI64,
|
||||
0xa8 => Operator::I32TruncF32S,
|
||||
0xa9 => Operator::I32TruncF32U,
|
||||
0xaa => Operator::I32TruncF64S,
|
||||
0xab => Operator::I32TruncF64U,
|
||||
0xac => Operator::I64ExtendI32S,
|
||||
0xad => Operator::I64ExtendI32U,
|
||||
0xae => Operator::I64TruncF32S,
|
||||
0xaf => Operator::I64TruncF32U,
|
||||
0xb0 => Operator::I64TruncF64S,
|
||||
0xb1 => Operator::I64TruncF64U,
|
||||
0xb2 => Operator::F32ConvertI32S,
|
||||
0xb3 => Operator::F32ConvertI32U,
|
||||
0xb4 => Operator::F32ConvertI64S,
|
||||
0xb5 => Operator::F32ConvertI64U,
|
||||
0xb6 => Operator::F32DemoteF64,
|
||||
0xb7 => Operator::F64ConvertSI32,
|
||||
0xb8 => Operator::F64ConvertUI32,
|
||||
0xb9 => Operator::F64ConvertSI64,
|
||||
0xba => Operator::F64ConvertUI64,
|
||||
0xb7 => Operator::F64ConvertI32S,
|
||||
0xb8 => Operator::F64ConvertI32U,
|
||||
0xb9 => Operator::F64ConvertI64S,
|
||||
0xba => Operator::F64ConvertI64U,
|
||||
0xbb => Operator::F64PromoteF32,
|
||||
0xbc => Operator::I32ReinterpretF32,
|
||||
0xbd => Operator::I64ReinterpretF64,
|
||||
|
@ -1134,6 +1240,9 @@ impl<'a> BinaryReader<'a> {
|
|||
|
||||
0xd0 => Operator::RefNull,
|
||||
0xd1 => Operator::RefIsNull,
|
||||
0xd2 => Operator::RefFunc {
|
||||
function_index: self.read_var_u32()?,
|
||||
},
|
||||
|
||||
0xfc => self.read_0xfc_operator()?,
|
||||
0xfd => self.read_0xfd_operator()?,
|
||||
|
@ -1151,14 +1260,14 @@ impl<'a> BinaryReader<'a> {
|
|||
fn read_0xfc_operator(&mut self) -> Result<Operator<'a>> {
|
||||
let code = self.read_u8()? as u8;
|
||||
Ok(match code {
|
||||
0x00 => Operator::I32TruncSSatF32,
|
||||
0x01 => Operator::I32TruncUSatF32,
|
||||
0x02 => Operator::I32TruncSSatF64,
|
||||
0x03 => Operator::I32TruncUSatF64,
|
||||
0x04 => Operator::I64TruncSSatF32,
|
||||
0x05 => Operator::I64TruncUSatF32,
|
||||
0x06 => Operator::I64TruncSSatF64,
|
||||
0x07 => Operator::I64TruncUSatF64,
|
||||
0x00 => Operator::I32TruncSatF32S,
|
||||
0x01 => Operator::I32TruncSatF32U,
|
||||
0x02 => Operator::I32TruncSatF64S,
|
||||
0x03 => Operator::I32TruncSatF64U,
|
||||
0x04 => Operator::I64TruncSatF32S,
|
||||
0x05 => Operator::I64TruncSatF32U,
|
||||
0x06 => Operator::I64TruncSatF64S,
|
||||
0x07 => Operator::I64TruncSatF64U,
|
||||
|
||||
0x08 => {
|
||||
let segment = self.read_var_u32()?;
|
||||
|
@ -1176,15 +1285,15 @@ impl<'a> BinaryReader<'a> {
|
|||
Operator::DataDrop { segment }
|
||||
}
|
||||
0x0a => {
|
||||
let src = self.read_u8()?;
|
||||
if src != 0 {
|
||||
let dst = self.read_u8()?;
|
||||
if dst != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
let dst = self.read_u8()?;
|
||||
if dst != 0 {
|
||||
let src = self.read_u8()?;
|
||||
if src != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
|
@ -1204,35 +1313,20 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
0x0c => {
|
||||
let segment = self.read_var_u32()?;
|
||||
let table = self.read_u8()?;
|
||||
if table != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::TableInit { segment }
|
||||
let table = self.read_var_u32()?;
|
||||
Operator::TableInit { segment, table }
|
||||
}
|
||||
0x0d => {
|
||||
let segment = self.read_var_u32()?;
|
||||
Operator::ElemDrop { segment }
|
||||
}
|
||||
0x0e => {
|
||||
let src = self.read_u8()?;
|
||||
if src != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
let dst_table = self.read_var_u32()?;
|
||||
let src_table = self.read_var_u32()?;
|
||||
Operator::TableCopy {
|
||||
src_table,
|
||||
dst_table,
|
||||
}
|
||||
let dst = self.read_u8()?;
|
||||
if dst != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "reserved byte must be zero",
|
||||
offset: self.original_position() - 1,
|
||||
});
|
||||
}
|
||||
Operator::TableCopy
|
||||
}
|
||||
|
||||
0x0f => {
|
||||
|
@ -1244,6 +1338,11 @@ impl<'a> BinaryReader<'a> {
|
|||
Operator::TableSize { table }
|
||||
}
|
||||
|
||||
0x11 => {
|
||||
let table = self.read_var_u32()?;
|
||||
Operator::TableFill { table }
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Unknown 0xfc opcode",
|
||||
|
@ -1420,6 +1519,7 @@ impl<'a> BinaryReader<'a> {
|
|||
0x89 => Operator::I64x2ShrU,
|
||||
0x8a => Operator::I64x2Add,
|
||||
0x8d => Operator::I64x2Sub,
|
||||
0x90 => Operator::I64x2Mul,
|
||||
0x95 => Operator::F32x4Abs,
|
||||
0x96 => Operator::F32x4Neg,
|
||||
0x97 => Operator::F32x4Sqrt,
|
||||
|
@ -1438,34 +1538,67 @@ impl<'a> BinaryReader<'a> {
|
|||
0xa8 => Operator::F64x2Div,
|
||||
0xa9 => Operator::F64x2Min,
|
||||
0xaa => Operator::F64x2Max,
|
||||
0xab => Operator::I32x4TruncSF32x4Sat,
|
||||
0xac => Operator::I32x4TruncUF32x4Sat,
|
||||
0xad => Operator::I64x2TruncSF64x2Sat,
|
||||
0xae => Operator::I64x2TruncUF64x2Sat,
|
||||
0xaf => Operator::F32x4ConvertSI32x4,
|
||||
0xb0 => Operator::F32x4ConvertUI32x4,
|
||||
0xb1 => Operator::F64x2ConvertSI64x2,
|
||||
0xb2 => Operator::F64x2ConvertUI64x2,
|
||||
0xab => Operator::I32x4TruncSatF32x4S,
|
||||
0xac => Operator::I32x4TruncSatF32x4U,
|
||||
0xad => Operator::I64x2TruncSatF64x2S,
|
||||
0xae => Operator::I64x2TruncSatF64x2U,
|
||||
0xaf => Operator::F32x4ConvertI32x4S,
|
||||
0xb0 => Operator::F32x4ConvertI32x4U,
|
||||
0xb1 => Operator::F64x2ConvertI64x2S,
|
||||
0xb2 => Operator::F64x2ConvertI64x2U,
|
||||
0xc0 => Operator::V8x16Swizzle,
|
||||
0x03 | 0xc1 => {
|
||||
let mut lanes = [0 as SIMDLaneIndex; 16];
|
||||
for i in 0..16 {
|
||||
lanes[i] = self.read_lane_index(32)?
|
||||
for lane in &mut lanes {
|
||||
*lane = self.read_lane_index(32)?
|
||||
}
|
||||
Operator::V8x16Shuffle { lanes }
|
||||
}
|
||||
0xc2 => Operator::I8x16LoadSplat {
|
||||
0xc2 => Operator::V8x16LoadSplat {
|
||||
memarg: self.read_memarg_of_align(0)?,
|
||||
},
|
||||
0xc3 => Operator::I16x8LoadSplat {
|
||||
0xc3 => Operator::V16x8LoadSplat {
|
||||
memarg: self.read_memarg_of_align(1)?,
|
||||
},
|
||||
0xc4 => Operator::I32x4LoadSplat {
|
||||
0xc4 => Operator::V32x4LoadSplat {
|
||||
memarg: self.read_memarg_of_align(2)?,
|
||||
},
|
||||
0xc5 => Operator::I64x2LoadSplat {
|
||||
0xc5 => Operator::V64x2LoadSplat {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xc6 => Operator::I8x16NarrowI16x8S,
|
||||
0xc7 => Operator::I8x16NarrowI16x8U,
|
||||
0xc8 => Operator::I16x8NarrowI32x4S,
|
||||
0xc9 => Operator::I16x8NarrowI32x4U,
|
||||
0xca => Operator::I16x8WidenLowI8x16S,
|
||||
0xcb => Operator::I16x8WidenHighI8x16S,
|
||||
0xcc => Operator::I16x8WidenLowI8x16U,
|
||||
0xcd => Operator::I16x8WidenHighI8x16U,
|
||||
0xce => Operator::I32x4WidenLowI16x8S,
|
||||
0xcf => Operator::I32x4WidenHighI16x8S,
|
||||
0xd0 => Operator::I32x4WidenLowI16x8U,
|
||||
0xd1 => Operator::I32x4WidenHighI16x8U,
|
||||
0xd2 => Operator::I16x8Load8x8S {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd3 => Operator::I16x8Load8x8U {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd4 => Operator::I32x4Load16x4S {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd5 => Operator::I32x4Load16x4U {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd6 => Operator::I64x2Load32x2S {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd7 => Operator::I64x2Load32x2U {
|
||||
memarg: self.read_memarg_of_align(3)?,
|
||||
},
|
||||
0xd8 => Operator::V128AndNot,
|
||||
0xd9 => Operator::I8x16RoundingAverageU,
|
||||
0xda => Operator::I16x8RoundingAverageU,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Unknown 0xfd opcode",
|
||||
|
@ -1476,7 +1609,7 @@ impl<'a> BinaryReader<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn read_file_header(&mut self) -> Result<u32> {
|
||||
let magic_number = self.read_u32()?;
|
||||
let magic_number = self.read_bytes(4)?;
|
||||
if magic_number != WASM_MAGIC_NUMBER {
|
||||
return Err(BinaryReaderError {
|
||||
message: "Bad magic number",
|
||||
|
@ -1567,6 +1700,11 @@ impl<'a> BrTable<'a> {
|
|||
self.cnt
|
||||
}
|
||||
|
||||
/// Returns whether `BrTable` doesn't have any labels apart from the default one.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Reads br_table entries.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -1609,6 +1747,7 @@ impl<'a> BrTable<'a> {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BrTableIterator<'a> {
|
||||
reader: BinaryReader<'a>,
|
||||
}
|
||||
|
|
|
@ -23,24 +23,11 @@
|
|||
//! this is not the right library for you. You could however, build such
|
||||
//! a data-structure using this library.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_use]
|
||||
extern crate alloc as std;
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use hashbrown::HashSet;
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub use crate::binary_reader::BinaryReader;
|
||||
pub use crate::binary_reader::Range;
|
||||
use crate::binary_reader::SectionHeader;
|
||||
|
||||
pub use crate::parser::ElemSectionEntryTable;
|
||||
pub use crate::parser::LocalName;
|
||||
pub use crate::parser::NameEntry;
|
||||
pub use crate::parser::Parser;
|
||||
|
@ -88,6 +75,7 @@ pub use crate::readers::Data;
|
|||
pub use crate::readers::DataKind;
|
||||
pub use crate::readers::DataSectionReader;
|
||||
pub use crate::readers::Element;
|
||||
pub use crate::readers::ElementItem;
|
||||
pub use crate::readers::ElementItems;
|
||||
pub use crate::readers::ElementItemsReader;
|
||||
pub use crate::readers::ElementKind;
|
||||
|
|
|
@ -15,20 +15,20 @@
|
|||
|
||||
// The following limits are imposed by wasmparser on WebAssembly modules.
|
||||
// The limits are agreed upon with other engines for consistency.
|
||||
pub const MAX_WASM_TYPES: usize = 1000000;
|
||||
pub const MAX_WASM_FUNCTIONS: usize = 1000000;
|
||||
pub const _MAX_WASM_IMPORTS: usize = 100000;
|
||||
pub const _MAX_WASM_EXPORTS: usize = 100000;
|
||||
pub const MAX_WASM_GLOBALS: usize = 1000000;
|
||||
pub const _MAX_WASM_DATA_SEGMENTS: usize = 100000;
|
||||
pub const MAX_WASM_TYPES: usize = 1_000_000;
|
||||
pub const MAX_WASM_FUNCTIONS: usize = 1_000_000;
|
||||
pub const _MAX_WASM_IMPORTS: usize = 100_000;
|
||||
pub const _MAX_WASM_EXPORTS: usize = 100_000;
|
||||
pub const MAX_WASM_GLOBALS: usize = 1_000_000;
|
||||
pub const _MAX_WASM_DATA_SEGMENTS: usize = 100_000;
|
||||
pub const MAX_WASM_MEMORY_PAGES: usize = 65536;
|
||||
pub const MAX_WASM_STRING_SIZE: usize = 100000;
|
||||
pub const MAX_WASM_STRING_SIZE: usize = 100_000;
|
||||
pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
|
||||
pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024;
|
||||
pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000;
|
||||
pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000;
|
||||
pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000;
|
||||
pub const _MAX_WASM_TABLE_SIZE: usize = 10000000;
|
||||
pub const MAX_WASM_TABLE_ENTRIES: usize = 10000000;
|
||||
pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000;
|
||||
pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000;
|
||||
pub const MAX_WASM_TABLES: usize = 1;
|
||||
pub const MAX_WASM_MEMORIES: usize = 1;
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::cmp::min;
|
||||
use core::result;
|
||||
use std::cmp::min;
|
||||
use std::result;
|
||||
use std::str;
|
||||
use std::vec::Vec;
|
||||
|
||||
use crate::primitives::{
|
||||
FuncType, GlobalType, MemoryImmediate, MemoryType, Operator, SIMDLaneIndex, TableType, Type,
|
||||
|
@ -27,9 +26,9 @@ use crate::primitives::{
|
|||
pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
|
||||
match supertype {
|
||||
Type::AnyRef => {
|
||||
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::Null
|
||||
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef
|
||||
}
|
||||
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::Null,
|
||||
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef,
|
||||
_ => subtype == supertype,
|
||||
}
|
||||
}
|
||||
|
@ -373,10 +372,10 @@ impl OperatorValidator {
|
|||
fn check_operands(&self, expected_types: &[Type]) -> OperatorValidatorResult<()> {
|
||||
let len = expected_types.len();
|
||||
self.check_frame_size(len)?;
|
||||
for i in 0..len {
|
||||
for (i, expected_type) in expected_types.iter().enumerate() {
|
||||
if !self
|
||||
.func_state
|
||||
.assert_stack_type_at(len - 1 - i, expected_types[i])
|
||||
.assert_stack_type_at(len - 1 - i, *expected_type)
|
||||
{
|
||||
return Err("stack operand type mismatch");
|
||||
}
|
||||
|
@ -498,7 +497,7 @@ impl OperatorValidator {
|
|||
self.check_memory_index(0, resources)?;
|
||||
let align = memarg.flags;
|
||||
if align > max_align {
|
||||
return Err("align is required to be at most the number of accessed bytes");
|
||||
return Err("alignment must not be larger than natural");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -572,6 +571,9 @@ impl OperatorValidator {
|
|||
| TypeOrFuncType::Type(Type::I64)
|
||||
| TypeOrFuncType::Type(Type::F32)
|
||||
| TypeOrFuncType::Type(Type::F64) => Ok(()),
|
||||
TypeOrFuncType::Type(Type::AnyRef) | TypeOrFuncType::Type(Type::AnyFunc) => {
|
||||
self.check_reference_types_enabled()
|
||||
}
|
||||
TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(),
|
||||
TypeOrFuncType::FuncType(idx) => {
|
||||
let idx = idx as usize;
|
||||
|
@ -622,28 +624,35 @@ impl OperatorValidator {
|
|||
self.check_frame_size(3)?;
|
||||
let func_state = &self.func_state;
|
||||
let last_block = func_state.last_block();
|
||||
Ok(if last_block.is_stack_polymorphic() {
|
||||
|
||||
let ty = if last_block.is_stack_polymorphic() {
|
||||
match func_state.stack_types.len() - last_block.stack_starts_at {
|
||||
0 => None,
|
||||
0 => return Ok(None),
|
||||
1 => {
|
||||
self.check_operands_1(Type::I32)?;
|
||||
None
|
||||
return Ok(None);
|
||||
}
|
||||
2 => {
|
||||
self.check_operands_1(Type::I32)?;
|
||||
Some(func_state.stack_types[func_state.stack_types.len() - 2])
|
||||
func_state.stack_types[func_state.stack_types.len() - 2]
|
||||
}
|
||||
_ => {
|
||||
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
|
||||
self.check_operands_2(ty, Type::I32)?;
|
||||
Some(ty)
|
||||
ty
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
|
||||
self.check_operands_2(ty, Type::I32)?;
|
||||
Some(ty)
|
||||
})
|
||||
ty
|
||||
};
|
||||
|
||||
if !ty.is_valid_for_old_select() {
|
||||
return Err("invalid type for select");
|
||||
}
|
||||
|
||||
Ok(Some(ty))
|
||||
}
|
||||
|
||||
pub(crate) fn process_operator(
|
||||
|
@ -687,10 +696,9 @@ impl OperatorValidator {
|
|||
self.func_state.end_function();
|
||||
return Ok(FunctionEnd::Yes);
|
||||
}
|
||||
if {
|
||||
let last_block = &self.func_state.last_block();
|
||||
last_block.is_else_allowed && last_block.start_types != last_block.return_types
|
||||
} {
|
||||
|
||||
let last_block = &self.func_state.last_block();
|
||||
if last_block.is_else_allowed && last_block.start_types != last_block.return_types {
|
||||
return Err("else is expected: if block has a type that can't be implemented with a no-op");
|
||||
}
|
||||
self.func_state.pop_block()
|
||||
|
@ -760,14 +768,18 @@ impl OperatorValidator {
|
|||
let ty = self.check_select()?;
|
||||
self.func_state.change_frame_after_select(ty)?;
|
||||
}
|
||||
Operator::GetLocal { local_index } => {
|
||||
Operator::TypedSelect { ty } => {
|
||||
self.check_operands(&[Type::I32, ty, ty])?;
|
||||
self.func_state.change_frame_after_select(Some(ty))?;
|
||||
}
|
||||
Operator::LocalGet { local_index } => {
|
||||
if local_index as usize >= self.func_state.local_types.len() {
|
||||
return Err("local index out of bounds");
|
||||
}
|
||||
let local_type = self.func_state.local_types[local_index as usize];
|
||||
self.func_state.change_frame_with_type(0, local_type)?;
|
||||
}
|
||||
Operator::SetLocal { local_index } => {
|
||||
Operator::LocalSet { local_index } => {
|
||||
if local_index as usize >= self.func_state.local_types.len() {
|
||||
return Err("local index out of bounds");
|
||||
}
|
||||
|
@ -775,7 +787,7 @@ impl OperatorValidator {
|
|||
self.check_operands_1(local_type)?;
|
||||
self.func_state.change_frame(1)?;
|
||||
}
|
||||
Operator::TeeLocal { local_index } => {
|
||||
Operator::LocalTee { local_index } => {
|
||||
if local_index as usize >= self.func_state.local_types.len() {
|
||||
return Err("local index out of bounds");
|
||||
}
|
||||
|
@ -783,14 +795,14 @@ impl OperatorValidator {
|
|||
self.check_operands_1(local_type)?;
|
||||
self.func_state.change_frame_with_type(1, local_type)?;
|
||||
}
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
if global_index as usize >= resources.globals().len() {
|
||||
return Err("global index out of bounds");
|
||||
}
|
||||
let ty = &resources.globals()[global_index as usize];
|
||||
self.func_state.change_frame_with_type(0, ty.content_type)?;
|
||||
}
|
||||
Operator::SetGlobal { global_index } => {
|
||||
Operator::GlobalSet { global_index } => {
|
||||
if global_index as usize >= resources.globals().len() {
|
||||
return Err("global index out of bounds");
|
||||
}
|
||||
|
@ -1089,32 +1101,32 @@ impl OperatorValidator {
|
|||
self.check_operands_1(Type::I64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::I32TruncSF32 | Operator::I32TruncUF32 => {
|
||||
Operator::I32TruncF32S | Operator::I32TruncF32U => {
|
||||
self.check_operands_1(Type::F32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::I32TruncSF64 | Operator::I32TruncUF64 => {
|
||||
Operator::I32TruncF64S | Operator::I32TruncF64U => {
|
||||
self.check_operands_1(Type::F64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::I64ExtendSI32 | Operator::I64ExtendUI32 => {
|
||||
Operator::I64ExtendI32S | Operator::I64ExtendI32U => {
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I64)?;
|
||||
}
|
||||
Operator::I64TruncSF32 | Operator::I64TruncUF32 => {
|
||||
Operator::I64TruncF32S | Operator::I64TruncF32U => {
|
||||
self.check_operands_1(Type::F32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I64)?;
|
||||
}
|
||||
Operator::I64TruncSF64 | Operator::I64TruncUF64 => {
|
||||
Operator::I64TruncF64S | Operator::I64TruncF64U => {
|
||||
self.check_operands_1(Type::F64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I64)?;
|
||||
}
|
||||
Operator::F32ConvertSI32 | Operator::F32ConvertUI32 => {
|
||||
Operator::F32ConvertI32S | Operator::F32ConvertI32U => {
|
||||
self.check_non_deterministic_enabled()?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F32)?;
|
||||
}
|
||||
Operator::F32ConvertSI64 | Operator::F32ConvertUI64 => {
|
||||
Operator::F32ConvertI64S | Operator::F32ConvertI64U => {
|
||||
self.check_non_deterministic_enabled()?;
|
||||
self.check_operands_1(Type::I64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F32)?;
|
||||
|
@ -1124,12 +1136,12 @@ impl OperatorValidator {
|
|||
self.check_operands_1(Type::F64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F32)?;
|
||||
}
|
||||
Operator::F64ConvertSI32 | Operator::F64ConvertUI32 => {
|
||||
Operator::F64ConvertI32S | Operator::F64ConvertI32U => {
|
||||
self.check_non_deterministic_enabled()?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F64)?;
|
||||
}
|
||||
Operator::F64ConvertSI64 | Operator::F64ConvertUI64 => {
|
||||
Operator::F64ConvertI64S | Operator::F64ConvertI64U => {
|
||||
self.check_non_deterministic_enabled()?;
|
||||
self.check_operands_1(Type::I64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F64)?;
|
||||
|
@ -1157,19 +1169,19 @@ impl OperatorValidator {
|
|||
self.check_operands_1(Type::I64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::F64)?;
|
||||
}
|
||||
Operator::I32TruncSSatF32 | Operator::I32TruncUSatF32 => {
|
||||
Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => {
|
||||
self.check_operands_1(Type::F32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::I32TruncSSatF64 | Operator::I32TruncUSatF64 => {
|
||||
Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => {
|
||||
self.check_operands_1(Type::F64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::I64TruncSSatF32 | Operator::I64TruncUSatF32 => {
|
||||
Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => {
|
||||
self.check_operands_1(Type::F32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I64)?;
|
||||
}
|
||||
Operator::I64TruncSSatF64 | Operator::I64TruncUSatF64 => {
|
||||
Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => {
|
||||
self.check_operands_1(Type::F64)?;
|
||||
self.func_state.change_frame_with_type(1, Type::I64)?;
|
||||
}
|
||||
|
@ -1222,16 +1234,16 @@ impl OperatorValidator {
|
|||
| Operator::I32AtomicRmwAnd { ref memarg }
|
||||
| Operator::I32AtomicRmwOr { ref memarg }
|
||||
| Operator::I32AtomicRmwXor { ref memarg }
|
||||
| Operator::I32AtomicRmw16UAdd { ref memarg }
|
||||
| Operator::I32AtomicRmw16USub { ref memarg }
|
||||
| Operator::I32AtomicRmw16UAnd { ref memarg }
|
||||
| Operator::I32AtomicRmw16UOr { ref memarg }
|
||||
| Operator::I32AtomicRmw16UXor { ref memarg }
|
||||
| Operator::I32AtomicRmw8UAdd { ref memarg }
|
||||
| Operator::I32AtomicRmw8USub { ref memarg }
|
||||
| Operator::I32AtomicRmw8UAnd { ref memarg }
|
||||
| Operator::I32AtomicRmw8UOr { ref memarg }
|
||||
| Operator::I32AtomicRmw8UXor { ref memarg } => {
|
||||
| Operator::I32AtomicRmw16AddU { ref memarg }
|
||||
| Operator::I32AtomicRmw16SubU { ref memarg }
|
||||
| Operator::I32AtomicRmw16AndU { ref memarg }
|
||||
| Operator::I32AtomicRmw16OrU { ref memarg }
|
||||
| Operator::I32AtomicRmw16XorU { ref memarg }
|
||||
| Operator::I32AtomicRmw8AddU { ref memarg }
|
||||
| Operator::I32AtomicRmw8SubU { ref memarg }
|
||||
| Operator::I32AtomicRmw8AndU { ref memarg }
|
||||
| Operator::I32AtomicRmw8OrU { ref memarg }
|
||||
| Operator::I32AtomicRmw8XorU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands_2(Type::I32, Type::I32)?;
|
||||
|
@ -1242,79 +1254,79 @@ impl OperatorValidator {
|
|||
| Operator::I64AtomicRmwAnd { ref memarg }
|
||||
| Operator::I64AtomicRmwOr { ref memarg }
|
||||
| Operator::I64AtomicRmwXor { ref memarg }
|
||||
| Operator::I64AtomicRmw32UAdd { ref memarg }
|
||||
| Operator::I64AtomicRmw32USub { ref memarg }
|
||||
| Operator::I64AtomicRmw32UAnd { ref memarg }
|
||||
| Operator::I64AtomicRmw32UOr { ref memarg }
|
||||
| Operator::I64AtomicRmw32UXor { ref memarg }
|
||||
| Operator::I64AtomicRmw16UAdd { ref memarg }
|
||||
| Operator::I64AtomicRmw16USub { ref memarg }
|
||||
| Operator::I64AtomicRmw16UAnd { ref memarg }
|
||||
| Operator::I64AtomicRmw16UOr { ref memarg }
|
||||
| Operator::I64AtomicRmw16UXor { ref memarg }
|
||||
| Operator::I64AtomicRmw8UAdd { ref memarg }
|
||||
| Operator::I64AtomicRmw8USub { ref memarg }
|
||||
| Operator::I64AtomicRmw8UAnd { ref memarg }
|
||||
| Operator::I64AtomicRmw8UOr { ref memarg }
|
||||
| Operator::I64AtomicRmw8UXor { ref memarg } => {
|
||||
| Operator::I64AtomicRmw32AddU { ref memarg }
|
||||
| Operator::I64AtomicRmw32SubU { ref memarg }
|
||||
| Operator::I64AtomicRmw32AndU { ref memarg }
|
||||
| Operator::I64AtomicRmw32OrU { ref memarg }
|
||||
| Operator::I64AtomicRmw32XorU { ref memarg }
|
||||
| Operator::I64AtomicRmw16AddU { ref memarg }
|
||||
| Operator::I64AtomicRmw16SubU { ref memarg }
|
||||
| Operator::I64AtomicRmw16AndU { ref memarg }
|
||||
| Operator::I64AtomicRmw16OrU { ref memarg }
|
||||
| Operator::I64AtomicRmw16XorU { ref memarg }
|
||||
| Operator::I64AtomicRmw8AddU { ref memarg }
|
||||
| Operator::I64AtomicRmw8SubU { ref memarg }
|
||||
| Operator::I64AtomicRmw8AndU { ref memarg }
|
||||
| Operator::I64AtomicRmw8OrU { ref memarg }
|
||||
| Operator::I64AtomicRmw8XorU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands_2(Type::I32, Type::I64)?;
|
||||
self.func_state.change_frame_with_type(2, Type::I64)?;
|
||||
}
|
||||
Operator::I32AtomicRmwXchg { ref memarg }
|
||||
| Operator::I32AtomicRmw16UXchg { ref memarg }
|
||||
| Operator::I32AtomicRmw8UXchg { ref memarg } => {
|
||||
| Operator::I32AtomicRmw16XchgU { ref memarg }
|
||||
| Operator::I32AtomicRmw8XchgU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands_2(Type::I32, Type::I32)?;
|
||||
self.func_state.change_frame_with_type(2, Type::I32)?;
|
||||
}
|
||||
Operator::I32AtomicRmwCmpxchg { ref memarg }
|
||||
| Operator::I32AtomicRmw16UCmpxchg { ref memarg }
|
||||
| Operator::I32AtomicRmw8UCmpxchg { ref memarg } => {
|
||||
| Operator::I32AtomicRmw16CmpxchgU { ref memarg }
|
||||
| Operator::I32AtomicRmw8CmpxchgU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
|
||||
self.func_state.change_frame_with_type(3, Type::I32)?;
|
||||
}
|
||||
Operator::I64AtomicRmwXchg { ref memarg }
|
||||
| Operator::I64AtomicRmw32UXchg { ref memarg }
|
||||
| Operator::I64AtomicRmw16UXchg { ref memarg }
|
||||
| Operator::I64AtomicRmw8UXchg { ref memarg } => {
|
||||
| Operator::I64AtomicRmw32XchgU { ref memarg }
|
||||
| Operator::I64AtomicRmw16XchgU { ref memarg }
|
||||
| Operator::I64AtomicRmw8XchgU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands_2(Type::I32, Type::I64)?;
|
||||
self.func_state.change_frame_with_type(2, Type::I64)?;
|
||||
}
|
||||
Operator::I64AtomicRmwCmpxchg { ref memarg }
|
||||
| Operator::I64AtomicRmw32UCmpxchg { ref memarg }
|
||||
| Operator::I64AtomicRmw16UCmpxchg { ref memarg }
|
||||
| Operator::I64AtomicRmw8UCmpxchg { ref memarg } => {
|
||||
| Operator::I64AtomicRmw32CmpxchgU { ref memarg }
|
||||
| Operator::I64AtomicRmw16CmpxchgU { ref memarg }
|
||||
| Operator::I64AtomicRmw8CmpxchgU { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands(&[Type::I32, Type::I64, Type::I64])?;
|
||||
self.func_state.change_frame_with_type(3, Type::I64)?;
|
||||
}
|
||||
Operator::Wake { ref memarg } => {
|
||||
Operator::AtomicNotify { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands_2(Type::I32, Type::I32)?;
|
||||
self.func_state.change_frame_with_type(2, Type::I32)?;
|
||||
}
|
||||
Operator::I32Wait { ref memarg } => {
|
||||
Operator::I32AtomicWait { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands(&[Type::I32, Type::I32, Type::I64])?;
|
||||
self.func_state.change_frame_with_type(3, Type::I32)?;
|
||||
}
|
||||
Operator::I64Wait { ref memarg } => {
|
||||
Operator::I64AtomicWait { ref memarg } => {
|
||||
self.check_threads_enabled()?;
|
||||
self.check_shared_memarg_wo_align(memarg, resources)?;
|
||||
self.check_operands(&[Type::I32, Type::I64, Type::I64])?;
|
||||
self.func_state.change_frame_with_type(3, Type::I32)?;
|
||||
}
|
||||
Operator::Fence { ref flags } => {
|
||||
Operator::AtomicFence { ref flags } => {
|
||||
self.check_threads_enabled()?;
|
||||
if *flags != 0 {
|
||||
return Err("non-zero flags for fence not supported yet");
|
||||
|
@ -1322,13 +1334,20 @@ impl OperatorValidator {
|
|||
}
|
||||
Operator::RefNull => {
|
||||
self.check_reference_types_enabled()?;
|
||||
self.func_state.change_frame_with_type(0, Type::Null)?;
|
||||
self.func_state.change_frame_with_type(0, Type::NullRef)?;
|
||||
}
|
||||
Operator::RefIsNull => {
|
||||
self.check_reference_types_enabled()?;
|
||||
self.check_operands(&[Type::AnyRef])?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
}
|
||||
Operator::RefFunc { function_index } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if function_index as usize >= resources.func_type_indices().len() {
|
||||
return Err("function index out of bounds");
|
||||
}
|
||||
self.func_state.change_frame_with_type(0, Type::AnyFunc)?;
|
||||
}
|
||||
Operator::V128Load { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 4, resources)?;
|
||||
|
@ -1503,6 +1522,7 @@ impl OperatorValidator {
|
|||
| Operator::I32x4GeS
|
||||
| Operator::I32x4GeU
|
||||
| Operator::V128And
|
||||
| Operator::V128AndNot
|
||||
| Operator::V128Or
|
||||
| Operator::V128Xor
|
||||
| Operator::I8x16Add
|
||||
|
@ -1523,7 +1543,14 @@ impl OperatorValidator {
|
|||
| Operator::I32x4Sub
|
||||
| Operator::I32x4Mul
|
||||
| Operator::I64x2Add
|
||||
| Operator::I64x2Sub => {
|
||||
| Operator::I64x2Sub
|
||||
| Operator::I64x2Mul
|
||||
| Operator::I8x16RoundingAverageU
|
||||
| Operator::I16x8RoundingAverageU
|
||||
| Operator::I8x16NarrowI16x8S
|
||||
| Operator::I8x16NarrowI16x8U
|
||||
| Operator::I16x8NarrowI32x4S
|
||||
| Operator::I16x8NarrowI32x4U => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_2(Type::V128, Type::V128)?;
|
||||
self.func_state.change_frame_with_type(2, Type::V128)?;
|
||||
|
@ -1534,10 +1561,10 @@ impl OperatorValidator {
|
|||
| Operator::F64x2Abs
|
||||
| Operator::F64x2Neg
|
||||
| Operator::F64x2Sqrt
|
||||
| Operator::F32x4ConvertSI32x4
|
||||
| Operator::F32x4ConvertUI32x4
|
||||
| Operator::F64x2ConvertSI64x2
|
||||
| Operator::F64x2ConvertUI64x2 => {
|
||||
| Operator::F32x4ConvertI32x4S
|
||||
| Operator::F32x4ConvertI32x4U
|
||||
| Operator::F64x2ConvertI64x2S
|
||||
| Operator::F64x2ConvertI64x2U => {
|
||||
self.check_non_deterministic_enabled()?;
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(Type::V128)?;
|
||||
|
@ -1548,10 +1575,18 @@ impl OperatorValidator {
|
|||
| Operator::I16x8Neg
|
||||
| Operator::I32x4Neg
|
||||
| Operator::I64x2Neg
|
||||
| Operator::I32x4TruncSF32x4Sat
|
||||
| Operator::I32x4TruncUF32x4Sat
|
||||
| Operator::I64x2TruncSF64x2Sat
|
||||
| Operator::I64x2TruncUF64x2Sat => {
|
||||
| Operator::I32x4TruncSatF32x4S
|
||||
| Operator::I32x4TruncSatF32x4U
|
||||
| Operator::I64x2TruncSatF64x2S
|
||||
| Operator::I64x2TruncSatF64x2U
|
||||
| Operator::I16x8WidenLowI8x16S
|
||||
| Operator::I16x8WidenHighI8x16S
|
||||
| Operator::I16x8WidenLowI8x16U
|
||||
| Operator::I16x8WidenHighI8x16U
|
||||
| Operator::I32x4WidenLowI16x8S
|
||||
| Operator::I32x4WidenHighI16x8S
|
||||
| Operator::I32x4WidenLowI16x8U
|
||||
| Operator::I32x4WidenHighI16x8U => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_operands_1(Type::V128)?;
|
||||
self.func_state.change_frame_with_type(1, Type::V128)?;
|
||||
|
@ -1602,12 +1637,34 @@ impl OperatorValidator {
|
|||
}
|
||||
self.func_state.change_frame_with_type(2, Type::V128)?;
|
||||
}
|
||||
Operator::I8x16LoadSplat { ref memarg }
|
||||
| Operator::I16x8LoadSplat { ref memarg }
|
||||
| Operator::I32x4LoadSplat { ref memarg }
|
||||
| Operator::I64x2LoadSplat { ref memarg } => {
|
||||
Operator::V8x16LoadSplat { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 4, resources)?;
|
||||
self.check_memarg(memarg, 0, resources)?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::V128)?;
|
||||
}
|
||||
Operator::V16x8LoadSplat { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 1, resources)?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::V128)?;
|
||||
}
|
||||
Operator::V32x4LoadSplat { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 2, resources)?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::V128)?;
|
||||
}
|
||||
Operator::V64x2LoadSplat { ref memarg }
|
||||
| Operator::I16x8Load8x8S { ref memarg }
|
||||
| Operator::I16x8Load8x8U { ref memarg }
|
||||
| Operator::I32x4Load16x4S { ref memarg }
|
||||
| Operator::I32x4Load16x4U { ref memarg }
|
||||
| Operator::I64x2Load32x2S { ref memarg }
|
||||
| Operator::I64x2Load32x2U { ref memarg } => {
|
||||
self.check_simd_enabled()?;
|
||||
self.check_memarg(memarg, 3, resources)?;
|
||||
self.check_operands_1(Type::I32)?;
|
||||
self.func_state.change_frame_with_type(1, Type::V128)?;
|
||||
}
|
||||
|
||||
|
@ -1632,12 +1689,15 @@ impl OperatorValidator {
|
|||
self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
|
||||
self.func_state.change_frame(3)?;
|
||||
}
|
||||
Operator::TableInit { segment } => {
|
||||
Operator::TableInit { segment, table } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if segment >= resources.element_count() {
|
||||
return Err("segment index out of bounds");
|
||||
}
|
||||
if 0 >= resources.tables().len() {
|
||||
if table > 0 {
|
||||
self.check_reference_types_enabled()?;
|
||||
}
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
|
||||
|
@ -1649,9 +1709,17 @@ impl OperatorValidator {
|
|||
return Err("segment index out of bounds");
|
||||
}
|
||||
}
|
||||
Operator::TableCopy => {
|
||||
Operator::TableCopy {
|
||||
src_table,
|
||||
dst_table,
|
||||
} => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
if 0 >= resources.tables().len() {
|
||||
if src_table > 0 || dst_table > 0 {
|
||||
self.check_reference_types_enabled()?;
|
||||
}
|
||||
if src_table as usize >= resources.tables().len()
|
||||
|| dst_table as usize >= resources.tables().len()
|
||||
{
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(&[Type::I32, Type::I32, Type::I32])?;
|
||||
|
@ -1659,34 +1727,46 @@ impl OperatorValidator {
|
|||
}
|
||||
Operator::TableGet { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
let ty = match resources.tables().get(table as usize) {
|
||||
Some(ty) => ty.element_type,
|
||||
None => return Err("table index out of bounds"),
|
||||
};
|
||||
self.check_operands(&[Type::I32])?;
|
||||
self.func_state.change_frame_with_type(1, Type::AnyRef)?;
|
||||
self.func_state.change_frame_with_type(1, ty)?;
|
||||
}
|
||||
Operator::TableSet { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(&[Type::I32, Type::AnyRef])?;
|
||||
let ty = match resources.tables().get(table as usize) {
|
||||
Some(ty) => ty.element_type,
|
||||
None => return Err("table index out of bounds"),
|
||||
};
|
||||
self.check_operands(&[Type::I32, ty])?;
|
||||
self.func_state.change_frame(2)?;
|
||||
}
|
||||
Operator::TableGrow { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.check_operands(&[Type::I32])?;
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
let ty = match resources.tables().get(table as usize) {
|
||||
Some(ty) => ty.element_type,
|
||||
None => return Err("table index out of bounds"),
|
||||
};
|
||||
self.check_operands(&[ty, Type::I32])?;
|
||||
self.func_state.change_frame_with_type(2, Type::I32)?;
|
||||
}
|
||||
Operator::TableSize { table } => {
|
||||
self.check_reference_types_enabled()?;
|
||||
if table as usize >= resources.tables().len() {
|
||||
return Err("table index out of bounds");
|
||||
}
|
||||
self.func_state.change_frame_with_type(1, Type::I32)?;
|
||||
self.func_state.change_frame_with_type(0, Type::I32)?;
|
||||
}
|
||||
Operator::TableFill { table } => {
|
||||
self.check_bulk_memory_enabled()?;
|
||||
let ty = match resources.tables().get(table as usize) {
|
||||
Some(ty) => ty.element_type,
|
||||
None => return Err("table index out of bounds"),
|
||||
};
|
||||
self.check_operands(&[Type::I32, ty, Type::I32])?;
|
||||
self.func_state.change_frame(3)?;
|
||||
}
|
||||
}
|
||||
Ok(FunctionEnd::No)
|
||||
|
|
|
@ -28,11 +28,12 @@ use crate::primitives::{
|
|||
};
|
||||
|
||||
use crate::readers::{
|
||||
CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
|
||||
ElementSectionReader, Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global,
|
||||
GlobalSectionReader, Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader,
|
||||
ModuleReader, Name, NameSectionReader, NamingReader, OperatorsReader, Reloc,
|
||||
RelocSectionReader, Section, SectionReader, TableSectionReader, TypeSectionReader,
|
||||
CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
|
||||
ElementKind, ElementSectionReader, Export, ExportSectionReader, FunctionBody,
|
||||
FunctionSectionReader, Global, GlobalSectionReader, Import, ImportSectionReader,
|
||||
LinkingSectionReader, MemorySectionReader, ModuleReader, Name, NameSectionReader, NamingReader,
|
||||
OperatorsReader, Reloc, RelocSectionReader, Section, SectionReader, TableSectionReader,
|
||||
TypeSectionReader,
|
||||
};
|
||||
|
||||
use crate::binary_reader::{BinaryReader, Range};
|
||||
|
@ -60,10 +61,10 @@ pub struct RelocEntry {
|
|||
pub addend: Option<u32>,
|
||||
}
|
||||
|
||||
enum InitExpressionContinuation {
|
||||
GlobalSection,
|
||||
ElementSection,
|
||||
DataSection,
|
||||
enum InitExpressionContinuationSection {
|
||||
Global,
|
||||
Element,
|
||||
Data,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -116,9 +117,12 @@ pub enum ParserState<'a> {
|
|||
EndFunctionBody,
|
||||
SkippingFunctionBody,
|
||||
|
||||
BeginPassiveElementSectionEntry(Type),
|
||||
BeginActiveElementSectionEntry(u32),
|
||||
ElementSectionEntryBody(Box<[u32]>),
|
||||
BeginElementSectionEntry {
|
||||
/// `None` means this is a passive or defined entry
|
||||
table: ElemSectionEntryTable,
|
||||
ty: Type,
|
||||
},
|
||||
ElementSectionEntryBody(Box<[ElementItem]>),
|
||||
EndElementSectionEntry,
|
||||
|
||||
BeginPassiveDataSectionEntry,
|
||||
|
@ -138,6 +142,13 @@ pub enum ParserState<'a> {
|
|||
SourceMappingURL(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ElemSectionEntryTable {
|
||||
Passive,
|
||||
Declared,
|
||||
Active(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ParserInput {
|
||||
Default,
|
||||
|
@ -206,7 +217,7 @@ pub struct Parser<'a> {
|
|||
section_reader: ParserSectionReader<'a>,
|
||||
element_items: Option<ElementItems<'a>>,
|
||||
current_function_body: Option<FunctionBody<'a>>,
|
||||
init_expr_continuation: Option<InitExpressionContinuation>,
|
||||
init_expr_continuation: Option<InitExpressionContinuationSection>,
|
||||
current_data_segment: Option<&'a [u8]>,
|
||||
binary_reader: Option<BinaryReader<'a>>,
|
||||
operators_reader: Option<OperatorsReader<'a>>,
|
||||
|
@ -385,7 +396,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn read_init_expression_body(&mut self, cont: InitExpressionContinuation) {
|
||||
fn read_init_expression_body(&mut self, cont: InitExpressionContinuationSection) {
|
||||
self.state = ParserState::BeginInitExpressionBody;
|
||||
self.init_expr_continuation = Some(cont);
|
||||
}
|
||||
|
@ -419,19 +430,19 @@ impl<'a> Parser<'a> {
|
|||
if self.section_entries_left == 0 {
|
||||
return self.check_section_end();
|
||||
}
|
||||
let Element { kind, items } = section_reader!(self, ElementSectionReader).read()?;
|
||||
match kind {
|
||||
ElementKind::Passive(ty) => {
|
||||
self.state = ParserState::BeginPassiveElementSectionEntry(ty);
|
||||
}
|
||||
let Element { kind, items, ty } = section_reader!(self, ElementSectionReader).read()?;
|
||||
let table = match kind {
|
||||
ElementKind::Passive => ElemSectionEntryTable::Passive,
|
||||
ElementKind::Declared => ElemSectionEntryTable::Declared,
|
||||
ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
} => {
|
||||
self.state = ParserState::BeginActiveElementSectionEntry(table_index);
|
||||
self.operators_reader = Some(init_expr.get_operators_reader());
|
||||
ElemSectionEntryTable::Active(table_index)
|
||||
}
|
||||
}
|
||||
};
|
||||
self.state = ParserState::BeginElementSectionEntry { table, ty };
|
||||
self.element_items = Some(items);
|
||||
self.section_entries_left -= 1;
|
||||
Ok(())
|
||||
|
@ -450,7 +461,7 @@ impl<'a> Parser<'a> {
|
|||
offset: 0, // reader.position - 1, // TODO offset
|
||||
});
|
||||
}
|
||||
let mut elements: Vec<u32> = Vec::with_capacity(num_elements);
|
||||
let mut elements = Vec::with_capacity(num_elements);
|
||||
for _ in 0..num_elements {
|
||||
elements.push(reader.read()?);
|
||||
}
|
||||
|
@ -863,7 +874,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn read_data_chunk(&mut self) -> Result<()> {
|
||||
let data = self.current_data_segment.expect("data");
|
||||
if data.len() == 0 {
|
||||
if data.is_empty() {
|
||||
self.state = ParserState::EndDataSectionEntryBody;
|
||||
self.current_data_segment = None;
|
||||
return Ok(());
|
||||
|
@ -907,31 +918,32 @@ impl<'a> Parser<'a> {
|
|||
ParserState::TableSectionEntry(_) => self.read_table_entry()?,
|
||||
ParserState::ExportSectionEntry { .. } => self.read_export_entry()?,
|
||||
ParserState::BeginGlobalSectionEntry(_) => {
|
||||
self.read_init_expression_body(InitExpressionContinuation::GlobalSection)
|
||||
self.read_init_expression_body(InitExpressionContinuationSection::Global)
|
||||
}
|
||||
ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
|
||||
ParserState::BeginPassiveElementSectionEntry(_) => self.read_element_entry_body()?,
|
||||
ParserState::BeginActiveElementSectionEntry(_) => {
|
||||
self.read_init_expression_body(InitExpressionContinuation::ElementSection)
|
||||
ParserState::BeginElementSectionEntry {
|
||||
table: ElemSectionEntryTable::Active(_),
|
||||
..
|
||||
} => self.read_init_expression_body(InitExpressionContinuationSection::Element),
|
||||
ParserState::BeginElementSectionEntry { table: _, .. } => {
|
||||
self.read_element_entry_body()?
|
||||
}
|
||||
ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => {
|
||||
self.read_init_expression_operator()?
|
||||
}
|
||||
ParserState::BeginPassiveDataSectionEntry => {
|
||||
self.read_data_entry_body()?;
|
||||
}
|
||||
ParserState::BeginPassiveDataSectionEntry => self.read_data_entry_body()?,
|
||||
ParserState::BeginActiveDataSectionEntry(_) => {
|
||||
self.read_init_expression_body(InitExpressionContinuation::DataSection)
|
||||
self.read_init_expression_body(InitExpressionContinuationSection::Data)
|
||||
}
|
||||
ParserState::EndInitExpressionBody => {
|
||||
match self.init_expr_continuation {
|
||||
Some(InitExpressionContinuation::GlobalSection) => {
|
||||
Some(InitExpressionContinuationSection::Global) => {
|
||||
self.state = ParserState::EndGlobalSectionEntry
|
||||
}
|
||||
Some(InitExpressionContinuation::ElementSection) => {
|
||||
Some(InitExpressionContinuationSection::Element) => {
|
||||
self.read_element_entry_body()?
|
||||
}
|
||||
Some(InitExpressionContinuation::DataSection) => self.read_data_entry_body()?,
|
||||
Some(InitExpressionContinuationSection::Data) => self.read_data_entry_body()?,
|
||||
None => unreachable!(),
|
||||
}
|
||||
self.init_expr_continuation = None;
|
||||
|
@ -1078,11 +1090,19 @@ impl<'a> WasmDecoder<'a> for Parser<'a> {
|
|||
/// # 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0xb];
|
||||
/// use wasmparser::{WasmDecoder, Parser, ParserState};
|
||||
/// let mut parser = Parser::new(data);
|
||||
/// let mut types = Vec::new();
|
||||
/// let mut function_types = Vec::new();
|
||||
/// let mut function_readers = Vec::new();
|
||||
/// loop {
|
||||
/// match *parser.read() {
|
||||
/// match parser.read() {
|
||||
/// ParserState::Error(_) |
|
||||
/// ParserState::EndWasm => break,
|
||||
/// ParserState::TypeSectionEntry(ty) => {
|
||||
/// types.push(ty.clone());
|
||||
/// }
|
||||
/// ParserState::FunctionSectionEntry(id) => {
|
||||
/// function_types.push(id.clone());
|
||||
/// }
|
||||
/// ParserState::BeginFunctionBody {..} => {
|
||||
/// let reader = parser.create_binary_reader();
|
||||
/// function_readers.push(reader);
|
||||
|
@ -1091,9 +1111,21 @@ impl<'a> WasmDecoder<'a> for Parser<'a> {
|
|||
/// }
|
||||
/// }
|
||||
/// for (i, reader) in function_readers.iter_mut().enumerate() {
|
||||
/// println!("Function {}", i);
|
||||
/// // Access the function type through the types table.
|
||||
/// let ty = &types[function_types[i] as usize];
|
||||
/// println!("\nFunction {} of type {:?}", i, ty);
|
||||
/// // Read the local declarations required by the function body.
|
||||
/// let local_decls_len = reader.read_local_count().unwrap();
|
||||
/// let mut local_decls = Vec::with_capacity(local_decls_len);
|
||||
/// let mut local_count = ty.params.len();
|
||||
/// for _ in 0..local_decls_len {
|
||||
/// let local_decl = reader.read_local_decl(&mut local_count).unwrap();
|
||||
/// local_decls.push(local_decl);
|
||||
/// }
|
||||
/// println!("Function locals: vars {:?}; total {} ", local_decls, local_count);
|
||||
/// // Read the operations of the function body.
|
||||
/// while let Ok(ref op) = reader.read_operator() {
|
||||
/// println!(" {:?}", op);
|
||||
/// println!(" {:?}", op);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -13,12 +13,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::result;
|
||||
use std::boxed::Box;
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct BinaryReaderError {
|
||||
|
@ -28,7 +25,6 @@ pub struct BinaryReaderError {
|
|||
|
||||
pub type Result<T> = result::Result<T, BinaryReaderError>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for BinaryReaderError {}
|
||||
|
||||
impl fmt::Display for BinaryReaderError {
|
||||
|
@ -82,9 +78,18 @@ pub enum Type {
|
|||
V128,
|
||||
AnyFunc,
|
||||
AnyRef,
|
||||
NullRef,
|
||||
Func,
|
||||
EmptyBlockType,
|
||||
Null,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub(crate) fn is_valid_for_old_select(&self) -> bool {
|
||||
match self {
|
||||
Type::I32 | Type::I64 | Type::F32 | Type::F64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Either a value type or a function type.
|
||||
|
@ -150,7 +155,7 @@ pub enum ImportSectionEntryType {
|
|||
Global(GlobalType),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryImmediate {
|
||||
pub flags: u32,
|
||||
pub offset: u32,
|
||||
|
@ -187,7 +192,7 @@ pub enum RelocType {
|
|||
}
|
||||
|
||||
/// A br_table entries representation.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BrTable<'a> {
|
||||
pub(crate) buffer: &'a [u8],
|
||||
pub(crate) cnt: usize,
|
||||
|
@ -233,7 +238,7 @@ pub type SIMDLaneIndex = u8;
|
|||
/// Instructions as defined [here].
|
||||
///
|
||||
/// [here]: https://webassembly.github.io/spec/core/binary/instructions.html
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Operator<'a> {
|
||||
Unreachable,
|
||||
Nop,
|
||||
|
@ -250,11 +255,12 @@ pub enum Operator<'a> {
|
|||
CallIndirect { index: u32, table_index: u32 },
|
||||
Drop,
|
||||
Select,
|
||||
GetLocal { local_index: u32 },
|
||||
SetLocal { local_index: u32 },
|
||||
TeeLocal { local_index: u32 },
|
||||
GetGlobal { global_index: u32 },
|
||||
SetGlobal { global_index: u32 },
|
||||
TypedSelect { ty: Type },
|
||||
LocalGet { local_index: u32 },
|
||||
LocalSet { local_index: u32 },
|
||||
LocalTee { local_index: u32 },
|
||||
GlobalGet { global_index: u32 },
|
||||
GlobalSet { global_index: u32 },
|
||||
I32Load { memarg: MemoryImmediate },
|
||||
I64Load { memarg: MemoryImmediate },
|
||||
F32Load { memarg: MemoryImmediate },
|
||||
|
@ -286,6 +292,7 @@ pub enum Operator<'a> {
|
|||
F64Const { value: Ieee64 },
|
||||
RefNull,
|
||||
RefIsNull,
|
||||
RefFunc { function_index: u32 },
|
||||
I32Eqz,
|
||||
I32Eq,
|
||||
I32Ne,
|
||||
|
@ -385,25 +392,25 @@ pub enum Operator<'a> {
|
|||
F64Max,
|
||||
F64Copysign,
|
||||
I32WrapI64,
|
||||
I32TruncSF32,
|
||||
I32TruncUF32,
|
||||
I32TruncSF64,
|
||||
I32TruncUF64,
|
||||
I64ExtendSI32,
|
||||
I64ExtendUI32,
|
||||
I64TruncSF32,
|
||||
I64TruncUF32,
|
||||
I64TruncSF64,
|
||||
I64TruncUF64,
|
||||
F32ConvertSI32,
|
||||
F32ConvertUI32,
|
||||
F32ConvertSI64,
|
||||
F32ConvertUI64,
|
||||
I32TruncF32S,
|
||||
I32TruncF32U,
|
||||
I32TruncF64S,
|
||||
I32TruncF64U,
|
||||
I64ExtendI32S,
|
||||
I64ExtendI32U,
|
||||
I64TruncF32S,
|
||||
I64TruncF32U,
|
||||
I64TruncF64S,
|
||||
I64TruncF64U,
|
||||
F32ConvertI32S,
|
||||
F32ConvertI32U,
|
||||
F32ConvertI64S,
|
||||
F32ConvertI64U,
|
||||
F32DemoteF64,
|
||||
F64ConvertSI32,
|
||||
F64ConvertUI32,
|
||||
F64ConvertSI64,
|
||||
F64ConvertUI64,
|
||||
F64ConvertI32S,
|
||||
F64ConvertI32U,
|
||||
F64ConvertI64S,
|
||||
F64ConvertI64U,
|
||||
F64PromoteF32,
|
||||
I32ReinterpretF32,
|
||||
I64ReinterpretF64,
|
||||
|
@ -417,14 +424,14 @@ pub enum Operator<'a> {
|
|||
|
||||
// 0xFC operators
|
||||
// Non-trapping Float-to-int Conversions
|
||||
I32TruncSSatF32,
|
||||
I32TruncUSatF32,
|
||||
I32TruncSSatF64,
|
||||
I32TruncUSatF64,
|
||||
I64TruncSSatF32,
|
||||
I64TruncUSatF32,
|
||||
I64TruncSSatF64,
|
||||
I64TruncUSatF64,
|
||||
I32TruncSatF32S,
|
||||
I32TruncSatF32U,
|
||||
I32TruncSatF64S,
|
||||
I32TruncSatF64U,
|
||||
I64TruncSatF32S,
|
||||
I64TruncSatF32U,
|
||||
I64TruncSatF64S,
|
||||
I64TruncSatF64U,
|
||||
|
||||
// 0xFC operators
|
||||
// bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
|
||||
|
@ -432,9 +439,10 @@ pub enum Operator<'a> {
|
|||
DataDrop { segment: u32 },
|
||||
MemoryCopy,
|
||||
MemoryFill,
|
||||
TableInit { segment: u32 },
|
||||
TableInit { segment: u32, table: u32 },
|
||||
ElemDrop { segment: u32 },
|
||||
TableCopy,
|
||||
TableCopy { dst_table: u32, src_table: u32 },
|
||||
TableFill { table: u32 },
|
||||
TableGet { table: u32 },
|
||||
TableSet { table: u32 },
|
||||
TableGrow { table: u32 },
|
||||
|
@ -442,10 +450,10 @@ pub enum Operator<'a> {
|
|||
|
||||
// 0xFE operators
|
||||
// https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
|
||||
Wake { memarg: MemoryImmediate },
|
||||
I32Wait { memarg: MemoryImmediate },
|
||||
I64Wait { memarg: MemoryImmediate },
|
||||
Fence { flags: u8 },
|
||||
AtomicNotify { memarg: MemoryImmediate },
|
||||
I32AtomicWait { memarg: MemoryImmediate },
|
||||
I64AtomicWait { memarg: MemoryImmediate },
|
||||
AtomicFence { flags: u8 },
|
||||
I32AtomicLoad { memarg: MemoryImmediate },
|
||||
I64AtomicLoad { memarg: MemoryImmediate },
|
||||
I32AtomicLoad8U { memarg: MemoryImmediate },
|
||||
|
@ -462,53 +470,53 @@ pub enum Operator<'a> {
|
|||
I64AtomicStore32 { memarg: MemoryImmediate },
|
||||
I32AtomicRmwAdd { memarg: MemoryImmediate },
|
||||
I64AtomicRmwAdd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UAdd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UAdd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UAdd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UAdd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UAdd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8AddU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16AddU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8AddU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16AddU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32AddU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwSub { memarg: MemoryImmediate },
|
||||
I64AtomicRmwSub { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8USub { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16USub { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8USub { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16USub { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32USub { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8SubU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16SubU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8SubU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16SubU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32SubU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwAnd { memarg: MemoryImmediate },
|
||||
I64AtomicRmwAnd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UAnd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UAnd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UAnd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UAnd { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UAnd { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8AndU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16AndU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8AndU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16AndU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32AndU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwOr { memarg: MemoryImmediate },
|
||||
I64AtomicRmwOr { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UOr { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UOr { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UOr { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UOr { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UOr { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8OrU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16OrU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8OrU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16OrU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32OrU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwXor { memarg: MemoryImmediate },
|
||||
I64AtomicRmwXor { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UXor { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UXor { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UXor { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UXor { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UXor { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8XorU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16XorU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8XorU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16XorU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32XorU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwXchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmwXchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UXchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UXchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UXchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UXchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UXchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8XchgU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16XchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8XchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16XchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32XchgU { memarg: MemoryImmediate },
|
||||
I32AtomicRmwCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmwCmpxchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8UCmpxchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16UCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8UCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16UCmpxchg { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32UCmpxchg { memarg: MemoryImmediate },
|
||||
I32AtomicRmw8CmpxchgU { memarg: MemoryImmediate },
|
||||
I32AtomicRmw16CmpxchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw8CmpxchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw16CmpxchgU { memarg: MemoryImmediate },
|
||||
I64AtomicRmw32CmpxchgU { memarg: MemoryImmediate },
|
||||
|
||||
// 0xFD operators
|
||||
// SIMD https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md
|
||||
|
@ -579,6 +587,7 @@ pub enum Operator<'a> {
|
|||
F64x2Ge,
|
||||
V128Not,
|
||||
V128And,
|
||||
V128AndNot,
|
||||
V128Or,
|
||||
V128Xor,
|
||||
V128Bitselect,
|
||||
|
@ -625,6 +634,7 @@ pub enum Operator<'a> {
|
|||
I64x2ShrU,
|
||||
I64x2Add,
|
||||
I64x2Sub,
|
||||
I64x2Mul,
|
||||
F32x4Abs,
|
||||
F32x4Neg,
|
||||
F32x4Sqrt,
|
||||
|
@ -643,18 +653,38 @@ pub enum Operator<'a> {
|
|||
F64x2Div,
|
||||
F64x2Min,
|
||||
F64x2Max,
|
||||
I32x4TruncSF32x4Sat,
|
||||
I32x4TruncUF32x4Sat,
|
||||
I64x2TruncSF64x2Sat,
|
||||
I64x2TruncUF64x2Sat,
|
||||
F32x4ConvertSI32x4,
|
||||
F32x4ConvertUI32x4,
|
||||
F64x2ConvertSI64x2,
|
||||
F64x2ConvertUI64x2,
|
||||
I32x4TruncSatF32x4S,
|
||||
I32x4TruncSatF32x4U,
|
||||
I64x2TruncSatF64x2S,
|
||||
I64x2TruncSatF64x2U,
|
||||
F32x4ConvertI32x4S,
|
||||
F32x4ConvertI32x4U,
|
||||
F64x2ConvertI64x2S,
|
||||
F64x2ConvertI64x2U,
|
||||
V8x16Swizzle,
|
||||
V8x16Shuffle { lanes: [SIMDLaneIndex; 16] },
|
||||
I8x16LoadSplat { memarg: MemoryImmediate },
|
||||
I16x8LoadSplat { memarg: MemoryImmediate },
|
||||
I32x4LoadSplat { memarg: MemoryImmediate },
|
||||
I64x2LoadSplat { memarg: MemoryImmediate },
|
||||
V8x16LoadSplat { memarg: MemoryImmediate },
|
||||
V16x8LoadSplat { memarg: MemoryImmediate },
|
||||
V32x4LoadSplat { memarg: MemoryImmediate },
|
||||
V64x2LoadSplat { memarg: MemoryImmediate },
|
||||
I8x16NarrowI16x8S,
|
||||
I8x16NarrowI16x8U,
|
||||
I16x8NarrowI32x4S,
|
||||
I16x8NarrowI32x4U,
|
||||
I16x8WidenLowI8x16S,
|
||||
I16x8WidenHighI8x16S,
|
||||
I16x8WidenLowI8x16U,
|
||||
I16x8WidenHighI8x16U,
|
||||
I32x4WidenLowI16x8S,
|
||||
I32x4WidenHighI16x8S,
|
||||
I32x4WidenLowI16x8U,
|
||||
I32x4WidenHighI16x8U,
|
||||
I16x8Load8x8S { memarg: MemoryImmediate },
|
||||
I16x8Load8x8U { memarg: MemoryImmediate },
|
||||
I32x4Load16x4S { memarg: MemoryImmediate },
|
||||
I32x4Load16x4U { memarg: MemoryImmediate },
|
||||
I64x2Load32x2S { memarg: MemoryImmediate },
|
||||
I64x2Load32x2U { memarg: MemoryImmediate },
|
||||
I8x16RoundingAverageU,
|
||||
I16x8RoundingAverageU,
|
||||
}
|
||||
|
|
|
@ -17,47 +17,62 @@ use super::{
|
|||
BinaryReader, BinaryReaderError, InitExpr, Result, SectionIteratorLimited, SectionReader,
|
||||
SectionWithLimitedItems, Type,
|
||||
};
|
||||
use crate::{ExternalKind, Operator};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct Element<'a> {
|
||||
pub kind: ElementKind<'a>,
|
||||
pub items: ElementItems<'a>,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub enum ElementKind<'a> {
|
||||
Passive(Type),
|
||||
Passive,
|
||||
Active {
|
||||
table_index: u32,
|
||||
init_expr: InitExpr<'a>,
|
||||
},
|
||||
Declared,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ElementItems<'a> {
|
||||
exprs: bool,
|
||||
offset: usize,
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ElementItem {
|
||||
Null,
|
||||
Func(u32),
|
||||
}
|
||||
|
||||
impl<'a> ElementItems<'a> {
|
||||
pub fn get_items_reader<'b>(&self) -> Result<ElementItemsReader<'b>>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
ElementItemsReader::new(self.data, self.offset)
|
||||
ElementItemsReader::new(self.data, self.offset, self.exprs)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElementItemsReader<'a> {
|
||||
reader: BinaryReader<'a>,
|
||||
count: u32,
|
||||
exprs: bool,
|
||||
}
|
||||
|
||||
impl<'a> ElementItemsReader<'a> {
|
||||
pub fn new(data: &[u8], offset: usize) -> Result<ElementItemsReader> {
|
||||
pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result<ElementItemsReader> {
|
||||
let mut reader = BinaryReader::new_with_offset(data, offset);
|
||||
let count = reader.read_var_u32()?;
|
||||
Ok(ElementItemsReader { reader, count })
|
||||
Ok(ElementItemsReader {
|
||||
reader,
|
||||
count,
|
||||
exprs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn original_position(&self) -> usize {
|
||||
|
@ -68,13 +83,41 @@ impl<'a> ElementItemsReader<'a> {
|
|||
self.count
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> Result<u32> {
|
||||
self.reader.read_var_u32()
|
||||
pub fn uses_exprs(&self) -> bool {
|
||||
self.exprs
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> Result<ElementItem> {
|
||||
if self.exprs {
|
||||
let offset = self.reader.original_position();
|
||||
let ret = match self.reader.read_operator()? {
|
||||
Operator::RefNull => ElementItem::Null,
|
||||
Operator::RefFunc { function_index } => ElementItem::Func(function_index),
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid passive segment",
|
||||
offset,
|
||||
})
|
||||
}
|
||||
};
|
||||
match self.reader.read_operator()? {
|
||||
Operator::End => {}
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid passive segment",
|
||||
offset,
|
||||
})
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
} else {
|
||||
self.reader.read_var_u32().map(ElementItem::Func)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for ElementItemsReader<'a> {
|
||||
type Item = Result<u32>;
|
||||
type Item = Result<ElementItem>;
|
||||
type IntoIter = ElementItemsIterator<'a>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let count = self.count;
|
||||
|
@ -93,7 +136,7 @@ pub struct ElementItemsIterator<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for ElementItemsIterator<'a> {
|
||||
type Item = Result<u32>;
|
||||
type Item = Result<ElementItem>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.err || self.left == 0 {
|
||||
return None;
|
||||
|
@ -132,12 +175,8 @@ impl<'a> ElementSectionReader<'a> {
|
|||
/// Reads content of the element section.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
||||
/// # 0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
|
||||
/// # 0x05, 0x03, 0x01, 0x00, 0x02,
|
||||
/// # 0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00,
|
||||
/// # 0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
|
||||
/// ```no-run
|
||||
/// # let data: &[u8] = &[];
|
||||
/// use wasmparser::{ModuleReader, ElementKind};
|
||||
///use wasmparser::Result;
|
||||
/// let mut reader = ModuleReader::new(data).expect("module reader");
|
||||
|
@ -148,7 +187,6 @@ impl<'a> ElementSectionReader<'a> {
|
|||
/// let mut element_reader = section.get_element_section_reader().expect("element section reader");
|
||||
/// for _ in 0..element_reader.get_count() {
|
||||
/// let element = element_reader.read().expect("element");
|
||||
/// println!("Element: {:?}", element);
|
||||
/// if let ElementKind::Active { init_expr, .. } = element.kind {
|
||||
/// let mut init_expr_reader = init_expr.get_binary_reader();
|
||||
/// let op = init_expr_reader.read_operator().expect("op");
|
||||
|
@ -157,7 +195,7 @@ impl<'a> ElementSectionReader<'a> {
|
|||
/// let mut items_reader = element.items.get_items_reader().expect("items reader");
|
||||
/// for _ in 0..items_reader.get_count() {
|
||||
/// let item = items_reader.read().expect("item");
|
||||
/// println!(" Item: {}", item);
|
||||
/// println!(" Item: {:?}", item);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -166,19 +204,23 @@ impl<'a> ElementSectionReader<'a> {
|
|||
'a: 'b,
|
||||
{
|
||||
let flags = self.reader.read_var_u32()?;
|
||||
let kind = if flags == 1 {
|
||||
let ty = self.reader.read_type()?;
|
||||
ElementKind::Passive(ty)
|
||||
if (flags & !0b111) != 0 {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid flags byte in element segment",
|
||||
offset: self.reader.original_position() - 1,
|
||||
});
|
||||
}
|
||||
let kind = if flags & 0b001 != 0 {
|
||||
if flags & 0b010 != 0 {
|
||||
ElementKind::Declared
|
||||
} else {
|
||||
ElementKind::Passive
|
||||
}
|
||||
} else {
|
||||
let table_index = match flags {
|
||||
0 => 0,
|
||||
2 => self.reader.read_var_u32()?,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid flags byte in element segment",
|
||||
offset: self.reader.original_position() - 1,
|
||||
});
|
||||
}
|
||||
let table_index = if flags & 0b010 == 0 {
|
||||
0
|
||||
} else {
|
||||
self.reader.read_var_u32()?
|
||||
};
|
||||
let init_expr = {
|
||||
let expr_offset = self.reader.position;
|
||||
|
@ -191,17 +233,42 @@ impl<'a> ElementSectionReader<'a> {
|
|||
init_expr,
|
||||
}
|
||||
};
|
||||
let exprs = flags & 0b100 != 0;
|
||||
let ty = if flags & 0b011 != 0 {
|
||||
if exprs {
|
||||
self.reader.read_type()?
|
||||
} else {
|
||||
match self.reader.read_external_kind()? {
|
||||
ExternalKind::Function => Type::AnyFunc,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "only the function external type is supported in elem segment",
|
||||
offset: self.reader.original_position() - 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Type::AnyFunc
|
||||
};
|
||||
let data_start = self.reader.position;
|
||||
let items_count = self.reader.read_var_u32()?;
|
||||
for _ in 0..items_count {
|
||||
self.reader.skip_var_32()?;
|
||||
if exprs {
|
||||
for _ in 0..items_count {
|
||||
self.reader.skip_init_expr()?;
|
||||
}
|
||||
} else {
|
||||
for _ in 0..items_count {
|
||||
self.reader.skip_var_32()?;
|
||||
}
|
||||
}
|
||||
let data_end = self.reader.position;
|
||||
let items = ElementItems {
|
||||
offset: self.reader.original_offset + data_start,
|
||||
data: &self.reader.buffer[data_start..data_end],
|
||||
exprs,
|
||||
};
|
||||
Ok(Element { kind, items })
|
||||
Ok(Element { kind, items, ty })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ pub use self::data_section::Data;
|
|||
pub use self::data_section::DataKind;
|
||||
pub use self::data_section::DataSectionReader;
|
||||
pub use self::element_section::Element;
|
||||
pub use self::element_section::ElementItem;
|
||||
pub use self::element_section::ElementItems;
|
||||
pub use self::element_section::ElementItemsReader;
|
||||
pub use self::element_section::ElementKind;
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::iter::{IntoIterator, Iterator};
|
||||
|
||||
use super::{
|
||||
BinaryReader, BinaryReaderError, CustomSectionKind, Range, Result, SectionCode, SectionHeader,
|
||||
};
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
|
||||
use super::{BinaryReader, BinaryReaderError, Operator, Result};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OperatorsReader<'a> {
|
||||
reader: BinaryReader<'a>,
|
||||
pub(crate) reader: BinaryReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> OperatorsReader<'a> {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
mod simple_tests {
|
||||
use crate::operators_validator::OperatorValidatorConfig;
|
||||
|
@ -316,7 +315,6 @@ mod simple_tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
mod wast_tests {
|
||||
use crate::operators_validator::OperatorValidatorConfig;
|
||||
|
@ -324,8 +322,7 @@ mod wast_tests {
|
|||
use crate::validator::{ValidatingParser, ValidatingParserConfig};
|
||||
use crate::BinaryReaderError;
|
||||
use std::fs::{read, read_dir};
|
||||
use wabt::script::{Command, CommandKind, ModuleBinary, ScriptParser};
|
||||
use wabt::Features;
|
||||
use std::str;
|
||||
|
||||
const SPEC_TESTS_PATH: &str = "testsuite";
|
||||
|
||||
|
@ -345,10 +342,10 @@ mod wast_tests {
|
|||
}
|
||||
|
||||
fn validate_module(
|
||||
module: ModuleBinary,
|
||||
mut module: wast::Module,
|
||||
config: ValidatingParserConfig,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
let data = &module.into_vec();
|
||||
let data = module.encode().unwrap();
|
||||
let mut parser = ValidatingParser::new(data.as_slice(), Some(config));
|
||||
let mut max_iteration = 100000000;
|
||||
loop {
|
||||
|
@ -366,20 +363,6 @@ mod wast_tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn to_features(config: &ValidatingParserConfig) -> Features {
|
||||
let mut features = Features::new();
|
||||
if config.operator_config.enable_simd {
|
||||
features.enable_simd();
|
||||
}
|
||||
if config.operator_config.enable_multi_value {
|
||||
features.enable_multi_value();
|
||||
}
|
||||
if config.operator_config.enable_reference_types {
|
||||
features.enable_reference_types();
|
||||
}
|
||||
features
|
||||
}
|
||||
|
||||
fn run_wabt_scripts<F>(
|
||||
filename: &str,
|
||||
wast: &[u8],
|
||||
|
@ -395,27 +378,39 @@ mod wast_tests {
|
|||
return;
|
||||
}
|
||||
|
||||
let features = to_features(&config);
|
||||
let mut parser: ScriptParser<f32, f64> =
|
||||
ScriptParser::from_source_and_name_with_features(wast, filename, features)
|
||||
.expect("script parser");
|
||||
let contents = str::from_utf8(wast).unwrap();
|
||||
let buf = wast::parser::ParseBuffer::new(&contents)
|
||||
.map_err(|mut e| {
|
||||
e.set_path(filename.as_ref());
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
let wast = wast::parser::parse::<wast::Wast>(&buf)
|
||||
.map_err(|mut e| {
|
||||
e.set_path(filename.as_ref());
|
||||
e
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
while let Some(Command { kind, line }) = parser.next().expect("parser") {
|
||||
if skip_test(filename, line) {
|
||||
for directive in wast.directives {
|
||||
use wast::WastDirective::*;
|
||||
let (line, _col) = directive.span().linecol_in(&contents);
|
||||
let line = line + 1;
|
||||
if skip_test(filename, line as u64) {
|
||||
println!("{}:{}: skipping", filename, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
match kind {
|
||||
CommandKind::Module { module, .. }
|
||||
| CommandKind::AssertUninstantiable { module, .. }
|
||||
| CommandKind::AssertUnlinkable { module, .. } => {
|
||||
match directive {
|
||||
Module(module) | AssertUnlinkable { module, .. } => {
|
||||
if let Err(err) = validate_module(module, config.clone()) {
|
||||
panic!("{}:{}: invalid module: {}", filename, line, err.message);
|
||||
}
|
||||
}
|
||||
CommandKind::AssertInvalid { module, .. }
|
||||
| CommandKind::AssertMalformed { module, .. } => {
|
||||
AssertInvalid { module, .. }
|
||||
| AssertMalformed {
|
||||
module: wast::QuoteModule::Module(module),
|
||||
..
|
||||
} => {
|
||||
// TODO diffentiate between assert_invalid and assert_malformed
|
||||
if let Ok(_) = validate_module(module, config.clone()) {
|
||||
panic!(
|
||||
|
@ -425,13 +420,23 @@ mod wast_tests {
|
|||
}
|
||||
// TODO: Check the assert_invalid or assert_malformed message
|
||||
}
|
||||
CommandKind::Register { .. }
|
||||
| CommandKind::PerformAction(_)
|
||||
| CommandKind::AssertReturn { .. }
|
||||
| CommandKind::AssertTrap { .. }
|
||||
| CommandKind::AssertExhaustion { .. }
|
||||
| CommandKind::AssertReturnCanonicalNan { .. }
|
||||
| CommandKind::AssertReturnArithmeticNan { .. } => (),
|
||||
|
||||
AssertMalformed {
|
||||
module: wast::QuoteModule::Quote(_),
|
||||
..
|
||||
}
|
||||
| Register { .. }
|
||||
| Invoke { .. }
|
||||
| AssertTrap { .. }
|
||||
| AssertReturn { .. }
|
||||
| AssertReturnCanonicalNan { .. }
|
||||
| AssertReturnArithmeticNan { .. }
|
||||
| AssertReturnCanonicalNanF32x4 { .. }
|
||||
| AssertReturnCanonicalNanF64x2 { .. }
|
||||
| AssertReturnArithmeticNanF32x4 { .. }
|
||||
| AssertReturnArithmeticNanF64x2 { .. }
|
||||
| AssertReturnFunc { .. }
|
||||
| AssertExhaustion { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,12 +474,16 @@ mod wast_tests {
|
|||
config
|
||||
},
|
||||
|name, line| match (name, line) {
|
||||
("simd_address.wast", _)
|
||||
| ("simd_const.wast", _)
|
||||
| ("simd_f32x4_cmp.wast", _)
|
||||
| ("simd_store.wast", _)
|
||||
| ("simd_lane.wast", _)
|
||||
| ("simd_load.wast", _) => true,
|
||||
// FIXME(WebAssembly/simd#140) needs a few updates to the
|
||||
// `*.wast` file to successfully parse it (or so I think)
|
||||
("simd_lane.wast", _) => true,
|
||||
("simd_load_extend.wast", _) => true,
|
||||
("simd_f32x4_arith.wast", _) => true,
|
||||
("simd_f64x2_arith.wast", _) => true,
|
||||
("simd_f32x4.wast", _) => true,
|
||||
("simd_f64x2.wast", _) => true,
|
||||
("simd_const.wast", _) => true,
|
||||
("simd_load_splat.wast", _) => true,
|
||||
_ => false,
|
||||
},
|
||||
);
|
||||
|
@ -494,23 +503,14 @@ mod wast_tests {
|
|||
{
|
||||
let mut config: ValidatingParserConfig = default_config();
|
||||
config.operator_config.enable_reference_types = true;
|
||||
config.operator_config.enable_bulk_memory = true;
|
||||
config
|
||||
},
|
||||
|name, line| match (name, line) {
|
||||
("ref_null.wast", _)
|
||||
| ("ref_is_null.wast", _)
|
||||
| ("ref_func.wast", _)
|
||||
| ("linking.wast", _)
|
||||
| ("globals.wast", _)
|
||||
| ("imports.wast", _)
|
||||
| ("br_table.wast", _)
|
||||
("br_table.wast", _)
|
||||
| ("select.wast", _)
|
||||
| ("table_get.wast", _)
|
||||
| ("table_set.wast", _)
|
||||
| ("table_size.wast", _)
|
||||
| ("table_fill.wast", _)
|
||||
| ("table_grow.wast", _)
|
||||
| ("exports.wast", _) => true,
|
||||
| ("binary.wast", _)
|
||||
| ("linking.wast", 280) => true,
|
||||
_ => false,
|
||||
},
|
||||
);
|
||||
|
|
|
@ -13,11 +13,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use super::HashSet;
|
||||
use core::result;
|
||||
use std::collections::HashSet;
|
||||
use std::result;
|
||||
use std::str;
|
||||
use std::string::String;
|
||||
use std::vec::Vec;
|
||||
|
||||
use crate::limits::{
|
||||
MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_GLOBALS, MAX_WASM_MEMORIES,
|
||||
|
@ -37,6 +35,7 @@ use crate::operators_validator::{
|
|||
is_subtype_supertype, FunctionEnd, OperatorValidator, OperatorValidatorConfig,
|
||||
WasmModuleResources, DEFAULT_OPERATOR_VALIDATOR_CONFIG,
|
||||
};
|
||||
use crate::{ElemSectionEntryTable, ElementItem};
|
||||
|
||||
use crate::readers::FunctionBody;
|
||||
|
||||
|
@ -45,6 +44,7 @@ type ValidatorResult<'a, T> = result::Result<T, ParserState<'a>>;
|
|||
struct InitExpressionState {
|
||||
ty: Type,
|
||||
global_count: usize,
|
||||
function_count: usize,
|
||||
validated: bool,
|
||||
}
|
||||
|
||||
|
@ -179,8 +179,8 @@ impl<'a> ValidatingParser<'a> {
|
|||
&self.resources
|
||||
}
|
||||
|
||||
fn create_validation_error(&self, message: &'static str) -> Option<ParserState<'a>> {
|
||||
Some(ParserState::Error(BinaryReaderError {
|
||||
fn set_validation_error(&mut self, message: &'static str) {
|
||||
self.validation_error = Some(ParserState::Error(BinaryReaderError {
|
||||
message,
|
||||
offset: self.read_position.unwrap(),
|
||||
}))
|
||||
|
@ -196,7 +196,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
|
||||
match ty {
|
||||
Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
|
||||
Type::Null | Type::AnyFunc | Type::AnyRef => {
|
||||
Type::NullRef | Type::AnyFunc | Type::AnyRef => {
|
||||
if !self.config.operator_config.enable_reference_types {
|
||||
return self.create_error("reference types support is not enabled");
|
||||
}
|
||||
|
@ -241,11 +241,15 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
|
||||
fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> {
|
||||
if let Type::AnyFunc = table_type.element_type {
|
||||
self.check_limits(&table_type.limits)
|
||||
} else {
|
||||
self.create_error("element is not anyfunc")
|
||||
match table_type.element_type {
|
||||
Type::AnyFunc => {}
|
||||
_ => {
|
||||
if !self.config.operator_config.enable_reference_types {
|
||||
return self.create_error("element is not anyfunc");
|
||||
}
|
||||
}
|
||||
}
|
||||
self.check_limits(&table_type.limits)
|
||||
}
|
||||
|
||||
fn check_memory_type(&self, memory_type: &MemoryType) -> ValidatorResult<'a, ()> {
|
||||
|
@ -277,7 +281,9 @@ impl<'a> ValidatingParser<'a> {
|
|||
Ok(())
|
||||
}
|
||||
ImportSectionEntryType::Table(ref table_type) => {
|
||||
if self.resources.tables.len() >= MAX_WASM_TABLES {
|
||||
if !self.config.operator_config.enable_reference_types
|
||||
&& self.resources.tables.len() >= MAX_WASM_TABLES
|
||||
{
|
||||
return self.create_error("tables count must be at most 1");
|
||||
}
|
||||
self.check_table_type(table_type)
|
||||
|
@ -311,7 +317,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
if !self.config.operator_config.enable_reference_types {
|
||||
return self.create_error("reference types support is not enabled");
|
||||
}
|
||||
Type::Null
|
||||
Type::NullRef
|
||||
}
|
||||
Operator::V128Const { .. } => {
|
||||
if !self.config.operator_config.enable_simd {
|
||||
|
@ -319,12 +325,18 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
Type::V128
|
||||
}
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Operator::GlobalGet { global_index } => {
|
||||
if global_index as usize >= state.global_count {
|
||||
return self.create_error("init_expr global index out of bounds");
|
||||
}
|
||||
self.resources.globals[global_index as usize].content_type
|
||||
}
|
||||
Operator::RefFunc { function_index } => {
|
||||
if function_index as usize >= state.function_count {
|
||||
return self.create_error("init_expr function index out of bounds");
|
||||
}
|
||||
Type::AnyFunc
|
||||
}
|
||||
_ => return self.create_error("invalid init_expr operator"),
|
||||
};
|
||||
if !is_subtype_supertype(ty, state.ty) {
|
||||
|
@ -382,13 +394,10 @@ impl<'a> ValidatingParser<'a> {
|
|||
fn process_begin_section(&self, code: &SectionCode) -> ValidatorResult<'a, SectionOrderState> {
|
||||
let order_state = SectionOrderState::from_section_code(code);
|
||||
Ok(match self.section_order_state {
|
||||
SectionOrderState::Initial => {
|
||||
if order_state.is_none() {
|
||||
SectionOrderState::Initial
|
||||
} else {
|
||||
order_state.unwrap()
|
||||
}
|
||||
}
|
||||
SectionOrderState::Initial => match order_state {
|
||||
Some(section) => section,
|
||||
_ => SectionOrderState::Initial,
|
||||
},
|
||||
previous => {
|
||||
if let Some(order_state_unwraped) = order_state {
|
||||
if previous >= order_state_unwraped {
|
||||
|
@ -406,7 +415,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
match *self.parser.last_state() {
|
||||
ParserState::BeginWasm { version } => {
|
||||
if version != 1 {
|
||||
self.validation_error = self.create_validation_error("bad wasm file version");
|
||||
self.set_validation_error("bad wasm file version");
|
||||
}
|
||||
}
|
||||
ParserState::BeginSection { ref code, .. } => {
|
||||
|
@ -422,8 +431,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
if check.is_err() {
|
||||
self.validation_error = check.err();
|
||||
} else if self.resources.types.len() > MAX_WASM_TYPES {
|
||||
self.validation_error =
|
||||
self.create_validation_error("types count is out of bounds");
|
||||
self.set_validation_error("types count is out of bounds");
|
||||
} else {
|
||||
self.resources.types.push(func_type.clone());
|
||||
}
|
||||
|
@ -452,19 +460,18 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::FunctionSectionEntry(type_index) => {
|
||||
if type_index as usize >= self.resources.types.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("func type index out of bounds");
|
||||
self.set_validation_error("func type index out of bounds");
|
||||
} else if self.resources.func_type_indices.len() >= MAX_WASM_FUNCTIONS {
|
||||
self.validation_error =
|
||||
self.create_validation_error("functions count out of bounds");
|
||||
self.set_validation_error("functions count out of bounds");
|
||||
} else {
|
||||
self.resources.func_type_indices.push(type_index);
|
||||
}
|
||||
}
|
||||
ParserState::TableSectionEntry(ref table_type) => {
|
||||
if self.resources.tables.len() >= MAX_WASM_TABLES {
|
||||
self.validation_error =
|
||||
self.create_validation_error("tables count must be at most 1");
|
||||
if !self.config.operator_config.enable_reference_types
|
||||
&& self.resources.tables.len() >= MAX_WASM_TABLES
|
||||
{
|
||||
self.set_validation_error("tables count must be at most 1");
|
||||
} else {
|
||||
self.validation_error = self.check_table_type(table_type).err();
|
||||
self.resources.tables.push(table_type.clone());
|
||||
|
@ -472,8 +479,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::MemorySectionEntry(ref memory_type) => {
|
||||
if self.resources.memories.len() >= MAX_WASM_MEMORIES {
|
||||
self.validation_error =
|
||||
self.create_validation_error("memories count must be at most 1");
|
||||
self.set_validation_error("memories count must be at most 1");
|
||||
} else {
|
||||
self.validation_error = self.check_memory_type(memory_type).err();
|
||||
self.resources.memories.push(memory_type.clone());
|
||||
|
@ -481,13 +487,13 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::BeginGlobalSectionEntry(global_type) => {
|
||||
if self.resources.globals.len() >= MAX_WASM_GLOBALS {
|
||||
self.validation_error =
|
||||
self.create_validation_error("globals count out of bounds");
|
||||
self.set_validation_error("globals count out of bounds");
|
||||
} else {
|
||||
self.validation_error = self.check_global_type(global_type).err();
|
||||
self.init_expression_state = Some(InitExpressionState {
|
||||
ty: global_type.content_type,
|
||||
global_count: self.resources.globals.len(),
|
||||
function_count: self.resources.func_type_indices.len(),
|
||||
validated: false,
|
||||
});
|
||||
self.resources.globals.push(global_type);
|
||||
|
@ -502,7 +508,7 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::EndInitExpressionBody => {
|
||||
if !self.init_expression_state.as_ref().unwrap().validated {
|
||||
self.validation_error = self.create_validation_error("init_expr is empty");
|
||||
self.set_validation_error("init_expr is empty");
|
||||
}
|
||||
self.init_expression_state = None;
|
||||
}
|
||||
|
@ -516,39 +522,50 @@ impl<'a> ValidatingParser<'a> {
|
|||
ParserState::DataCountSectionEntry(count) => {
|
||||
self.resources.data_count = Some(count);
|
||||
}
|
||||
ParserState::BeginPassiveElementSectionEntry(_ty) => {
|
||||
ParserState::BeginElementSectionEntry { table, ty } => {
|
||||
self.resources.element_count += 1;
|
||||
}
|
||||
ParserState::BeginActiveElementSectionEntry(table_index) => {
|
||||
self.resources.element_count += 1;
|
||||
if table_index as usize >= self.resources.tables.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("element section table index out of bounds");
|
||||
} else {
|
||||
assert!(
|
||||
self.resources.tables[table_index as usize].element_type == Type::AnyFunc
|
||||
);
|
||||
if let ElemSectionEntryTable::Active(table_index) = table {
|
||||
let table = match self.resources.tables.get(table_index as usize) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
self.set_validation_error("element section table index out of bounds");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !is_subtype_supertype(ty, table.element_type) {
|
||||
self.set_validation_error("element_type != table type");
|
||||
return;
|
||||
}
|
||||
if !self.config.operator_config.enable_reference_types {
|
||||
if ty != Type::AnyFunc {
|
||||
self.set_validation_error(
|
||||
"element_type != anyfunc is not supported yet",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.init_expression_state = Some(InitExpressionState {
|
||||
ty: Type::I32,
|
||||
global_count: self.resources.globals.len(),
|
||||
function_count: self.resources.func_type_indices.len(),
|
||||
validated: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
ParserState::ElementSectionEntryBody(ref indices) => {
|
||||
for func_index in &**indices {
|
||||
if *func_index as usize >= self.resources.func_type_indices.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("element func index out of bounds");
|
||||
break;
|
||||
for item in &**indices {
|
||||
if let ElementItem::Func(func_index) = item {
|
||||
if *func_index as usize >= self.resources.func_type_indices.len() {
|
||||
self.set_validation_error("element func index out of bounds");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ParserState::BeginFunctionBody { .. } => {
|
||||
let index = (self.current_func_index + self.func_imports_count) as usize;
|
||||
if index as usize >= self.resources.func_type_indices.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("func type is not defined");
|
||||
self.set_validation_error("func type is not defined");
|
||||
}
|
||||
}
|
||||
ParserState::FunctionBodyLocals { ref locals } => {
|
||||
|
@ -565,11 +582,9 @@ impl<'a> ValidatingParser<'a> {
|
|||
.as_mut()
|
||||
.unwrap()
|
||||
.process_operator(operator, &self.resources);
|
||||
match check {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
self.validation_error = self.create_validation_error(err);
|
||||
}
|
||||
|
||||
if let Err(err) = check {
|
||||
self.set_validation_error(err);
|
||||
}
|
||||
}
|
||||
ParserState::EndFunctionBody => {
|
||||
|
@ -578,8 +593,8 @@ impl<'a> ValidatingParser<'a> {
|
|||
.as_ref()
|
||||
.unwrap()
|
||||
.process_end_function();
|
||||
if check.is_err() {
|
||||
self.validation_error = self.create_validation_error(check.err().unwrap());
|
||||
if let Err(err) = check {
|
||||
self.set_validation_error(err);
|
||||
}
|
||||
self.current_func_index += 1;
|
||||
self.current_operator_validator = None;
|
||||
|
@ -589,12 +604,12 @@ impl<'a> ValidatingParser<'a> {
|
|||
}
|
||||
ParserState::BeginActiveDataSectionEntry(memory_index) => {
|
||||
if memory_index as usize >= self.resources.memories.len() {
|
||||
self.validation_error =
|
||||
self.create_validation_error("data section memory index out of bounds");
|
||||
self.set_validation_error("data section memory index out of bounds");
|
||||
} else {
|
||||
self.init_expression_state = Some(InitExpressionState {
|
||||
ty: Type::I32,
|
||||
global_count: self.resources.globals.len(),
|
||||
function_count: self.resources.func_type_indices.len(),
|
||||
validated: false,
|
||||
});
|
||||
}
|
||||
|
@ -603,15 +618,13 @@ impl<'a> ValidatingParser<'a> {
|
|||
if self.resources.func_type_indices.len()
|
||||
!= self.current_func_index as usize + self.func_imports_count as usize
|
||||
{
|
||||
self.validation_error = self.create_validation_error(
|
||||
self.set_validation_error(
|
||||
"function and code section have inconsistent lengths",
|
||||
);
|
||||
}
|
||||
if let Some(data_count) = self.resources.data_count {
|
||||
if data_count != self.data_found {
|
||||
self.validation_error = self.create_validation_error(
|
||||
"data count section and passive data mismatch",
|
||||
);
|
||||
self.set_validation_error("data count section and passive data mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -803,10 +816,10 @@ pub fn validate_function_body(
|
|||
let mut locals_reader = function_body.get_locals_reader()?;
|
||||
let local_count = locals_reader.get_count() as usize;
|
||||
if local_count > MAX_WASM_FUNCTION_LOCALS {
|
||||
Err(BinaryReaderError {
|
||||
return Err(BinaryReaderError {
|
||||
message: "locals exceed maximum",
|
||||
offset: locals_reader.original_position(),
|
||||
})?;
|
||||
});
|
||||
}
|
||||
let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
|
||||
let mut locals_total: usize = 0;
|
||||
|
@ -820,10 +833,10 @@ pub fn validate_function_body(
|
|||
offset: locals_reader.original_position(),
|
||||
})?;
|
||||
if locals_total > MAX_WASM_FUNCTION_LOCALS {
|
||||
Err(BinaryReaderError {
|
||||
return Err(BinaryReaderError {
|
||||
message: "locals exceed maximum",
|
||||
offset: locals_reader.original_position(),
|
||||
})?;
|
||||
});
|
||||
}
|
||||
locals.push((count, ty));
|
||||
}
|
||||
|
@ -848,10 +861,10 @@ pub fn validate_function_body(
|
|||
}
|
||||
}
|
||||
if !eof_found {
|
||||
Err(BinaryReaderError {
|
||||
return Err(BinaryReaderError {
|
||||
message: "end of function not found",
|
||||
offset: last_op,
|
||||
})?;
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -867,7 +880,7 @@ pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<
|
|||
let state = parser.read_with_input(next_input);
|
||||
match *state {
|
||||
ParserState::EndWasm => break,
|
||||
ParserState::Error(e) => Err(e)?,
|
||||
ParserState::Error(e) => return Err(e),
|
||||
ParserState::BeginFunctionBody { range } => {
|
||||
parser_input = Some(ParserInput::SkipFunctionBody);
|
||||
func_ranges.push(range);
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# This is the test script for testing the no_std configuration of
|
||||
# packages which support it.
|
||||
|
||||
# Repository top-level directory.
|
||||
topdir=$(dirname "$0")
|
||||
cd "$topdir"
|
||||
|
||||
function banner {
|
||||
echo "====== $* ======"
|
||||
}
|
||||
|
||||
banner "Rust unit tests"
|
||||
|
||||
# Test with just "core" enabled.
|
||||
cargo +nightly test --no-default-features --features core
|
||||
|
||||
# Test with "core" and "std" enabled at the same time.
|
||||
cargo +nightly test --features core
|
||||
|
||||
banner "OK"
|
Загрузка…
Ссылка в новой задаче