Bug 1469027: Vendor in Rust dependencies for Cranelift; r=froydnj
authorBenjamin Bouvier <benj@benj.me>
Wed, 12 Sep 2018 16:04:35 +0200
changeset 497122 8a644dda1dc3fef959d320ec4a737ba21a38dccb
parent 497121 7864f125bbcd940ab543fc383f2f00cbeeae3244
child 497123 66a1434be89e0345e70f585fd2a960dae41324ce
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1469027
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1469027: Vendor in Rust dependencies for Cranelift; r=froydnj
Cargo.lock
third_party/rust/cranelift-bforest/.cargo-checksum.json
third_party/rust/cranelift-bforest/Cargo.toml
third_party/rust/cranelift-bforest/LICENSE
third_party/rust/cranelift-bforest/README.md
third_party/rust/cranelift-bforest/src/lib.rs
third_party/rust/cranelift-bforest/src/map.rs
third_party/rust/cranelift-bforest/src/node.rs
third_party/rust/cranelift-bforest/src/path.rs
third_party/rust/cranelift-bforest/src/pool.rs
third_party/rust/cranelift-bforest/src/set.rs
third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
third_party/rust/cranelift-codegen-meta/Cargo.toml
third_party/rust/cranelift-codegen-meta/LICENSE
third_party/rust/cranelift-codegen-meta/README.md
third_party/rust/cranelift-codegen-meta/src/base/mod.rs
third_party/rust/cranelift-codegen-meta/src/base/types.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs
third_party/rust/cranelift-codegen-meta/src/error.rs
third_party/rust/cranelift-codegen-meta/src/gen_types.rs
third_party/rust/cranelift-codegen-meta/src/lib.rs
third_party/rust/cranelift-codegen-meta/src/srcgen.rs
third_party/rust/cranelift-codegen/.cargo-checksum.json
third_party/rust/cranelift-codegen/Cargo.toml
third_party/rust/cranelift-codegen/LICENSE
third_party/rust/cranelift-codegen/README.md
third_party/rust/cranelift-codegen/build.rs
third_party/rust/cranelift-codegen/meta-python/base/__init__.py
third_party/rust/cranelift-codegen/meta-python/base/entities.py
third_party/rust/cranelift-codegen/meta-python/base/formats.py
third_party/rust/cranelift-codegen/meta-python/base/immediates.py
third_party/rust/cranelift-codegen/meta-python/base/instructions.py
third_party/rust/cranelift-codegen/meta-python/base/legalize.py
third_party/rust/cranelift-codegen/meta-python/base/predicates.py
third_party/rust/cranelift-codegen/meta-python/base/semantics.py
third_party/rust/cranelift-codegen/meta-python/base/settings.py
third_party/rust/cranelift-codegen/meta-python/base/types.py
third_party/rust/cranelift-codegen/meta-python/build.py
third_party/rust/cranelift-codegen/meta-python/cdsl/__init__.py
third_party/rust/cranelift-codegen/meta-python/cdsl/ast.py
third_party/rust/cranelift-codegen/meta-python/cdsl/formats.py
third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py
third_party/rust/cranelift-codegen/meta-python/cdsl/isa.py
third_party/rust/cranelift-codegen/meta-python/cdsl/operands.py
third_party/rust/cranelift-codegen/meta-python/cdsl/predicates.py
third_party/rust/cranelift-codegen/meta-python/cdsl/registers.py
third_party/rust/cranelift-codegen/meta-python/cdsl/settings.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_ast.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_package.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_ti.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_typevar.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_xform.py
third_party/rust/cranelift-codegen/meta-python/cdsl/ti.py
third_party/rust/cranelift-codegen/meta-python/cdsl/types.py
third_party/rust/cranelift-codegen/meta-python/cdsl/typevar.py
third_party/rust/cranelift-codegen/meta-python/cdsl/xform.py
third_party/rust/cranelift-codegen/meta-python/check.sh
third_party/rust/cranelift-codegen/meta-python/constant_hash.py
third_party/rust/cranelift-codegen/meta-python/gen_binemit.py
third_party/rust/cranelift-codegen/meta-python/gen_build_deps.py
third_party/rust/cranelift-codegen/meta-python/gen_encoding.py
third_party/rust/cranelift-codegen/meta-python/gen_instr.py
third_party/rust/cranelift-codegen/meta-python/gen_legalizer.py
third_party/rust/cranelift-codegen/meta-python/gen_registers.py
third_party/rust/cranelift-codegen/meta-python/gen_settings.py
third_party/rust/cranelift-codegen/meta-python/gen_types.py
third_party/rust/cranelift-codegen/meta-python/isa/__init__.py
third_party/rust/cranelift-codegen/meta-python/isa/arm32/__init__.py
third_party/rust/cranelift-codegen/meta-python/isa/arm32/defs.py
third_party/rust/cranelift-codegen/meta-python/isa/arm32/registers.py
third_party/rust/cranelift-codegen/meta-python/isa/arm32/settings.py
third_party/rust/cranelift-codegen/meta-python/isa/arm64/__init__.py
third_party/rust/cranelift-codegen/meta-python/isa/arm64/defs.py
third_party/rust/cranelift-codegen/meta-python/isa/arm64/registers.py
third_party/rust/cranelift-codegen/meta-python/isa/arm64/settings.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/__init__.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/defs.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/encodings.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/registers.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/settings.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/__init__.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/defs.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/instructions.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/legalize.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/recipes.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/registers.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/settings.py
third_party/rust/cranelift-codegen/meta-python/mypy.ini
third_party/rust/cranelift-codegen/meta-python/semantics/__init__.py
third_party/rust/cranelift-codegen/meta-python/semantics/elaborate.py
third_party/rust/cranelift-codegen/meta-python/semantics/macros.py
third_party/rust/cranelift-codegen/meta-python/semantics/primitives.py
third_party/rust/cranelift-codegen/meta-python/semantics/smtlib.py
third_party/rust/cranelift-codegen/meta-python/semantics/test_elaborate.py
third_party/rust/cranelift-codegen/meta-python/srcgen.py
third_party/rust/cranelift-codegen/meta-python/stubs/z3/__init__.pyi
third_party/rust/cranelift-codegen/meta-python/stubs/z3/z3core.pyi
third_party/rust/cranelift-codegen/meta-python/stubs/z3/z3types.pyi
third_party/rust/cranelift-codegen/meta-python/test_constant_hash.py
third_party/rust/cranelift-codegen/meta-python/test_gen_legalizer.py
third_party/rust/cranelift-codegen/meta-python/test_srcgen.py
third_party/rust/cranelift-codegen/meta-python/unique_table.py
third_party/rust/cranelift-codegen/src/abi.rs
third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
third_party/rust/cranelift-codegen/src/binemit/mod.rs
third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
third_party/rust/cranelift-codegen/src/binemit/shrink.rs
third_party/rust/cranelift-codegen/src/bitset.rs
third_party/rust/cranelift-codegen/src/cfg_printer.rs
third_party/rust/cranelift-codegen/src/constant_hash.rs
third_party/rust/cranelift-codegen/src/context.rs
third_party/rust/cranelift-codegen/src/cursor.rs
third_party/rust/cranelift-codegen/src/dbg.rs
third_party/rust/cranelift-codegen/src/dce.rs
third_party/rust/cranelift-codegen/src/divconst_magic_numbers.rs
third_party/rust/cranelift-codegen/src/dominator_tree.rs
third_party/rust/cranelift-codegen/src/flowgraph.rs
third_party/rust/cranelift-codegen/src/fx.rs
third_party/rust/cranelift-codegen/src/ir/builder.rs
third_party/rust/cranelift-codegen/src/ir/condcodes.rs
third_party/rust/cranelift-codegen/src/ir/dfg.rs
third_party/rust/cranelift-codegen/src/ir/entities.rs
third_party/rust/cranelift-codegen/src/ir/extfunc.rs
third_party/rust/cranelift-codegen/src/ir/extname.rs
third_party/rust/cranelift-codegen/src/ir/function.rs
third_party/rust/cranelift-codegen/src/ir/globalvalue.rs
third_party/rust/cranelift-codegen/src/ir/heap.rs
third_party/rust/cranelift-codegen/src/ir/immediates.rs
third_party/rust/cranelift-codegen/src/ir/instructions.rs
third_party/rust/cranelift-codegen/src/ir/jumptable.rs
third_party/rust/cranelift-codegen/src/ir/layout.rs
third_party/rust/cranelift-codegen/src/ir/libcall.rs
third_party/rust/cranelift-codegen/src/ir/memflags.rs
third_party/rust/cranelift-codegen/src/ir/mod.rs
third_party/rust/cranelift-codegen/src/ir/progpoint.rs
third_party/rust/cranelift-codegen/src/ir/sourceloc.rs
third_party/rust/cranelift-codegen/src/ir/stackslot.rs
third_party/rust/cranelift-codegen/src/ir/table.rs
third_party/rust/cranelift-codegen/src/ir/trapcode.rs
third_party/rust/cranelift-codegen/src/ir/types.rs
third_party/rust/cranelift-codegen/src/ir/valueloc.rs
third_party/rust/cranelift-codegen/src/isa/arm32/abi.rs
third_party/rust/cranelift-codegen/src/isa/arm32/binemit.rs
third_party/rust/cranelift-codegen/src/isa/arm32/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
third_party/rust/cranelift-codegen/src/isa/arm32/registers.rs
third_party/rust/cranelift-codegen/src/isa/arm32/settings.rs
third_party/rust/cranelift-codegen/src/isa/arm64/abi.rs
third_party/rust/cranelift-codegen/src/isa/arm64/binemit.rs
third_party/rust/cranelift-codegen/src/isa/arm64/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
third_party/rust/cranelift-codegen/src/isa/arm64/registers.rs
third_party/rust/cranelift-codegen/src/isa/arm64/settings.rs
third_party/rust/cranelift-codegen/src/isa/constraints.rs
third_party/rust/cranelift-codegen/src/isa/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/encoding.rs
third_party/rust/cranelift-codegen/src/isa/mod.rs
third_party/rust/cranelift-codegen/src/isa/registers.rs
third_party/rust/cranelift-codegen/src/isa/riscv/abi.rs
third_party/rust/cranelift-codegen/src/isa/riscv/binemit.rs
third_party/rust/cranelift-codegen/src/isa/riscv/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
third_party/rust/cranelift-codegen/src/isa/riscv/registers.rs
third_party/rust/cranelift-codegen/src/isa/riscv/settings.rs
third_party/rust/cranelift-codegen/src/isa/stack.rs
third_party/rust/cranelift-codegen/src/isa/x86/abi.rs
third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
third_party/rust/cranelift-codegen/src/isa/x86/registers.rs
third_party/rust/cranelift-codegen/src/isa/x86/settings.rs
third_party/rust/cranelift-codegen/src/iterators.rs
third_party/rust/cranelift-codegen/src/legalizer/boundary.rs
third_party/rust/cranelift-codegen/src/legalizer/call.rs
third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
third_party/rust/cranelift-codegen/src/legalizer/heap.rs
third_party/rust/cranelift-codegen/src/legalizer/libcall.rs
third_party/rust/cranelift-codegen/src/legalizer/mod.rs
third_party/rust/cranelift-codegen/src/legalizer/split.rs
third_party/rust/cranelift-codegen/src/legalizer/table.rs
third_party/rust/cranelift-codegen/src/lib.rs
third_party/rust/cranelift-codegen/src/licm.rs
third_party/rust/cranelift-codegen/src/loop_analysis.rs
third_party/rust/cranelift-codegen/src/nan_canonicalization.rs
third_party/rust/cranelift-codegen/src/partition_slice.rs
third_party/rust/cranelift-codegen/src/postopt.rs
third_party/rust/cranelift-codegen/src/predicates.rs
third_party/rust/cranelift-codegen/src/preopt.rs
third_party/rust/cranelift-codegen/src/print_errors.rs
third_party/rust/cranelift-codegen/src/ref_slice.rs
third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
third_party/rust/cranelift-codegen/src/regalloc/context.rs
third_party/rust/cranelift-codegen/src/regalloc/diversion.rs
third_party/rust/cranelift-codegen/src/regalloc/live_value_tracker.rs
third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
third_party/rust/cranelift-codegen/src/regalloc/liverange.rs
third_party/rust/cranelift-codegen/src/regalloc/mod.rs
third_party/rust/cranelift-codegen/src/regalloc/pressure.rs
third_party/rust/cranelift-codegen/src/regalloc/register_set.rs
third_party/rust/cranelift-codegen/src/regalloc/reload.rs
third_party/rust/cranelift-codegen/src/regalloc/solver.rs
third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs
third_party/rust/cranelift-codegen/src/result.rs
third_party/rust/cranelift-codegen/src/scoped_hash_map.rs
third_party/rust/cranelift-codegen/src/settings.rs
third_party/rust/cranelift-codegen/src/simple_gvn.rs
third_party/rust/cranelift-codegen/src/stack_layout.rs
third_party/rust/cranelift-codegen/src/timing.rs
third_party/rust/cranelift-codegen/src/topo_order.rs
third_party/rust/cranelift-codegen/src/unreachable_code.rs
third_party/rust/cranelift-codegen/src/verifier/cssa.rs
third_party/rust/cranelift-codegen/src/verifier/flags.rs
third_party/rust/cranelift-codegen/src/verifier/liveness.rs
third_party/rust/cranelift-codegen/src/verifier/locations.rs
third_party/rust/cranelift-codegen/src/verifier/mod.rs
third_party/rust/cranelift-codegen/src/write.rs
third_party/rust/cranelift-entity/.cargo-checksum.json
third_party/rust/cranelift-entity/Cargo.toml
third_party/rust/cranelift-entity/LICENSE
third_party/rust/cranelift-entity/README.md
third_party/rust/cranelift-entity/src/iter.rs
third_party/rust/cranelift-entity/src/keys.rs
third_party/rust/cranelift-entity/src/lib.rs
third_party/rust/cranelift-entity/src/list.rs
third_party/rust/cranelift-entity/src/map.rs
third_party/rust/cranelift-entity/src/packed_option.rs
third_party/rust/cranelift-entity/src/primary.rs
third_party/rust/cranelift-entity/src/set.rs
third_party/rust/cranelift-entity/src/sparse.rs
third_party/rust/cranelift-frontend/.cargo-checksum.json
third_party/rust/cranelift-frontend/Cargo.toml
third_party/rust/cranelift-frontend/LICENSE
third_party/rust/cranelift-frontend/README.md
third_party/rust/cranelift-frontend/src/frontend.rs
third_party/rust/cranelift-frontend/src/lib.rs
third_party/rust/cranelift-frontend/src/ssa.rs
third_party/rust/cranelift-frontend/src/variable.rs
third_party/rust/cranelift-wasm/.cargo-checksum.json
third_party/rust/cranelift-wasm/Cargo.toml
third_party/rust/cranelift-wasm/LICENSE
third_party/rust/cranelift-wasm/README.md
third_party/rust/cranelift-wasm/src/code_translator.rs
third_party/rust/cranelift-wasm/src/environ/dummy.rs
third_party/rust/cranelift-wasm/src/environ/mod.rs
third_party/rust/cranelift-wasm/src/environ/spec.rs
third_party/rust/cranelift-wasm/src/func_translator.rs
third_party/rust/cranelift-wasm/src/lib.rs
third_party/rust/cranelift-wasm/src/module_translator.rs
third_party/rust/cranelift-wasm/src/sections_translator.rs
third_party/rust/cranelift-wasm/src/state.rs
third_party/rust/cranelift-wasm/src/translation_utils.rs
third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs
third_party/rust/target-lexicon/.cargo-checksum.json
third_party/rust/target-lexicon/.rustfmt.toml
third_party/rust/target-lexicon/.travis.yml
third_party/rust/target-lexicon/Cargo.toml
third_party/rust/target-lexicon/LICENSE
third_party/rust/target-lexicon/README.md
third_party/rust/target-lexicon/build.rs
third_party/rust/target-lexicon/examples/misc.rs
third_party/rust/target-lexicon/src/host.rs
third_party/rust/target-lexicon/src/lib.rs
third_party/rust/target-lexicon/src/parse_error.rs
third_party/rust/target-lexicon/src/targets.rs
third_party/rust/target-lexicon/src/triple.rs
third_party/rust/wasmparser/.cargo-checksum.json
third_party/rust/wasmparser/.travis.yml
third_party/rust/wasmparser/Cargo.toml
third_party/rust/wasmparser/LICENSE
third_party/rust/wasmparser/README.md
third_party/rust/wasmparser/check-rustfmt.sh
third_party/rust/wasmparser/examples/dump.rs
third_party/rust/wasmparser/examples/simple.rs
third_party/rust/wasmparser/format-all.sh
third_party/rust/wasmparser/src/lib.rs
third_party/rust/wasmparser/src/limits.rs
third_party/rust/wasmparser/src/parser.rs
third_party/rust/wasmparser/src/tests.rs
third_party/rust/wasmparser/src/validator.rs
third_party/rust/wasmparser/test-all.sh
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,16 +132,28 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "baldrdash"
+version = "0.1.0"
+dependencies = [
+ "bindgen 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "base64"
 version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -391,16 +403,71 @@ dependencies = [
 name = "cose-c"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "cranelift-bforest"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cranelift-codegen"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cranelift-bforest 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cranelift-codegen-meta"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cranelift-entity"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cranelift-frontend"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cranelift-wasm"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasmparser 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "crc"
 version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -884,16 +951,17 @@ dependencies = [
  "audioipc-server 0.2.3",
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb-pulse 0.2.0",
  "cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
+ "jsrust_shared 0.1.0",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozurl 0.0.1",
  "mp4parse_capi 0.10.1",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
  "prefs_parser 0.0.1",
  "rkv 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1052,16 +1120,31 @@ dependencies = [
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozjs_sys 0.0.0",
  "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "jsrust"
+version = "0.1.0"
+dependencies = [
+ "jsrust_shared 0.1.0",
+]
+
+[[package]]
+name = "jsrust_shared"
+version = "0.1.0"
+dependencies = [
+ "baldrdash 0.1.0",
+ "bindgen 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1356,16 +1439,17 @@ dependencies = [
 name = "moz_cbor"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "mozjs_sys"
 version = "0.0.0"
 dependencies = [
+ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mozprofile"
 version = "0.4.0"
@@ -2216,16 +2300,26 @@ source = "registry+https://github.com/ru
 dependencies = [
  "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "target-lexicon"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "tempdir"
 version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2586,16 +2680,21 @@ version = "0.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "wasmparser"
+version = "0.17.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "webdriver"
 version = "0.37.0"
 dependencies = [
  "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2843,16 +2942,22 @@ dependencies = [
 "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
 "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
 "checksum core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7caa6cb9e76ddddbea09a03266d6b3bc98cd41e9fb9b017c473e7cca593ec25"
 "checksum core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2a53cce0ddcf7e7e1f998738d757d5a3bf08bf799a180e50ebe50d298f52f5a"
 "checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
 "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
 "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.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96851b525021dd220259b9f29bf79d83f65b49e4f12b786d545aa929e4cad2"
+"checksum cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16f418f1d1e6221812a7d35cff5b9a572dc978c002e33792134bbd50c07cacca"
+"checksum cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1da3daa0109e7a0b7b322cea666cc223fb6a0d5170e83d23b3d5d2deaddca5f3"
+"checksum cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27412f153f2b517125dea9247ee8859a9ea3923d44384d54420e64fab9314752"
+"checksum cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03c44cc7006b375e60e0c7edb6fc81abfbf20158374c03f5d0da981b373860a3"
+"checksum cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a9d3454bf60ee6c3d1f54d6cf9ed82cfc1a2e7efb9ec1b16666bf2987c88bfa"
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
 "checksum cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)" = "495beddc39b1987b8e9f029354eccbd5ef88eb5f1cd24badb764dce338acf2e0"
@@ -3011,16 +3116,17 @@ dependencies = [
 "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
 "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
 "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
 "checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d"
 "checksum synstructure 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "98cad891cd238c98e1f0aec9f7c0f620aa696e4e5f7daba56ac67b5e86a6b049"
 "checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
+"checksum target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a34226bd63b5a26fc909f5f0d7ef4dc55d5851077035e49437e4e14bf567247f"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
 "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
 "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
 "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
 "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
@@ -3051,16 +3157,17 @@ dependencies = [
 "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
 "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "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 wasmparser 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fed18a63a6796175be2254fccca1da4e8b8fec0abca37ad155aea345feb50798"
 "checksum webidl 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc14e4b71f94b5bb4c6d696e3b3be4d2e9ee6750a60870ecae09ff7138a131a7"
 "checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"2ac8519f0423d9cc23bc68fb13e4af52ba478dd31c49fdb4cd0a1bd3251d4a48","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"569333274dd318ddfe098a9962f353ca45d2702f9a44dfe8180f91c97fa19211","src/map.rs":"1d7882872863386c2576bfcb7c4caf2d135c250feadf82d342ad3682c64d9c7c","src/node.rs":"3943b6126f1b8f83421a9db073db880e80003d93458170a36195f06bad452be4","src/path.rs":"28e29259ff6a2ca35adc5a036bebede3f0da39d40c91de27d219ef04dd60f994","src/pool.rs":"d572863b0e2055b13ea4f34a06512778915a98bfe6f9073d3829d26108c506b0","src/set.rs":"879a7469b7f86fe90786945b19d3f85909a651fb9b297d660b4ce118d6718ec6"},"package":"1e96851b525021dd220259b9f29bf79d83f65b49e4f12b786d545aa929e4cad2"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/Cargo.toml
@@ -0,0 +1,35 @@
+# 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]
+name = "cranelift-bforest"
+version = "0.20.0"
+authors = ["The Cranelift Project Developers"]
+description = "A forest of B+-trees"
+documentation = "https://cranelift.readthedocs.io/"
+readme = "README.md"
+keywords = ["btree", "forest", "set", "map"]
+categories = ["no-std"]
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/CraneStation/cranelift"
+[dependencies.cranelift-entity]
+version = "0.20.0"
+default-features = false
+
+[features]
+default = ["std"]
+std = ["cranelift-entity/std"]
+[badges.maintenance]
+status = "experimental"
+
+[badges.travis-ci]
+repository = "CraneStation/cranelift"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/LICENSE
@@ -0,0 +1,219 @@
+
+                                 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.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/README.md
@@ -0,0 +1,12 @@
+This crate contains array-based data structures used by the core Cranelift code
+generator which represent a set of small ordered sets or maps.
+
+**These are not general purpose data structures that are somehow magically faster that the
+standard library's `BTreeSet` and `BTreeMap` types.**
+
+The tradeoffs are different:
+
+- Keys and values are expected to be small and copyable. We optimize for 32-bit types.
+- A comparator object is used to compare keys, allowing smaller "context free" keys.
+- Empty trees have a very small 32-bit footprint.
+- All the trees in a forest can be cleared in constant time.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/lib.rs
@@ -0,0 +1,201 @@
+//! A forest of B+-trees.
+//!
+//! This crate provides a data structures representing a set of small ordered sets or maps.
+//! It is implemented as a forest of B+-trees all allocating nodes out of the same pool.
+//!
+//! **These are not general purpose data structures that are somehow magically faster that the
+//! standard library's `BTreeSet` and `BTreeMap` types.**
+//!
+//! The tradeoffs are different:
+//!
+//! - Keys and values are expected to be small and copyable. We optimize for 32-bit types.
+//! - A comparator object is used to compare keys, allowing smaller "context free" keys.
+//! - Empty trees have a very small 32-bit footprint.
+//! - All the trees in a forest can be cleared in constant time.
+
+#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
+#![warn(unused_import_braces)]
+#![cfg_attr(feature = "std", warn(unstable_features))]
+#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
+#![cfg_attr(feature = "cargo-clippy", allow(new_without_default, new_without_default_derive))]
+#![cfg_attr(
+    feature = "cargo-clippy",
+    warn(
+        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
+        print_stdout, unicode_not_nfc, use_self
+    )
+)]
+// Turns on no_std and alloc features if std is not available.
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(not(feature = "std"), feature(alloc))]
+
+/// This replaces `std` in builds with `core`.
+#[cfg(not(feature = "std"))]
+mod std {
+    extern crate alloc;
+    pub use self::alloc::{boxed, string, vec};
+    pub use core::*;
+}
+
+#[macro_use]
+extern crate cranelift_entity as entity;
+use entity::packed_option;
+
+use std::borrow::BorrowMut;
+use std::cmp::Ordering;
+
+mod map;
+mod node;
+mod path;
+mod pool;
+mod set;
+
+pub use self::map::{Map, MapCursor, MapForest, MapIter};
+pub use self::set::{Set, SetCursor, SetForest, SetIter};
+
+use self::node::NodeData;
+use self::path::Path;
+use self::pool::NodePool;
+
+/// The maximum branching factor of an inner node in a B+-tree.
+/// The minimum number of outgoing edges is `INNER_SIZE/2`.
+const INNER_SIZE: usize = 8;
+
+/// Given the worst case branching factor of `INNER_SIZE/2` = 4, this is the
+/// worst case path length from the root node to a leaf node in a tree with 2^32
+/// entries. We would run out of node references before we hit `MAX_PATH`.
+const MAX_PATH: usize = 16;
+
+/// Key comparator.
+///
+/// Keys don't need to implement `Ord`. They are compared using a comparator object which
+/// provides a context for comparison.
+pub trait Comparator<K>
+where
+    K: Copy,
+{
+    /// Compare keys `a` and `b`.
+    ///
+    /// This relation must provide a total ordering or the key space.
+    fn cmp(&self, a: K, b: K) -> Ordering;
+
+    /// Binary search for `k` in an ordered slice.
+    ///
+    /// Assume that `s` is already sorted according to this ordering, search for the key `k`.
+    ///
+    /// Returns `Ok(idx)` if `k` was found in the slice or `Err(idx)` with the position where it
+    /// should be inserted to preserve the ordering.
+    fn search(&self, k: K, s: &[K]) -> Result<usize, usize> {
+        s.binary_search_by(|x| self.cmp(*x, k))
+    }
+}
+
+/// Trivial comparator that doesn't actually provide any context.
+impl<K> Comparator<K> for ()
+where
+    K: Copy + Ord,
+{
+    fn cmp(&self, a: K, b: K) -> Ordering {
+        a.cmp(&b)
+    }
+}
+
+/// Family of types shared by the map and set forest implementations.
+trait Forest {
+    /// The key type is present for both sets and maps.
+    type Key: Copy;
+
+    /// The value type is `()` for sets.
+    type Value: Copy;
+
+    /// An array of keys for the leaf nodes.
+    type LeafKeys: Copy + BorrowMut<[Self::Key]>;
+
+    /// An array of values for the leaf nodes.
+    type LeafValues: Copy + BorrowMut<[Self::Value]>;
+
+    /// Splat a single key into a whole array.
+    fn splat_key(key: Self::Key) -> Self::LeafKeys;
+
+    /// Splat a single value inst a whole array
+    fn splat_value(value: Self::Value) -> Self::LeafValues;
+}
+
+/// A reference to a B+-tree node.
+#[derive(Clone, Copy, PartialEq, Eq)]
+struct Node(u32);
+entity_impl!(Node, "node");
+
+/// Empty type to be used as the "value" in B-trees representing sets.
+#[derive(Clone, Copy)]
+struct SetValue();
+
+/// Insert `x` into `s` at position `i`, pushing out the last element.
+fn slice_insert<T: Copy>(s: &mut [T], i: usize, x: T) {
+    for j in (i + 1..s.len()).rev() {
+        s[j] = s[j - 1];
+    }
+    s[i] = x;
+}
+
+/// Shift elements in `s` to the left by `n` positions.
+fn slice_shift<T: Copy>(s: &mut [T], n: usize) {
+    for j in 0..s.len() - n {
+        s[j] = s[j + n];
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use entity::EntityRef;
+
+    /// An opaque reference to an extended basic block in a function.
+    #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+    pub struct Ebb(u32);
+    entity_impl!(Ebb, "ebb");
+
+    #[test]
+    fn comparator() {
+        let ebb1 = Ebb::new(1);
+        let ebb2 = Ebb::new(2);
+        let ebb3 = Ebb::new(3);
+        let ebb4 = Ebb::new(4);
+        let vals = [ebb1, ebb2, ebb4];
+        let comp = ();
+        assert_eq!(comp.search(ebb1, &vals), Ok(0));
+        assert_eq!(comp.search(ebb3, &vals), Err(2));
+        assert_eq!(comp.search(ebb4, &vals), Ok(2));
+    }
+
+    #[test]
+    fn slice_insertion() {
+        let mut a = ['a', 'b', 'c', 'd'];
+
+        slice_insert(&mut a[0..1], 0, 'e');
+        assert_eq!(a, ['e', 'b', 'c', 'd']);
+
+        slice_insert(&mut a, 0, 'a');
+        assert_eq!(a, ['a', 'e', 'b', 'c']);
+
+        slice_insert(&mut a, 3, 'g');
+        assert_eq!(a, ['a', 'e', 'b', 'g']);
+
+        slice_insert(&mut a, 1, 'h');
+        assert_eq!(a, ['a', 'h', 'e', 'b']);
+    }
+
+    #[test]
+    fn slice_shifting() {
+        let mut a = ['a', 'b', 'c', 'd'];
+
+        slice_shift(&mut a[0..1], 1);
+        assert_eq!(a, ['a', 'b', 'c', 'd']);
+
+        slice_shift(&mut a[1..], 1);
+        assert_eq!(a, ['a', 'c', 'd', 'd']);
+
+        slice_shift(&mut a, 2);
+        assert_eq!(a, ['d', 'd', 'd', 'd']);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/map.rs
@@ -0,0 +1,926 @@
+//! Forest of maps.
+
+use super::{Comparator, Forest, Node, NodeData, NodePool, Path, INNER_SIZE};
+use packed_option::PackedOption;
+#[cfg(test)]
+use std::fmt;
+use std::marker::PhantomData;
+#[cfg(test)]
+use std::string::String;
+
+/// Tag type defining forest types for a map.
+struct MapTypes<K, V>(PhantomData<(K, V)>);
+
+impl<K, V> Forest for MapTypes<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    type Key = K;
+    type Value = V;
+    type LeafKeys = [K; INNER_SIZE - 1];
+    type LeafValues = [V; INNER_SIZE - 1];
+
+    fn splat_key(key: Self::Key) -> Self::LeafKeys {
+        [key; INNER_SIZE - 1]
+    }
+
+    fn splat_value(value: Self::Value) -> Self::LeafValues {
+        [value; INNER_SIZE - 1]
+    }
+}
+
+/// Memory pool for a forest of `Map` instances.
+pub struct MapForest<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    nodes: NodePool<MapTypes<K, V>>,
+}
+
+impl<K, V> MapForest<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    /// Create a new empty forest.
+    pub fn new() -> Self {
+        Self {
+            nodes: NodePool::new(),
+        }
+    }
+
+    /// Clear all maps in the forest.
+    ///
+    /// All `Map` instances belong to this forest are invalidated and should no longer be used.
+    pub fn clear(&mut self) {
+        self.nodes.clear();
+    }
+}
+
+/// B-tree mapping from `K` to `V`.
+///
+/// This is not a general-purpose replacement for `BTreeMap`. See the [module
+/// documentation](index.html) for more information about design tradeoffs.
+///
+/// Maps can be cloned, but that operation should only be used as part of cloning the whole forest
+/// they belong to. *Cloning a map does not allocate new memory for the clone*. It creates an alias
+/// of the same memory.
+#[derive(Clone)]
+pub struct Map<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    root: PackedOption<Node>,
+    unused: PhantomData<(K, V)>,
+}
+
+impl<K, V> Map<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    /// Make an empty map.
+    pub fn new() -> Self {
+        Self {
+            root: None.into(),
+            unused: PhantomData,
+        }
+    }
+
+    /// Is this an empty map?
+    pub fn is_empty(&self) -> bool {
+        self.root.is_none()
+    }
+
+    /// Get the value stored for `key`.
+    pub fn get<C: Comparator<K>>(&self, key: K, forest: &MapForest<K, V>, comp: &C) -> Option<V> {
+        self.root
+            .expand()
+            .and_then(|root| Path::default().find(key, root, &forest.nodes, comp))
+    }
+
+    /// Look up the value stored for `key`.
+    ///
+    /// If it exists, return the stored key-value pair.
+    ///
+    /// Otherwise, return the last key-value pair with a key that is less than or equal to `key`.
+    ///
+    /// If no stored keys are less than or equal to `key`, return `None`.
+    pub fn get_or_less<C: Comparator<K>>(
+        &self,
+        key: K,
+        forest: &MapForest<K, V>,
+        comp: &C,
+    ) -> Option<(K, V)> {
+        self.root.expand().and_then(|root| {
+            let mut path = Path::default();
+            match path.find(key, root, &forest.nodes, comp) {
+                Some(v) => Some((key, v)),
+                None => path.prev(root, &forest.nodes),
+            }
+        })
+    }
+
+    /// Insert `key, value` into the map and return the old value stored for `key`, if any.
+    pub fn insert<C: Comparator<K>>(
+        &mut self,
+        key: K,
+        value: V,
+        forest: &mut MapForest<K, V>,
+        comp: &C,
+    ) -> Option<V> {
+        self.cursor(forest, comp).insert(key, value)
+    }
+
+    /// Remove `key` from the map and return the removed value for `key`, if any.
+    pub fn remove<C: Comparator<K>>(
+        &mut self,
+        key: K,
+        forest: &mut MapForest<K, V>,
+        comp: &C,
+    ) -> Option<V> {
+        let mut c = self.cursor(forest, comp);
+        if c.goto(key).is_some() {
+            c.remove()
+        } else {
+            None
+        }
+    }
+
+    /// Remove all entries.
+    pub fn clear(&mut self, forest: &mut MapForest<K, V>) {
+        if let Some(root) = self.root.take() {
+            forest.nodes.free_tree(root);
+        }
+    }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// Remove all key-value pairs where the predicate returns false.
+    ///
+    /// The predicate is allowed to update the values stored in the map.
+    pub fn retain<F>(&mut self, forest: &mut MapForest<K, V>, mut predicate: F)
+    where
+        F: FnMut(K, &mut V) -> bool,
+    {
+        let mut path = Path::default();
+        if let Some(root) = self.root.expand() {
+            path.first(root, &forest.nodes);
+        }
+        while let Some((node, entry)) = path.leaf_pos() {
+            let keep = {
+                let (ks, vs) = forest.nodes[node].unwrap_leaf_mut();
+                predicate(ks[entry], &mut vs[entry])
+            };
+            if keep {
+                path.next(&forest.nodes);
+            } else {
+                self.root = path.remove(&mut forest.nodes).into();
+            }
+        }
+    }
+
+    /// Create a cursor for navigating this map. The cursor is initially positioned off the end of
+    /// the map.
+    pub fn cursor<'a, C: Comparator<K>>(
+        &'a mut self,
+        forest: &'a mut MapForest<K, V>,
+        comp: &'a C,
+    ) -> MapCursor<'a, K, V, C> {
+        MapCursor::new(self, forest, comp)
+    }
+
+    /// Create an iterator traversing this map. The iterator type is `(K, V)`.
+    pub fn iter<'a>(&'a self, forest: &'a MapForest<K, V>) -> MapIter<'a, K, V> {
+        MapIter {
+            root: self.root,
+            pool: &forest.nodes,
+            path: Path::default(),
+        }
+    }
+}
+
+impl<K, V> Default for Map<K, V>
+where
+    K: Copy,
+    V: Copy,
+{
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[cfg(test)]
+impl<K, V> Map<K, V>
+where
+    K: Copy + fmt::Display,
+    V: Copy,
+{
+    /// Verify consistency.
+    fn verify<C: Comparator<K>>(&self, forest: &MapForest<K, V>, comp: &C)
+    where
+        NodeData<MapTypes<K, V>>: fmt::Display,
+    {
+        if let Some(root) = self.root.expand() {
+            forest.nodes.verify_tree(root, comp);
+        }
+    }
+
+    /// Get a text version of the path to `key`.
+    fn tpath<C: Comparator<K>>(&self, key: K, forest: &MapForest<K, V>, comp: &C) -> String {
+        use std::string::ToString;
+        match self.root.expand() {
+            None => "map(empty)".to_string(),
+            Some(root) => {
+                let mut path = Path::default();
+                path.find(key, root, &forest.nodes, comp);
+                path.to_string()
+            }
+        }
+    }
+}
+
+/// A position in a `Map` used to navigate and modify the ordered map.
+///
+/// A cursor always points at a key-value pair in the map, or "off the end" which is a position
+/// after the last entry in the map.
+pub struct MapCursor<'a, K, V, C>
+where
+    K: 'a + Copy,
+    V: 'a + Copy,
+    C: 'a + Comparator<K>,
+{
+    root: &'a mut PackedOption<Node>,
+    pool: &'a mut NodePool<MapTypes<K, V>>,
+    comp: &'a C,
+    path: Path<MapTypes<K, V>>,
+}
+
+impl<'a, K, V, C> MapCursor<'a, K, V, C>
+where
+    K: Copy,
+    V: Copy,
+    C: Comparator<K>,
+{
+    /// Create a cursor with a default (off-the-end) location.
+    fn new(
+        container: &'a mut Map<K, V>,
+        forest: &'a mut MapForest<K, V>,
+        comp: &'a C,
+    ) -> MapCursor<'a, K, V, C> {
+        MapCursor {
+            root: &mut container.root,
+            pool: &mut forest.nodes,
+            comp,
+            path: Path::default(),
+        }
+    }
+
+    /// Is this cursor pointing to an empty map?
+    pub fn is_empty(&self) -> bool {
+        self.root.is_none()
+    }
+
+    /// Move cursor to the next key-value pair and return it.
+    ///
+    /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end
+    /// position.
+    pub fn next(&mut self) -> Option<(K, V)> {
+        self.path.next(self.pool)
+    }
+
+    /// Move cursor to the previous key-value pair and return it.
+    ///
+    /// If the cursor is already pointing at the first entry, leave it there and return `None`.
+    pub fn prev(&mut self) -> Option<(K, V)> {
+        self.root
+            .expand()
+            .and_then(|root| self.path.prev(root, self.pool))
+    }
+
+    /// Get the current key, or `None` if the cursor is at the end.
+    pub fn key(&self) -> Option<K> {
+        self.path
+            .leaf_pos()
+            .and_then(|(node, entry)| self.pool[node].unwrap_leaf().0.get(entry).cloned())
+    }
+
+    /// Get the current value, or `None` if the cursor is at the end.
+    pub fn value(&self) -> Option<V> {
+        self.path
+            .leaf_pos()
+            .and_then(|(node, entry)| self.pool[node].unwrap_leaf().1.get(entry).cloned())
+    }
+
+    /// Get a mutable reference to the current value, or `None` if the cursor is at the end.
+    pub fn value_mut(&mut self) -> Option<&mut V> {
+        self.path
+            .leaf_pos()
+            .and_then(move |(node, entry)| self.pool[node].unwrap_leaf_mut().1.get_mut(entry))
+    }
+
+    /// Move this cursor to `key`.
+    ///
+    /// If `key` is in the map, place the cursor at `key` and return the corresponding value.
+    ///
+    /// If `key` is not in the set, place the cursor at the next larger element (or the end) and
+    /// return `None`.
+    pub fn goto(&mut self, elem: K) -> Option<V> {
+        self.root.expand().and_then(|root| {
+            let v = self.path.find(elem, root, self.pool, self.comp);
+            if v.is_none() {
+                self.path.normalize(self.pool);
+            }
+            v
+        })
+    }
+
+    /// Move this cursor to the first element.
+    pub fn goto_first(&mut self) -> Option<V> {
+        self.root.map(|root| self.path.first(root, self.pool).1)
+    }
+
+    /// Insert `(key, value))` into the map and leave the cursor at the inserted pair.
+    ///
+    /// If the map did not contain `key`, return `None`.
+    ///
+    /// If `key` is already present, replace the existing with `value` and return the old value.
+    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
+        match self.root.expand() {
+            None => {
+                let root = self.pool.alloc_node(NodeData::leaf(key, value));
+                *self.root = root.into();
+                self.path.set_root_node(root);
+                None
+            }
+            Some(root) => {
+                // TODO: Optimize the case where `self.path` is already at the correct insert pos.
+                let old = self.path.find(key, root, self.pool, self.comp);
+                if old.is_some() {
+                    *self.path.value_mut(self.pool) = value;
+                } else {
+                    *self.root = self.path.insert(key, value, self.pool).into();
+                }
+                old
+            }
+        }
+    }
+
+    /// Remove the current entry (if any) and return the mapped value.
+    /// This advances the cursor to the next entry after the removed one.
+    pub fn remove(&mut self) -> Option<V> {
+        let value = self.value();
+        if value.is_some() {
+            *self.root = self.path.remove(self.pool).into();
+        }
+        value
+    }
+}
+
+/// An iterator visiting the key-value pairs of a `Map`.
+pub struct MapIter<'a, K, V>
+where
+    K: 'a + Copy,
+    V: 'a + Copy,
+{
+    root: PackedOption<Node>,
+    pool: &'a NodePool<MapTypes<K, V>>,
+    path: Path<MapTypes<K, V>>,
+}
+
+impl<'a, K, V> Iterator for MapIter<'a, K, V>
+where
+    K: 'a + Copy,
+    V: 'a + Copy,
+{
+    type Item = (K, V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // We use `self.root` to indicate if we need to go to the first element. Reset to `None`
+        // once we've returned the first element. This also works for an empty tree since the
+        // `path.next()` call returns `None` when the path is empty. This also fuses the iterator.
+        match self.root.take() {
+            Some(root) => Some(self.path.first(root, self.pool)),
+            None => self.path.next(self.pool),
+        }
+    }
+}
+
+#[cfg(test)]
+impl<'a, K, V, C> MapCursor<'a, K, V, C>
+where
+    K: Copy + fmt::Display,
+    V: Copy + fmt::Display,
+    C: Comparator<K>,
+{
+    fn verify(&self) {
+        self.path.verify(self.pool);
+        self.root.map(|root| self.pool.verify_tree(root, self.comp));
+    }
+
+    /// Get a text version of the path to the current position.
+    fn tpath(&self) -> String {
+        use std::string::ToString;
+        self.path.to_string()
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::super::NodeData;
+    use super::*;
+    use std::mem;
+    use std::vec::Vec;
+
+    #[test]
+    fn node_size() {
+        // check that nodes are cache line sized when keys and values are 32 bits.
+        type F = MapTypes<u32, u32>;
+        assert_eq!(mem::size_of::<NodeData<F>>(), 64);
+    }
+
+    #[test]
+    fn empty() {
+        let mut f = MapForest::<u32, f32>::new();
+        f.clear();
+
+        let mut m = Map::<u32, f32>::new();
+        assert!(m.is_empty());
+        m.clear(&mut f);
+
+        assert_eq!(m.get(7, &f, &()), None);
+        assert_eq!(m.iter(&f).next(), None);
+        assert_eq!(m.get_or_less(7, &f, &()), None);
+        m.retain(&mut f, |_, _| unreachable!());
+
+        let mut c = m.cursor(&mut f, &());
+        assert!(c.is_empty());
+        assert_eq!(c.key(), None);
+        assert_eq!(c.value(), None);
+        assert_eq!(c.next(), None);
+        assert_eq!(c.prev(), None);
+        c.verify();
+        assert_eq!(c.tpath(), "<empty path>");
+        assert_eq!(c.goto_first(), None);
+        assert_eq!(c.tpath(), "<empty path>");
+    }
+
+    #[test]
+    fn inserting() {
+        let f = &mut MapForest::<u32, f32>::new();
+        let mut m = Map::<u32, f32>::new();
+
+        // The first seven values stay in a single leaf node.
+        assert_eq!(m.insert(50, 5.0, f, &()), None);
+        assert_eq!(m.insert(50, 5.5, f, &()), Some(5.0));
+        assert_eq!(m.insert(20, 2.0, f, &()), None);
+        assert_eq!(m.insert(80, 8.0, f, &()), None);
+        assert_eq!(m.insert(40, 4.0, f, &()), None);
+        assert_eq!(m.insert(60, 6.0, f, &()), None);
+        assert_eq!(m.insert(90, 9.0, f, &()), None);
+        assert_eq!(m.insert(200, 20.0, f, &()), None);
+
+        m.verify(f, &());
+
+        assert_eq!(
+            m.iter(f).collect::<Vec<_>>(),
+            [
+                (20, 2.0),
+                (40, 4.0),
+                (50, 5.5),
+                (60, 6.0),
+                (80, 8.0),
+                (90, 9.0),
+                (200, 20.0),
+            ]
+        );
+
+        assert_eq!(m.get(0, f, &()), None);
+        assert_eq!(m.get(20, f, &()), Some(2.0));
+        assert_eq!(m.get(30, f, &()), None);
+        assert_eq!(m.get(40, f, &()), Some(4.0));
+        assert_eq!(m.get(50, f, &()), Some(5.5));
+        assert_eq!(m.get(60, f, &()), Some(6.0));
+        assert_eq!(m.get(70, f, &()), None);
+        assert_eq!(m.get(80, f, &()), Some(8.0));
+        assert_eq!(m.get(100, f, &()), None);
+
+        assert_eq!(m.get_or_less(0, f, &()), None);
+        assert_eq!(m.get_or_less(20, f, &()), Some((20, 2.0)));
+        assert_eq!(m.get_or_less(30, f, &()), Some((20, 2.0)));
+        assert_eq!(m.get_or_less(40, f, &()), Some((40, 4.0)));
+        assert_eq!(m.get_or_less(200, f, &()), Some((200, 20.0)));
+        assert_eq!(m.get_or_less(201, f, &()), Some((200, 20.0)));
+
+        {
+            let mut c = m.cursor(f, &());
+            assert_eq!(c.prev(), Some((200, 20.0)));
+            assert_eq!(c.prev(), Some((90, 9.0)));
+            assert_eq!(c.prev(), Some((80, 8.0)));
+            assert_eq!(c.prev(), Some((60, 6.0)));
+            assert_eq!(c.prev(), Some((50, 5.5)));
+            assert_eq!(c.prev(), Some((40, 4.0)));
+            assert_eq!(c.prev(), Some((20, 2.0)));
+            assert_eq!(c.prev(), None);
+        }
+
+        // Test some removals where the node stays healthy.
+        assert_eq!(m.tpath(50, f, &()), "node0[2]");
+        assert_eq!(m.tpath(80, f, &()), "node0[4]");
+        assert_eq!(m.tpath(200, f, &()), "node0[6]");
+
+        assert_eq!(m.remove(80, f, &()), Some(8.0));
+        assert_eq!(m.tpath(50, f, &()), "node0[2]");
+        assert_eq!(m.tpath(80, f, &()), "node0[4]");
+        assert_eq!(m.tpath(200, f, &()), "node0[5]");
+        assert_eq!(m.remove(80, f, &()), None);
+        m.verify(f, &());
+
+        assert_eq!(m.remove(20, f, &()), Some(2.0));
+        assert_eq!(m.tpath(50, f, &()), "node0[1]");
+        assert_eq!(m.tpath(80, f, &()), "node0[3]");
+        assert_eq!(m.tpath(200, f, &()), "node0[4]");
+        assert_eq!(m.remove(20, f, &()), None);
+        m.verify(f, &());
+
+        // [ 40 50 60 90 200 ]
+
+        {
+            let mut c = m.cursor(f, &());
+            assert_eq!(c.goto_first(), Some(4.0));
+            assert_eq!(c.key(), Some(40));
+            assert_eq!(c.value(), Some(4.0));
+            assert_eq!(c.next(), Some((50, 5.5)));
+            assert_eq!(c.next(), Some((60, 6.0)));
+            assert_eq!(c.next(), Some((90, 9.0)));
+            assert_eq!(c.next(), Some((200, 20.0)));
+            c.verify();
+            assert_eq!(c.next(), None);
+            c.verify();
+        }
+
+        // Removals from the root leaf node beyond underflow.
+        assert_eq!(m.remove(200, f, &()), Some(20.0));
+        assert_eq!(m.remove(40, f, &()), Some(4.0));
+        assert_eq!(m.remove(60, f, &()), Some(6.0));
+        m.verify(f, &());
+        assert_eq!(m.remove(50, f, &()), Some(5.5));
+        m.verify(f, &());
+        assert_eq!(m.remove(90, f, &()), Some(9.0));
+        m.verify(f, &());
+        assert!(m.is_empty());
+    }
+
+    #[test]
+    fn split_level0_leaf() {
+        // Various ways of splitting a full leaf node at level 0.
+        let f = &mut MapForest::<u32, f32>::new();
+
+        fn full_leaf(f: &mut MapForest<u32, f32>) -> Map<u32, f32> {
+            let mut m = Map::new();
+            for n in 1..8 {
+                m.insert(n * 10, n as f32 * 1.1, f, &());
+            }
+            m
+        }
+
+        // Insert at front of leaf.
+        let mut m = full_leaf(f);
+        m.insert(5, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(5, f, &()), Some(4.2));
+
+        // Retain even entries, with altered values.
+        m.retain(f, |k, v| {
+            *v = (k / 10) as f32;
+            (k % 20) == 0
+        });
+        assert_eq!(
+            m.iter(f).collect::<Vec<_>>(),
+            [(20, 2.0), (40, 4.0), (60, 6.0)]
+        );
+
+        // Insert at back of leaf.
+        let mut m = full_leaf(f);
+        m.insert(80, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(80, f, &()), Some(4.2));
+
+        // Insert before middle (40).
+        let mut m = full_leaf(f);
+        m.insert(35, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(35, f, &()), Some(4.2));
+
+        // Insert after middle (40).
+        let mut m = full_leaf(f);
+        m.insert(45, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(45, f, &()), Some(4.2));
+
+        m.clear(f);
+        assert!(m.is_empty());
+    }
+
+    #[test]
+    fn split_level1_leaf() {
+        // Various ways of splitting a full leaf node at level 1.
+        let f = &mut MapForest::<u32, f32>::new();
+
+        // Return a map whose root node is a full inner node, and the leaf nodes are all full
+        // containing:
+        //
+        // 110, 120, ..., 170
+        // 210, 220, ..., 270
+        // ...
+        // 810, 820, ..., 870
+        fn full(f: &mut MapForest<u32, f32>) -> Map<u32, f32> {
+            let mut m = Map::new();
+
+            // Start by inserting elements in order.
+            // This should leave 8 leaf nodes with 4 elements in each.
+            for row in 1..9 {
+                for col in 1..5 {
+                    m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &());
+                }
+            }
+
+            // Then top up the leaf nodes without splitting them.
+            for row in 1..9 {
+                for col in 5..8 {
+                    m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &());
+                }
+            }
+
+            m
+        }
+
+        let mut m = full(f);
+        // Verify geometry. Get get node2 as the root and leaves node0, 1, 3, ...
+        m.verify(f, &());
+        assert_eq!(m.tpath(110, f, &()), "node2[0]--node0[0]");
+        assert_eq!(m.tpath(140, f, &()), "node2[0]--node0[3]");
+        assert_eq!(m.tpath(210, f, &()), "node2[1]--node1[0]");
+        assert_eq!(m.tpath(270, f, &()), "node2[1]--node1[6]");
+        assert_eq!(m.tpath(310, f, &()), "node2[2]--node3[0]");
+        assert_eq!(m.tpath(810, f, &()), "node2[7]--node8[0]");
+        assert_eq!(m.tpath(870, f, &()), "node2[7]--node8[6]");
+
+        {
+            let mut c = m.cursor(f, &());
+            assert_eq!(c.goto_first(), Some(1.1));
+            assert_eq!(c.key(), Some(110));
+        }
+
+        // Front of first leaf.
+        m.insert(0, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(0, f, &()), Some(4.2));
+
+        // First leaf split 4-4 after appending to LHS.
+        f.clear();
+        m = full(f);
+        m.insert(135, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(135, f, &()), Some(4.2));
+
+        // First leaf split 4-4 after prepending to RHS.
+        f.clear();
+        m = full(f);
+        m.insert(145, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(145, f, &()), Some(4.2));
+
+        // First leaf split 4-4 after appending to RHS.
+        f.clear();
+        m = full(f);
+        m.insert(175, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(175, f, &()), Some(4.2));
+
+        // Left-middle leaf split, ins LHS.
+        f.clear();
+        m = full(f);
+        m.insert(435, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(435, f, &()), Some(4.2));
+
+        // Left-middle leaf split, ins RHS.
+        f.clear();
+        m = full(f);
+        m.insert(445, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(445, f, &()), Some(4.2));
+
+        // Right-middle leaf split, ins LHS.
+        f.clear();
+        m = full(f);
+        m.insert(535, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(535, f, &()), Some(4.2));
+
+        // Right-middle leaf split, ins RHS.
+        f.clear();
+        m = full(f);
+        m.insert(545, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(545, f, &()), Some(4.2));
+
+        // Last leaf split, ins LHS.
+        f.clear();
+        m = full(f);
+        m.insert(835, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(835, f, &()), Some(4.2));
+
+        // Last leaf split, ins RHS.
+        f.clear();
+        m = full(f);
+        m.insert(845, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(845, f, &()), Some(4.2));
+
+        // Front of last leaf.
+        f.clear();
+        m = full(f);
+        m.insert(805, 4.2, f, &());
+        m.verify(f, &());
+        assert_eq!(m.get(805, f, &()), Some(4.2));
+
+        m.clear(f);
+        m.verify(f, &());
+    }
+
+    // Make a tree with two barely healthy leaf nodes:
+    // [ 10 20 30 40 ] [ 50 60 70 80 ]
+    fn two_leaf(f: &mut MapForest<u32, f32>) -> Map<u32, f32> {
+        f.clear();
+        let mut m = Map::new();
+        for n in 1..9 {
+            m.insert(n * 10, n as f32, f, &());
+        }
+        m
+    }
+
+    #[test]
+    fn remove_level1() {
+        let f = &mut MapForest::<u32, f32>::new();
+        let mut m = two_leaf(f);
+
+        // Verify geometry.
+        m.verify(f, &());
+        assert_eq!(m.tpath(10, f, &()), "node2[0]--node0[0]");
+        assert_eq!(m.tpath(40, f, &()), "node2[0]--node0[3]");
+        assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(50, f, &()), "node2[1]--node1[0]");
+        assert_eq!(m.tpath(80, f, &()), "node2[1]--node1[3]");
+
+        // Remove the front entry from a node that stays healthy.
+        assert_eq!(m.insert(55, 5.5, f, &()), None);
+        assert_eq!(m.remove(50, f, &()), Some(5.0));
+        m.verify(f, &());
+        assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(55, f, &()), "node2[1]--node1[0]");
+
+        // Remove the front entry from the first leaf node: No critical key to update.
+        assert_eq!(m.insert(15, 1.5, f, &()), None);
+        assert_eq!(m.remove(10, f, &()), Some(1.0));
+        m.verify(f, &());
+
+        // [ 15 20 30 40 ] [ 55 60 70 80 ]
+
+        // Remove the front entry from a right-most node that underflows.
+        // No rebalancing for the right-most node. Still need critical key update.
+        assert_eq!(m.remove(55, f, &()), Some(5.5));
+        m.verify(f, &());
+        assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]");
+
+        // [ 15 20 30 40 ] [ 60 70 80 ]
+
+        // Replenish the right leaf.
+        assert_eq!(m.insert(90, 9.0, f, &()), None);
+        assert_eq!(m.insert(100, 10.0, f, &()), None);
+        m.verify(f, &());
+        assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]");
+
+        // [ 15 20 30 40 ] [ 60 70 80 90 100 ]
+
+        // Removing one entry from the left leaf should trigger a rebalancing from the right
+        // sibling.
+        assert_eq!(m.remove(20, f, &()), Some(2.0));
+        m.verify(f, &());
+
+        // [ 15 30 40 60 ] [ 70 80 90 100 ]
+        // Check that the critical key was updated correctly.
+        assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[3]");
+        assert_eq!(m.tpath(60, f, &()), "node2[0]--node0[3]");
+        assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]");
+
+        // Remove front entry from the left-most leaf node, underflowing.
+        // This should cause two leaf nodes to be merged and the root node to go away.
+        assert_eq!(m.remove(15, f, &()), Some(1.5));
+        m.verify(f, &());
+    }
+
+    #[test]
+    fn remove_level1_rightmost() {
+        let f = &mut MapForest::<u32, f32>::new();
+        let mut m = two_leaf(f);
+
+        // [ 10 20 30 40 ] [ 50 60 70 80 ]
+
+        // Remove entries from the right leaf. This doesn't trigger a rebalancing.
+        assert_eq!(m.remove(60, f, &()), Some(6.0));
+        assert_eq!(m.remove(80, f, &()), Some(8.0));
+        assert_eq!(m.remove(50, f, &()), Some(5.0));
+        m.verify(f, &());
+
+        // [ 10 20 30 40 ] [ 70 ]
+        assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]");
+        assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]");
+
+        // Removing the last entry from the right leaf should cause a collapse.
+        assert_eq!(m.remove(70, f, &()), Some(7.0));
+        m.verify(f, &());
+    }
+
+    // Make a 3-level tree with barely healthy nodes.
+    // 1 root, 8 inner nodes, 7*4+5=33 leaf nodes, 4 entries each.
+    fn level3_sparse(f: &mut MapForest<u32, f32>) -> Map<u32, f32> {
+        f.clear();
+        let mut m = Map::new();
+        for n in 1..133 {
+            m.insert(n * 10, n as f32, f, &());
+        }
+        m
+    }
+
+    #[test]
+    fn level3_removes() {
+        let f = &mut MapForest::<u32, f32>::new();
+        let mut m = level3_sparse(f);
+        m.verify(f, &());
+
+        // Check geometry.
+        // Root: node11
+        // [ node2 170 node10 330 node16 490 node21 650 node26 810 node31 970 node36 1130 node41 ]
+        // L1: node11
+        assert_eq!(m.tpath(0, f, &()), "node11[0]--node2[0]--node0[0]");
+        assert_eq!(m.tpath(10000, f, &()), "node11[7]--node41[4]--node40[4]");
+
+        // 650 is a critical key in the middle of the root.
+        assert_eq!(m.tpath(640, f, &()), "node11[3]--node21[3]--node19[3]");
+        assert_eq!(m.tpath(650, f, &()), "node11[4]--node26[0]--node20[0]");
+
+        // Deleting 640 triggers a rebalance from node19 to node 20, cascading to n21 -> n26.
+        assert_eq!(m.remove(640, f, &()), Some(64.0));
+        m.verify(f, &());
+        assert_eq!(m.tpath(650, f, &()), "node11[3]--node26[3]--node20[3]");
+
+        // 1130 is in the first leaf of the last L1 node. Deleting it triggers a rebalance node35
+        // -> node37, but no rebalance above where there is no right sibling.
+        assert_eq!(m.tpath(1130, f, &()), "node11[6]--node41[0]--node35[0]");
+        assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node35[1]");
+        assert_eq!(m.remove(1130, f, &()), Some(113.0));
+        m.verify(f, &());
+        assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node37[0]");
+    }
+
+    #[test]
+    fn insert_many() {
+        let f = &mut MapForest::<u32, f32>::new();
+        let mut m = Map::<u32, f32>::new();
+
+        let mm = 4096;
+        let mut x = 0;
+
+        for n in 0..mm {
+            assert_eq!(m.insert(x, n as f32, f, &()), None);
+            m.verify(f, &());
+
+            x = (x + n + 1) % mm;
+        }
+
+        x = 0;
+        for n in 0..mm {
+            assert_eq!(m.get(x, f, &()), Some(n as f32));
+            x = (x + n + 1) % mm;
+        }
+
+        x = 0;
+        for n in 0..mm {
+            assert_eq!(m.remove(x, f, &()), Some(n as f32));
+            m.verify(f, &());
+
+            x = (x + n + 1) % mm;
+        }
+
+        assert!(m.is_empty());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/node.rs
@@ -0,0 +1,805 @@
+//! B+-tree nodes.
+
+use super::{slice_insert, slice_shift, Forest, Node, SetValue, INNER_SIZE};
+use std::borrow::{Borrow, BorrowMut};
+use std::fmt;
+
+/// B+-tree node.
+///
+/// A B+-tree has different node types for inner nodes and leaf nodes. Inner nodes contain M node
+/// references and M-1 keys while leaf nodes contain N keys and values. Values for M and N are
+/// chosen such that a node is exactly 64 bytes (a cache line) when keys and values are 32 bits
+/// each.
+///
+/// An inner node contains at least M/2 node references unless it is the right-most node at its
+/// level. A leaf node contains at least N/2 keys unless it is the right-most leaf.
+pub(super) enum NodeData<F: Forest> {
+    Inner {
+        /// The number of keys in this node.
+        /// The number of node references is always one more.
+        size: u8,
+
+        /// Keys discriminating sub-trees.
+        ///
+        /// The key in `keys[i]` is greater than all keys in `tree[i]` and less than or equal to
+        /// all keys in `tree[i+1]`.
+        keys: [F::Key; INNER_SIZE - 1],
+
+        /// Sub-trees.
+        tree: [Node; INNER_SIZE],
+    },
+    Leaf {
+        /// Number of key-value pairs in this node.
+        size: u8,
+
+        // Key array.
+        keys: F::LeafKeys,
+
+        // Value array.
+        vals: F::LeafValues,
+    },
+    /// An unused node on the free list.
+    Free { next: Option<Node> },
+}
+
+// Implement `Clone` and `Copy` manually, because deriving them would also require `Forest` to
+// implement `Clone`.
+impl<F: Forest> Copy for NodeData<F> {}
+impl<F: Forest> Clone for NodeData<F> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<F: Forest> NodeData<F> {
+    /// Is this a free/unused node?
+    pub fn is_free(&self) -> bool {
+        match *self {
+            NodeData::Free { .. } => true,
+            _ => false,
+        }
+    }
+
+    /// Get the number of entries in this node.
+    ///
+    /// This is the number of outgoing edges in an inner node, or the number of key-value pairs in
+    /// a leaf node.
+    pub fn entries(&self) -> usize {
+        match *self {
+            NodeData::Inner { size, .. } => usize::from(size) + 1,
+            NodeData::Leaf { size, .. } => usize::from(size),
+            NodeData::Free { .. } => panic!("freed node"),
+        }
+    }
+
+    /// Create an inner node with a single key and two sub-trees.
+    pub fn inner(left: Node, key: F::Key, right: Node) -> Self {
+        // Splat the key and right node to the whole array.
+        // Saves us from inventing a default/reserved value.
+        let mut tree = [right; INNER_SIZE];
+        tree[0] = left;
+        NodeData::Inner {
+            size: 1,
+            keys: [key; INNER_SIZE - 1],
+            tree,
+        }
+    }
+
+    /// Create a leaf node with a single key-value pair.
+    pub fn leaf(key: F::Key, value: F::Value) -> Self {
+        NodeData::Leaf {
+            size: 1,
+            keys: F::splat_key(key),
+            vals: F::splat_value(value),
+        }
+    }
+
+    /// Unwrap an inner node into two slices (keys, trees).
+    pub fn unwrap_inner(&self) -> (&[F::Key], &[Node]) {
+        match *self {
+            NodeData::Inner {
+                size,
+                ref keys,
+                ref tree,
+            } => {
+                let size = usize::from(size);
+                // TODO: We could probably use `get_unchecked()` here since `size` is always in
+                // range.
+                (&keys[0..size], &tree[0..size + 1])
+            }
+            _ => panic!("Expected inner node"),
+        }
+    }
+
+    /// Unwrap a leaf node into two slices (keys, values) of the same length.
+    pub fn unwrap_leaf(&self) -> (&[F::Key], &[F::Value]) {
+        match *self {
+            NodeData::Leaf {
+                size,
+                ref keys,
+                ref vals,
+            } => {
+                let size = usize::from(size);
+                let keys = keys.borrow();
+                let vals = vals.borrow();
+                // TODO: We could probably use `get_unchecked()` here since `size` is always in
+                // range.
+                (&keys[0..size], &vals[0..size])
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Unwrap a mutable leaf node into two slices (keys, values) of the same length.
+    pub fn unwrap_leaf_mut(&mut self) -> (&mut [F::Key], &mut [F::Value]) {
+        match *self {
+            NodeData::Leaf {
+                size,
+                ref mut keys,
+                ref mut vals,
+            } => {
+                let size = usize::from(size);
+                let keys = keys.borrow_mut();
+                let vals = vals.borrow_mut();
+                // TODO: We could probably use `get_unchecked_mut()` here since `size` is always in
+                // range.
+                (&mut keys[0..size], &mut vals[0..size])
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Get the critical key for a leaf node.
+    /// This is simply the first key.
+    pub fn leaf_crit_key(&self) -> F::Key {
+        match *self {
+            NodeData::Leaf { size, ref keys, .. } => {
+                debug_assert!(size > 0, "Empty leaf node");
+                keys.borrow()[0]
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Try to insert `(key, node)` at key-position `index` in an inner node.
+    /// This means that `key` is inserted at `keys[i]` and `node` is inserted at `tree[i + 1]`.
+    /// If the node is full, this leaves the node unchanged and returns false.
+    pub fn try_inner_insert(&mut self, index: usize, key: F::Key, node: Node) -> bool {
+        match *self {
+            NodeData::Inner {
+                ref mut size,
+                ref mut keys,
+                ref mut tree,
+            } => {
+                let sz = usize::from(*size);
+                debug_assert!(sz <= keys.len());
+                debug_assert!(index <= sz, "Can't insert at {} with {} keys", index, sz);
+
+                if let Some(ks) = keys.get_mut(0..sz + 1) {
+                    *size = (sz + 1) as u8;
+                    slice_insert(ks, index, key);
+                    slice_insert(&mut tree[1..sz + 2], index, node);
+                    true
+                } else {
+                    false
+                }
+            }
+            _ => panic!("Expected inner node"),
+        }
+    }
+
+    /// Try to insert `key, value` at `index` in a leaf node, but fail and return false if the node
+    /// is full.
+    pub fn try_leaf_insert(&mut self, index: usize, key: F::Key, value: F::Value) -> bool {
+        match *self {
+            NodeData::Leaf {
+                ref mut size,
+                ref mut keys,
+                ref mut vals,
+            } => {
+                let sz = usize::from(*size);
+                let keys = keys.borrow_mut();
+                let vals = vals.borrow_mut();
+                debug_assert!(sz <= keys.len());
+                debug_assert!(index <= sz);
+
+                if let Some(ks) = keys.get_mut(0..sz + 1) {
+                    *size = (sz + 1) as u8;
+                    slice_insert(ks, index, key);
+                    slice_insert(&mut vals[0..sz + 1], index, value);
+                    true
+                } else {
+                    false
+                }
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Split off the second half of this node.
+    /// It is assumed that this a completely full inner or leaf node.
+    ///
+    /// The `insert_index` parameter is the position where an insertion was tried and failed. The
+    /// node will be split in half with a bias towards an even split after the insertion is retried.
+    pub fn split(&mut self, insert_index: usize) -> SplitOff<F> {
+        match *self {
+            NodeData::Inner {
+                ref mut size,
+                ref keys,
+                ref tree,
+            } => {
+                debug_assert_eq!(usize::from(*size), keys.len(), "Node not full");
+
+                // Number of tree entries in the lhs node.
+                let l_ents = split_pos(tree.len(), insert_index + 1);
+                let r_ents = tree.len() - l_ents;
+
+                // With INNER_SIZE=8, we get l_ents=4 and:
+                //
+                // self: [ n0 k0 n1 k1 n2 k2 n3 k3 n4 k4 n5 k5 n6 k6 n7 ]
+                // lhs:  [ n0 k0 n1 k1 n2 k2 n3 ]
+                // crit_key = k3 (not present in either node)
+                // rhs:  [ n4 k4 n5 k5 n6 k6 n7 ]
+
+                // 1. Truncate the LHS.
+                *size = (l_ents - 1) as u8;
+
+                // 2. Copy second half to `rhs_data`.
+                let mut r_keys = *keys;
+                r_keys[0..r_ents - 1].copy_from_slice(&keys[l_ents..]);
+
+                let mut r_tree = *tree;
+                r_tree[0..r_ents].copy_from_slice(&tree[l_ents..]);
+
+                SplitOff {
+                    lhs_entries: l_ents,
+                    rhs_entries: r_ents,
+                    crit_key: keys[l_ents - 1],
+                    rhs_data: NodeData::Inner {
+                        size: (r_ents - 1) as u8,
+                        keys: r_keys,
+                        tree: r_tree,
+                    },
+                }
+            }
+            NodeData::Leaf {
+                ref mut size,
+                ref keys,
+                ref vals,
+            } => {
+                let o_keys = keys.borrow();
+                let o_vals = vals.borrow();
+                debug_assert_eq!(usize::from(*size), o_keys.len(), "Node not full");
+
+                let l_size = split_pos(o_keys.len(), insert_index);
+                let r_size = o_keys.len() - l_size;
+
+                // 1. Truncate the LHS node at `l_size`.
+                *size = l_size as u8;
+
+                // 2. Copy second half to `rhs_data`.
+                let mut r_keys = *keys;
+                r_keys.borrow_mut()[0..r_size].copy_from_slice(&o_keys[l_size..]);
+
+                let mut r_vals = *vals;
+                r_vals.borrow_mut()[0..r_size].copy_from_slice(&o_vals[l_size..]);
+
+                SplitOff {
+                    lhs_entries: l_size,
+                    rhs_entries: r_size,
+                    crit_key: o_keys[l_size],
+                    rhs_data: NodeData::Leaf {
+                        size: r_size as u8,
+                        keys: r_keys,
+                        vals: r_vals,
+                    },
+                }
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Remove the sub-tree at `index` from this inner node.
+    ///
+    /// Note that `index` refers to a sub-tree entry and not a key entry as it does for
+    /// `try_inner_insert()`. It is possible to remove the first sub-tree (which can't be inserted
+    /// by `try_inner_insert()`).
+    ///
+    /// Return an indication of the node's health (i.e. below half capacity).
+    pub fn inner_remove(&mut self, index: usize) -> Removed {
+        match *self {
+            NodeData::Inner {
+                ref mut size,
+                ref mut keys,
+                ref mut tree,
+            } => {
+                let ents = usize::from(*size) + 1;
+                debug_assert!(ents <= tree.len());
+                debug_assert!(index < ents);
+                // Leave an invalid 0xff size when node becomes empty.
+                *size = ents.wrapping_sub(2) as u8;
+                if ents > 1 {
+                    slice_shift(&mut keys[index.saturating_sub(1)..ents - 1], 1);
+                }
+                slice_shift(&mut tree[index..ents], 1);
+                Removed::new(index, ents - 1, tree.len())
+            }
+            _ => panic!("Expected inner node"),
+        }
+    }
+
+    /// Remove the key-value pair at `index` from this leaf node.
+    ///
+    /// Return an indication of the node's health (i.e. below half capacity).
+    pub fn leaf_remove(&mut self, index: usize) -> Removed {
+        match *self {
+            NodeData::Leaf {
+                ref mut size,
+                ref mut keys,
+                ref mut vals,
+            } => {
+                let sz = usize::from(*size);
+                let keys = keys.borrow_mut();
+                let vals = vals.borrow_mut();
+                *size -= 1;
+                slice_shift(&mut keys[index..sz], 1);
+                slice_shift(&mut vals[index..sz], 1);
+                Removed::new(index, sz - 1, keys.len())
+            }
+            _ => panic!("Expected leaf node"),
+        }
+    }
+
+    /// Balance this node with its right sibling.
+    ///
+    /// It is assumed that the current node has underflowed. Look at the right sibling node and do
+    /// one of two things:
+    ///
+    /// 1. Move all entries to the right node, leaving this node empty, or
+    /// 2. Distribute entries evenly between the two nodes.
+    ///
+    /// In the first case, `None` is returned. In the second case, the new critical key for the
+    /// right sibling node is returned.
+    pub fn balance(&mut self, crit_key: F::Key, rhs: &mut Self) -> Option<F::Key> {
+        match (self, rhs) {
+            (
+                &mut NodeData::Inner {
+                    size: ref mut l_size,
+                    keys: ref mut l_keys,
+                    tree: ref mut l_tree,
+                },
+                &mut NodeData::Inner {
+                    size: ref mut r_size,
+                    keys: ref mut r_keys,
+                    tree: ref mut r_tree,
+                },
+            ) => {
+                let l_ents = usize::from(*l_size) + 1;
+                let r_ents = usize::from(*r_size) + 1;
+                let ents = l_ents + r_ents;
+
+                if ents <= r_tree.len() {
+                    // All entries will fit in the RHS node.
+                    // We'll leave the LHS node empty, but first use it as a scratch space.
+                    *l_size = 0;
+                    // Insert `crit_key` between the two nodes.
+                    l_keys[l_ents - 1] = crit_key;
+                    l_keys[l_ents..ents - 1].copy_from_slice(&r_keys[0..r_ents - 1]);
+                    r_keys[0..ents - 1].copy_from_slice(&l_keys[0..ents - 1]);
+                    l_tree[l_ents..ents].copy_from_slice(&r_tree[0..r_ents]);
+                    r_tree[0..ents].copy_from_slice(&l_tree[0..ents]);
+                    *r_size = (ents - 1) as u8;
+                    None
+                } else {
+                    // The entries don't all fit in one node. Distribute some from RHS -> LHS.
+                    // Split evenly with a bias to putting one entry in LHS.
+                    let r_goal = ents / 2;
+                    let l_goal = ents - r_goal;
+                    debug_assert!(l_goal > l_ents, "Node must be underflowed");
+
+                    l_keys[l_ents - 1] = crit_key;
+                    l_keys[l_ents..l_goal - 1].copy_from_slice(&r_keys[0..l_goal - 1 - l_ents]);
+                    l_tree[l_ents..l_goal].copy_from_slice(&r_tree[0..l_goal - l_ents]);
+                    *l_size = (l_goal - 1) as u8;
+
+                    let new_crit = r_keys[r_ents - r_goal - 1];
+                    slice_shift(&mut r_keys[0..r_ents - 1], r_ents - r_goal);
+                    slice_shift(&mut r_tree[0..r_ents], r_ents - r_goal);
+                    *r_size = (r_goal - 1) as u8;
+
+                    Some(new_crit)
+                }
+            }
+            (
+                &mut NodeData::Leaf {
+                    size: ref mut l_size,
+                    keys: ref mut l_keys,
+                    vals: ref mut l_vals,
+                },
+                &mut NodeData::Leaf {
+                    size: ref mut r_size,
+                    keys: ref mut r_keys,
+                    vals: ref mut r_vals,
+                },
+            ) => {
+                let l_ents = usize::from(*l_size);
+                let l_keys = l_keys.borrow_mut();
+                let l_vals = l_vals.borrow_mut();
+                let r_ents = usize::from(*r_size);
+                let r_keys = r_keys.borrow_mut();
+                let r_vals = r_vals.borrow_mut();
+                let ents = l_ents + r_ents;
+
+                if ents <= r_vals.len() {
+                    // We can fit all entries in the RHS node.
+                    // We'll leave the LHS node empty, but first use it as a scratch space.
+                    *l_size = 0;
+                    l_keys[l_ents..ents].copy_from_slice(&r_keys[0..r_ents]);
+                    r_keys[0..ents].copy_from_slice(&l_keys[0..ents]);
+                    l_vals[l_ents..ents].copy_from_slice(&r_vals[0..r_ents]);
+                    r_vals[0..ents].copy_from_slice(&l_vals[0..ents]);
+                    *r_size = ents as u8;
+                    None
+                } else {
+                    // The entries don't all fit in one node. Distribute some from RHS -> LHS.
+                    // Split evenly with a bias to putting one entry in LHS.
+                    let r_goal = ents / 2;
+                    let l_goal = ents - r_goal;
+                    debug_assert!(l_goal > l_ents, "Node must be underflowed");
+
+                    l_keys[l_ents..l_goal].copy_from_slice(&r_keys[0..l_goal - l_ents]);
+                    l_vals[l_ents..l_goal].copy_from_slice(&r_vals[0..l_goal - l_ents]);
+                    *l_size = l_goal as u8;
+
+                    slice_shift(&mut r_keys[0..r_ents], r_ents - r_goal);
+                    slice_shift(&mut r_vals[0..r_ents], r_ents - r_goal);
+                    *r_size = r_goal as u8;
+
+                    Some(r_keys[0])
+                }
+            }
+            _ => panic!("Mismatched nodes"),
+        }
+    }
+}
+
+/// Find the right split position for halving a full node with `len` entries to recover from a
+/// failed insertion at `ins`.
+///
+/// If `len` is even, we should split straight down the middle regardless of `len`.
+///
+/// If `len` is odd, we should split the node such that the two halves are the same size after the
+/// insertion is retried.
+fn split_pos(len: usize, ins: usize) -> usize {
+    // Anticipate `len` being a compile time constant, so this all folds away when `len` is even.
+    if ins <= len / 2 {
+        len / 2
+    } else {
+        (len + 1) / 2
+    }
+}
+
+/// The result of splitting off the second half of a node.
+pub(super) struct SplitOff<F: Forest> {
+    /// The number of entries left in the original node which becomes the left-hand-side of the
+    /// pair. This is the number of outgoing node edges for an inner node, and the number of
+    /// key-value pairs for a leaf node.
+    pub lhs_entries: usize,
+
+    /// The number of entries in the new RHS node.
+    pub rhs_entries: usize,
+
+    /// The critical key separating the LHS and RHS nodes. All keys in the LHS sub-tree are less
+    /// than the critical key, and all entries in the RHS sub-tree are greater or equal to the
+    /// critical key.
+    pub crit_key: F::Key,
+
+    /// The RHS node data containing the elements that were removed from the original node (now the
+    /// LHS).
+    pub rhs_data: NodeData<F>,
+}
+
+/// The result of removing an entry from a node.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(super) enum Removed {
+    /// An entry was removed, and the node is still in good shape.
+    Healthy,
+
+    /// The node is in good shape after removing the rightmost element.
+    Rightmost,
+
+    /// The node has too few entries now, and it should be balanced with a sibling node.
+    Underflow,
+
+    /// The last entry was removed. For an inner node, this means that the `keys` array is empty
+    /// and there is just a single sub-tree left.
+    Empty,
+}
+
+impl Removed {
+    /// Create a `Removed` status from a size and capacity.
+    fn new(removed: usize, new_size: usize, capacity: usize) -> Self {
+        if 2 * new_size >= capacity {
+            if removed == new_size {
+                Removed::Rightmost
+            } else {
+                Removed::Healthy
+            }
+        } else if new_size > 0 {
+            Removed::Underflow
+        } else {
+            Removed::Empty
+        }
+    }
+}
+
+// Display ": value" or nothing at all for `()`.
+pub(super) trait ValDisp {
+    fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
+}
+
+impl ValDisp for SetValue {
+    fn valfmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+        Ok(())
+    }
+}
+
+impl<T: fmt::Display> ValDisp for T {
+    fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, ":{}", self)
+    }
+}
+
+impl<F> fmt::Display for NodeData<F>
+where
+    F: Forest,
+    F::Key: fmt::Display,
+    F::Value: ValDisp,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            NodeData::Inner { size, keys, tree } => {
+                write!(f, "[ {}", tree[0])?;
+                for i in 0..usize::from(size) {
+                    write!(f, " {} {}", keys[i], tree[i + 1])?;
+                }
+                write!(f, " ]")
+            }
+            NodeData::Leaf { size, keys, vals } => {
+                let keys = keys.borrow();
+                let vals = vals.borrow();
+                write!(f, "[")?;
+                for i in 0..usize::from(size) {
+                    write!(f, " {}", keys[i])?;
+                    vals[i].valfmt(f)?;
+                }
+                write!(f, " ]")
+            }
+            NodeData::Free { next: Some(n) } => write!(f, "[ free -> {} ]", n),
+            NodeData::Free { next: None } => write!(f, "[ free ]"),
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::mem;
+    use std::string::ToString;
+
+    // Forest impl for a set implementation.
+    struct TF();
+
+    impl Forest for TF {
+        type Key = char;
+        type Value = SetValue;
+        type LeafKeys = [char; 15];
+        type LeafValues = [SetValue; 15];
+
+        fn splat_key(key: Self::Key) -> Self::LeafKeys {
+            [key; 15]
+        }
+
+        fn splat_value(value: Self::Value) -> Self::LeafValues {
+            [value; 15]
+        }
+    }
+
+    #[test]
+    fn inner() {
+        let n1 = Node(1);
+        let n2 = Node(2);
+        let n3 = Node(3);
+        let n4 = Node(4);
+        let mut inner = NodeData::<TF>::inner(n1, 'c', n4);
+        assert_eq!(mem::size_of_val(&inner), 64);
+        assert_eq!(inner.to_string(), "[ node1 c node4 ]");
+
+        assert!(inner.try_inner_insert(0, 'a', n2));
+        assert_eq!(inner.to_string(), "[ node1 a node2 c node4 ]");
+
+        assert!(inner.try_inner_insert(1, 'b', n3));
+        assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
+
+        for i in 3..7 {
+            assert!(inner.try_inner_insert(
+                usize::from(i),
+                ('a' as u8 + i) as char,
+                Node(i as u32 + 2),
+            ));
+        }
+        assert_eq!(
+            inner.to_string(),
+            "[ node1 a node2 b node3 c node4 d node5 e node6 f node7 g node8 ]"
+        );
+
+        // Now the node is full and insertion should fail anywhere.
+        assert!(!inner.try_inner_insert(0, 'x', n3));
+        assert!(!inner.try_inner_insert(4, 'x', n3));
+        assert!(!inner.try_inner_insert(7, 'x', n3));
+
+        // Splitting should be independent of the hint because we have an even number of node
+        // references.
+        let saved = inner.clone();
+        let sp = inner.split(1);
+        assert_eq!(sp.lhs_entries, 4);
+        assert_eq!(sp.rhs_entries, 4);
+        assert_eq!(sp.crit_key, 'd');
+        // The critical key is not present in either of the resulting nodes.
+        assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
+        assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");
+
+        assert_eq!(inner.inner_remove(0), Removed::Underflow);
+        assert_eq!(inner.to_string(), "[ node2 b node3 c node4 ]");
+
+        assert_eq!(inner.inner_remove(1), Removed::Underflow);
+        assert_eq!(inner.to_string(), "[ node2 c node4 ]");
+
+        assert_eq!(inner.inner_remove(1), Removed::Underflow);
+        assert_eq!(inner.to_string(), "[ node2 ]");
+
+        assert_eq!(inner.inner_remove(0), Removed::Empty);
+
+        inner = saved;
+        let sp = inner.split(6);
+        assert_eq!(sp.lhs_entries, 4);
+        assert_eq!(sp.rhs_entries, 4);
+        assert_eq!(sp.crit_key, 'd');
+        assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
+        assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");
+    }
+
+    #[test]
+    fn leaf() {
+        let mut leaf = NodeData::<TF>::leaf('d', SetValue());
+        assert_eq!(leaf.to_string(), "[ d ]");
+
+        assert!(leaf.try_leaf_insert(0, 'a', SetValue()));
+        assert_eq!(leaf.to_string(), "[ a d ]");
+        assert!(leaf.try_leaf_insert(1, 'b', SetValue()));
+        assert!(leaf.try_leaf_insert(2, 'c', SetValue()));
+        assert_eq!(leaf.to_string(), "[ a b c d ]");
+        for i in 4..15 {
+            assert!(leaf.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));
+        }
+        assert_eq!(leaf.to_string(), "[ a b c d e f g h i j k l m n o ]");
+
+        // Now the node is full and insertion should fail anywhere.
+        assert!(!leaf.try_leaf_insert(0, 'x', SetValue()));
+        assert!(!leaf.try_leaf_insert(8, 'x', SetValue()));
+        assert!(!leaf.try_leaf_insert(15, 'x', SetValue()));
+
+        // The index given to `split` is not the split position, it's a hint for balancing the node.
+        let saved = leaf.clone();
+        let sp = leaf.split(12);
+        assert_eq!(sp.lhs_entries, 8);
+        assert_eq!(sp.rhs_entries, 7);
+        assert_eq!(sp.crit_key, 'i');
+        assert_eq!(leaf.to_string(), "[ a b c d e f g h ]");
+        assert_eq!(sp.rhs_data.to_string(), "[ i j k l m n o ]");
+
+        assert!(leaf.try_leaf_insert(8, 'i', SetValue()));
+        assert_eq!(leaf.leaf_remove(2), Removed::Healthy);
+        assert_eq!(leaf.to_string(), "[ a b d e f g h i ]");
+        assert_eq!(leaf.leaf_remove(7), Removed::Underflow);
+        assert_eq!(leaf.to_string(), "[ a b d e f g h ]");
+
+        leaf = saved;
+        let sp = leaf.split(7);
+        assert_eq!(sp.lhs_entries, 7);
+        assert_eq!(sp.rhs_entries, 8);
+        assert_eq!(sp.crit_key, 'h');
+        assert_eq!(leaf.to_string(), "[ a b c d e f g ]");
+        assert_eq!(sp.rhs_data.to_string(), "[ h i j k l m n o ]");
+    }
+
+    #[test]
+    fn optimal_split_pos() {
+        // An even split is easy.
+        assert_eq!(split_pos(8, 0), 4);
+        assert_eq!(split_pos(8, 8), 4);
+
+        // Easy cases for odd splits.
+        assert_eq!(split_pos(7, 0), 3);
+        assert_eq!(split_pos(7, 7), 4);
+
+        // If the insertion point is the same as the split position, we
+        // will append to the lhs node.
+        assert_eq!(split_pos(7, 3), 3);
+        assert_eq!(split_pos(7, 4), 4);
+    }
+
+    #[test]
+    fn inner_balance() {
+        let n1 = Node(1);
+        let n2 = Node(2);
+        let n3 = Node(3);
+        let mut lhs = NodeData::<TF>::inner(n1, 'a', n2);
+        assert!(lhs.try_inner_insert(1, 'b', n3));
+        assert_eq!(lhs.to_string(), "[ node1 a node2 b node3 ]");
+
+        let n11 = Node(11);
+        let n12 = Node(12);
+        let mut rhs = NodeData::<TF>::inner(n11, 'p', n12);
+
+        for i in 1..4 {
+            assert!(rhs.try_inner_insert(
+                usize::from(i),
+                ('p' as u8 + i) as char,
+                Node(i as u32 + 12),
+            ));
+        }
+        assert_eq!(
+            rhs.to_string(),
+            "[ node11 p node12 q node13 r node14 s node15 ]"
+        );
+
+        // 3+5 elements fit in RHS.
+        assert_eq!(lhs.balance('o', &mut rhs), None);
+        assert_eq!(
+            rhs.to_string(),
+            "[ node1 a node2 b node3 o node11 p node12 q node13 r node14 s node15 ]"
+        );
+
+        // 2+8 elements are redistributed.
+        lhs = NodeData::<TF>::inner(Node(20), 'x', Node(21));
+        assert_eq!(lhs.balance('y', &mut rhs), Some('o'));
+        assert_eq!(
+            lhs.to_string(),
+            "[ node20 x node21 y node1 a node2 b node3 ]"
+        );
+        assert_eq!(
+            rhs.to_string(),
+            "[ node11 p node12 q node13 r node14 s node15 ]"
+        );
+    }
+
+    #[test]
+    fn leaf_balance() {
+        let mut lhs = NodeData::<TF>::leaf('a', SetValue());
+        for i in 1..6 {
+            assert!(lhs.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));
+        }
+        assert_eq!(lhs.to_string(), "[ a b c d e f ]");
+
+        let mut rhs = NodeData::<TF>::leaf('0', SetValue());
+        for i in 1..8 {
+            assert!(rhs.try_leaf_insert(usize::from(i), ('0' as u8 + i) as char, SetValue()));
+        }
+        assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");
+
+        // 6+8 elements all fits in rhs.
+        assert_eq!(lhs.balance('0', &mut rhs), None);
+        assert_eq!(rhs.to_string(), "[ a b c d e f 0 1 2 3 4 5 6 7 ]");
+
+        assert!(lhs.try_leaf_insert(0, 'x', SetValue()));
+        assert!(lhs.try_leaf_insert(1, 'y', SetValue()));
+        assert!(lhs.try_leaf_insert(2, 'z', SetValue()));
+        assert_eq!(lhs.to_string(), "[ x y z ]");
+
+        // 3+14 elements need redistribution.
+        assert_eq!(lhs.balance('a', &mut rhs), Some('0'));
+        assert_eq!(lhs.to_string(), "[ x y z a b c d e f ]");
+        assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/path.rs
@@ -0,0 +1,836 @@
+//! A path from the root of a B+-tree to a leaf node.
+
+use super::node::Removed;
+use super::{slice_insert, slice_shift, Comparator, Forest, Node, NodeData, NodePool, MAX_PATH};
+use std::borrow::Borrow;
+use std::marker::PhantomData;
+
+#[cfg(test)]
+use std::fmt;
+
+pub(super) struct Path<F: Forest> {
+    /// Number of path entries including the root and leaf nodes.
+    size: usize,
+
+    /// Path of node references from the root to a leaf node.
+    node: [Node; MAX_PATH],
+
+    /// Entry number in each node.
+    entry: [u8; MAX_PATH],
+
+    unused: PhantomData<F>,
+}
+
+impl<F: Forest> Default for Path<F> {
+    fn default() -> Self {
+        Self {
+            size: 0,
+            node: [Node(0); MAX_PATH],
+            entry: [0; MAX_PATH],
+            unused: PhantomData,
+        }
+    }
+}
+
+impl<F: Forest> Path<F> {
+    /// Reset path by searching for `key` starting from `root`.
+    ///
+    /// If `key` is in the tree, returns the corresponding value and leaved the path pointing at
+    /// the entry. Otherwise returns `None` and:
+    ///
+    /// - A key smaller than all stored keys returns a path to the first entry of the first leaf.
+    /// - A key larger than all stored keys returns a path to one beyond the last element of the
+    ///   last leaf.
+    /// - A key between the stored keys of adjacent leaf nodes returns a path to one beyond the
+    ///   last entry of the first of the leaf nodes.
+    ///
+    pub fn find(
+        &mut self,
+        key: F::Key,
+        root: Node,
+        pool: &NodePool<F>,
+        comp: &Comparator<F::Key>,
+    ) -> Option<F::Value> {
+        let mut node = root;
+        for level in 0.. {
+            self.size = level + 1;
+            self.node[level] = node;
+            match pool[node] {
+                NodeData::Inner { size, keys, tree } => {
+                    // Invariant: `tree[i]` contains keys smaller than
+                    // `keys[i]`, greater or equal to `keys[i-1]`.
+                    let i = match comp.search(key, &keys[0..size.into()]) {
+                        // We hit an existing key, so follow the >= branch.
+                        Ok(i) => i + 1,
+                        // Key is less than `keys[i]`, so follow the < branch.
+                        Err(i) => i,
+                    };
+                    self.entry[level] = i as u8;
+                    node = tree[i];
+                }
+                NodeData::Leaf { size, keys, vals } => {
+                    // For a leaf we want either the found key or an insert position.
+                    return match comp.search(key, &keys.borrow()[0..size.into()]) {
+                        Ok(i) => {
+                            self.entry[level] = i as u8;
+                            Some(vals.borrow()[i])
+                        }
+                        Err(i) => {
+                            self.entry[level] = i as u8;
+                            None
+                        }
+                    };
+                }
+                NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
+            }
+        }
+        unreachable!();
+    }
+
+    /// Move path to the first entry of the tree starting at `root` and return it.
+    pub fn first(&mut self, root: Node, pool: &NodePool<F>) -> (F::Key, F::Value) {
+        let mut node = root;
+        for level in 0.. {
+            self.size = level + 1;
+            self.node[level] = node;
+            self.entry[level] = 0;
+            match pool[node] {
+                NodeData::Inner { tree, .. } => node = tree[0],
+                NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]),
+                NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
+            }
+        }
+        unreachable!();
+    }
+
+    /// Move this path to the next key-value pair and return it.
+    pub fn next(&mut self, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {
+        match self.leaf_pos() {
+            None => return None,
+            Some((node, entry)) => {
+                let (keys, vals) = pool[node].unwrap_leaf();
+                if entry + 1 < keys.len() {
+                    self.entry[self.size - 1] += 1;
+                    return Some((keys[entry + 1], vals[entry + 1]));
+                }
+            }
+        }
+
+        // The current leaf node is exhausted. Move to the next one.
+        let leaf_level = self.size - 1;
+        self.next_node(leaf_level, pool).map(|node| {
+            let (keys, vals) = pool[node].unwrap_leaf();
+            (keys[0], vals[0])
+        })
+    }
+
+    /// Move this path to the previous key-value pair and return it.
+    ///
+    /// If the path is at the off-the-end position, go to the last key-value pair.
+    ///
+    /// If the path is already at the first key-value pair, leave it there and return `None`.
+    pub fn prev(&mut self, root: Node, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {
+        // We use `size == 0` as a generic off-the-end position.
+        if self.size == 0 {
+            self.goto_subtree_last(0, root, pool);
+            let (node, entry) = self.leaf_pos().unwrap();
+            let (keys, vals) = pool[node].unwrap_leaf();
+            return Some((keys[entry], vals[entry]));
+        }
+
+        match self.leaf_pos() {
+            None => return None,
+            Some((node, entry)) => {
+                if entry > 0 {
+                    self.entry[self.size - 1] -= 1;
+                    let (keys, vals) = pool[node].unwrap_leaf();
+                    return Some((keys[entry - 1], vals[entry - 1]));
+                }
+            }
+        }
+
+        // The current leaf node is exhausted. Move to the previous one.
+        self.prev_leaf(pool).map(|node| {
+            let (keys, vals) = pool[node].unwrap_leaf();
+            let e = self.leaf_entry();
+            (keys[e], vals[e])
+        })
+    }
+
+    /// Move path to the first entry of the next node at level, if one exists.
+    ///
+    /// Returns the new node if it exists.
+    ///
+    /// Reset the path to `size = 0` and return `None` if there is no next node.
+    fn next_node(&mut self, level: usize, pool: &NodePool<F>) -> Option<Node> {
+        match self.right_sibling_branch_level(level, pool) {
+            None => {
+                self.size = 0;
+                None
+            }
+            Some(bl) => {
+                let (_, bnodes) = pool[self.node[bl]].unwrap_inner();
+                self.entry[bl] += 1;
+                let mut node = bnodes[usize::from(self.entry[bl])];
+
+                for l in bl + 1..level {
+                    self.node[l] = node;
+                    self.entry[l] = 0;
+                    node = pool[node].unwrap_inner().1[0];
+                }
+
+                self.node[level] = node;
+                self.entry[level] = 0;
+                Some(node)
+            }
+        }
+    }
+
+    /// Move the path to the last entry of the previous leaf node, if one exists.
+    ///
+    /// Returns the new leaf node if it exists.
+    ///
+    /// Leave the path unchanged and returns `None` if we are already at the first leaf node.
+    fn prev_leaf(&mut self, pool: &NodePool<F>) -> Option<Node> {
+        self.left_sibling_branch_level(self.size - 1).map(|bl| {
+            let entry = self.entry[bl] - 1;
+            self.entry[bl] = entry;
+            let (_, bnodes) = pool[self.node[bl]].unwrap_inner();
+            self.goto_subtree_last(bl + 1, bnodes[usize::from(entry)], pool)
+        })
+    }
+
+    /// Move this path to the last position for the sub-tree at `level, root`.
+    fn goto_subtree_last(&mut self, level: usize, root: Node, pool: &NodePool<F>) -> Node {
+        let mut node = root;
+        for l in level.. {
+            self.node[l] = node;
+            match pool[node] {
+                NodeData::Inner { size, ref tree, .. } => {
+                    self.entry[l] = size;
+                    node = tree[usize::from(size)];
+                }
+                NodeData::Leaf { size, .. } => {
+                    self.entry[l] = size - 1;
+                    self.size = l + 1;
+                    break;
+                }
+                NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
+            }
+        }
+        node
+    }
+
+    /// Set the root node and point the path at the first entry of the node.
+    pub fn set_root_node(&mut self, root: Node) {
+        self.size = 1;
+        self.node[0] = root;
+        self.entry[0] = 0;
+    }
+
+    /// Get the current leaf node and entry, if any.
+    pub fn leaf_pos(&self) -> Option<(Node, usize)> {
+        let i = self.size.wrapping_sub(1);
+        self.node.get(i).map(|&n| (n, self.entry[i].into()))
+    }
+
+    /// Get the current leaf node.
+    fn leaf_node(&self) -> Node {
+        self.node[self.size - 1]
+    }
+
+    /// Get the current entry in the leaf node.
+    fn leaf_entry(&self) -> usize {
+        self.entry[self.size - 1].into()
+    }
+
+    /// Is this path pointing to the first entry in the tree?
+    /// This corresponds to the smallest key.
+    fn at_first_entry(&self) -> bool {
+        self.entry[0..self.size].iter().all(|&i| i == 0)
+    }
+
+    /// Get a mutable reference to the current value.
+    /// This assumes that there is a current value.
+    pub fn value_mut<'a>(&self, pool: &'a mut NodePool<F>) -> &'a mut F::Value {
+        &mut pool[self.leaf_node()].unwrap_leaf_mut().1[self.leaf_entry()]
+    }
+
+    /// Insert the key-value pair at the current position.
+    /// The current position must be the correct insertion location for the key.
+    /// This function does not check for duplicate keys. Use `find` or similar for that.
+    /// Returns the new root node.
+    pub fn insert(&mut self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> Node {
+        if !self.try_leaf_insert(key, value, pool) {
+            self.split_and_insert(key, value, pool);
+        }
+        self.node[0]
+    }
+
+    /// Try to insert `key, value` at the current position, but fail and return false if the leaf
+    /// node is full.
+    fn try_leaf_insert(&self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> bool {
+        let index = self.leaf_entry();
+
+        // The case `index == 0` should only ever happen when there are no earlier leaf nodes,
+        // otherwise we should have appended to the previous leaf node instead. This invariant
+        // means that we don't need to update keys stored in inner nodes here.
+        debug_assert!(index > 0 || self.at_first_entry());
+
+        pool[self.leaf_node()].try_leaf_insert(index, key, value)
+    }
+
+    /// Split the current leaf node and then insert `key, value`.
+    /// This should only be used if `try_leaf_insert()` fails.
+    fn split_and_insert(&mut self, mut key: F::Key, value: F::Value, pool: &mut NodePool<F>) {
+        let orig_root = self.node[0];
+
+        // Loop invariant: We need to split the node at `level` and then retry a failed insertion.
+        // The items to insert are either `(key, ins_node)` or `(key, value)`.
+        let mut ins_node = None;
+        let mut split;
+        for level in (0..self.size).rev() {
+            // Split the current node.
+            let mut node = self.node[level];
+            let mut entry = self.entry[level].into();
+            split = pool[node].split(entry);
+            let rhs_node = pool.alloc_node(split.rhs_data);
+
+            // Should the path be moved to the new RHS node?
+            // Prefer the smaller node if we're right in the middle.
+            // Prefer to append to LHS all other things being equal.
+            //
+            // When inserting into an inner node (`ins_node.is_some()`), we must point to a valid
+            // entry in the current node since the new entry is inserted *after* the insert
+            // location.
+            if entry > split.lhs_entries
+                || (entry == split.lhs_entries
+                    && (split.lhs_entries > split.rhs_entries || ins_node.is_some()))
+            {
+                node = rhs_node;
+                entry -= split.lhs_entries;
+                self.node[level] = node;
+                self.entry[level] = entry as u8;
+            }
+
+            // Now that we have a not-full node, it must be possible to insert.
+            match ins_node {
+                None => {
+                    let inserted = pool[node].try_leaf_insert(entry, key, value);
+                    debug_assert!(inserted);
+                    // If we inserted at the front of the new rhs_node leaf, we need to propagate
+                    // the inserted key as the critical key instead of the previous front key.
+                    if entry == 0 && node == rhs_node {
+                        split.crit_key = key;
+                    }
+                }
+                Some(n) => {
+                    let inserted = pool[node].try_inner_insert(entry, key, n);
+                    debug_assert!(inserted);
+                    // The lower level was moved to the new RHS node, so make sure that is
+                    // reflected here.
+                    if n == self.node[level + 1] {
+                        self.entry[level] += 1;
+                    }
+                }
+            }
+
+            // We are now done with the current level, but `rhs_node` must be inserted in the inner
+            // node above us. If we're already at level 0, the root node needs to be split.
+            key = split.crit_key;
+            ins_node = Some(rhs_node);
+            if level > 0 {
+                let pnode = &mut pool[self.node[level - 1]];
+                let pentry = self.entry[level - 1].into();
+                if pnode.try_inner_insert(pentry, key, rhs_node) {
+                    // If this level level was moved to the new RHS node, update parent entry.
+                    if node == rhs_node {
+                        self.entry[level - 1] += 1;
+                    }
+                    return;
+                }
+            }
+        }
+
+        // If we get here we have split the original root node and need to add an extra level.
+        let rhs_node = ins_node.expect("empty path");
+        let root = pool.alloc_node(NodeData::inner(orig_root, key, rhs_node));
+        let entry = if self.node[0] == rhs_node { 1 } else { 0 };
+        self.size += 1;
+        slice_insert(&mut self.node[0..self.size], 0, root);
+        slice_insert(&mut self.entry[0..self.size], 0, entry);
+    }
+
+    /// Remove the key-value pair at the current position and advance the path to the next
+    /// key-value pair, leaving the path in a normalized state.
+    ///
+    /// Return the new root node.
+    pub fn remove(&mut self, pool: &mut NodePool<F>) -> Option<Node> {
+        let e = self.leaf_entry();
+        match pool[self.leaf_node()].leaf_remove(e) {
+            Removed::Healthy => {
+                if e == 0 {
+                    self.update_crit_key(pool)
+                }
+                Some(self.node[0])
+            }
+            status => self.balance_nodes(status, pool),
+        }
+    }
+
+    /// Get the critical key for the current node at `level`.
+    ///
+    /// The critical key is less than or equal to all keys in the sub-tree at `level` and greater
+    /// than all keys to the left of the current node at `level`.
+    ///
+    /// The left-most node at any level does not have a critical key.
+    fn current_crit_key(&self, level: usize, pool: &NodePool<F>) -> Option<F::Key> {
+        // Find the level containing the critical key for the current node.
+        self.left_sibling_branch_level(level).map(|bl| {
+            let (keys, _) = pool[self.node[bl]].unwrap_inner();
+            keys[usize::from(self.entry[bl]) - 1]
+        })
+    }
+
+    /// Update the critical key after removing the front entry of the leaf node.
+    fn update_crit_key(&mut self, pool: &mut NodePool<F>) {
+        // Find the inner level containing the critical key for the current leaf node.
+        let crit_level = match self.left_sibling_branch_level(self.size - 1) {
+            None => return,
+            Some(l) => l,
+        };
+        let crit_kidx = self.entry[crit_level] - 1;
+
+        // Extract the new critical key from the leaf node.
+        let crit_key = pool[self.leaf_node()].leaf_crit_key();
+        let crit_node = self.node[crit_level];
+
+        match pool[crit_node] {
+            NodeData::Inner {
+                size, ref mut keys, ..
+            } => {
+                debug_assert!(crit_kidx < size);
+                keys[usize::from(crit_kidx)] = crit_key;
+            }
+            _ => panic!("Expected inner node"),
+        }
+    }
+
+    /// Given that the current leaf node is in an unhealthy (underflowed or even empty) status,
+    /// balance it with sibling nodes.
+    ///
+    /// Return the new root node.
+    fn balance_nodes(&mut self, status: Removed, pool: &mut NodePool<F>) -> Option<Node> {
+        // The current leaf node is not in a healthy state, and its critical key may have changed
+        // too.
+        //
+        // Start by dealing with a changed critical key for the leaf level.
+        if status != Removed::Empty && self.leaf_entry() == 0 {
+            self.update_crit_key(pool);
+        }
+
+        let leaf_level = self.size - 1;
+        if self.heal_level(status, leaf_level, pool) {
+            // Tree has become empty.
+            self.size = 0;
+            return None;
+        }
+
+        // Discard the root node if it has shrunk to a single sub-tree.
+        let mut ns = 0;
+        while let NodeData::Inner {
+            size: 0, ref tree, ..
+        } = pool[self.node[ns]]
+        {
+            ns += 1;
+            self.node[ns] = tree[0];
+        }
+
+        if ns > 0 {
+            for l in 0..ns {
+                pool.free_node(self.node[l]);
+            }
+
+            // Shift the whole array instead of just 0..size because `self.size` may be cleared
+            // here if the path is pointing off-the-end.
+            slice_shift(&mut self.node, ns);
+            slice_shift(&mut self.entry, ns);
+
+            if self.size > 0 {
+                self.size -= ns;
+            }
+        }
+
+        // Return the root node, even when `size=0` indicating that we're at the off-the-end
+        // position.
+        Some(self.node[0])
+    }
+
+    /// After removing an entry from the node at `level`, check its health and rebalance as needed.
+    ///
+    /// Leave the path up to and including `level` in a normalized state where all entries are in
+    /// bounds.
+    ///
+    /// Returns true if the tree becomes empty.
+    fn heal_level(&mut self, status: Removed, level: usize, pool: &mut NodePool<F>) -> bool {
+        match status {
+            Removed::Healthy => {}
+            Removed::Rightmost => {
+                // The rightmost entry was removed from the curent node, so move the path so it
+                // points at the first entry of the next node at this level.
+                debug_assert_eq!(
+                    usize::from(self.entry[level]),
+                    pool[self.node[level]].entries()
+                );
+                self.next_node(level, pool);
+            }
+            Removed::Underflow => self.underflowed_node(level, pool),
+            Removed::Empty => return self.empty_node(level, pool),
+        }
+        false
+    }
+
+    /// The current node at `level` has underflowed, meaning that it is below half capacity but
+    /// not completely empty.
+    ///
+    /// Handle this by balancing entries with the right sibling node.
+    ///
+    /// Leave the path up to and including `level` in a valid state that points to the same entry.
+    fn underflowed_node(&mut self, level: usize, pool: &mut NodePool<F>) {
+        // Look for a right sibling node at this level. If none exists, we allow the underflowed
+        // node to persist as the right-most node at its level.
+        if let Some((crit_key, rhs_node)) = self.right_sibling(level, pool) {
+            // New critical key for the updated right sibling node.
+            let new_ck: Option<F::Key>;
+            let empty;
+            // Make a COPY of the sibling node to avoid fighting the borrow checker.
+            let mut rhs = pool[rhs_node];
+            match pool[self.node[level]].balance(crit_key, &mut rhs) {
+                None => {
+                    // Everything got moved to the RHS node.
+                    new_ck = self.current_crit_key(level, pool);
+                    empty = true;
+                }
+                Some(key) => {
+                    // Entries moved from RHS node.
+                    new_ck = Some(key);
+                    empty = false;
+                }
+            }
+            // Put back the updated RHS node data.
+            pool[rhs_node] = rhs;
+            // Update the critical key for the RHS node unless it has become a left-most
+            // node.
+            if let Some(ck) = new_ck {
+                self.update_right_crit_key(level, ck, pool);
+            }
+            if empty {
+                let empty_tree = self.empty_node(level, pool);
+                debug_assert!(!empty_tree);
+            }
+
+            // Any Removed::Rightmost state must have been cleared above by merging nodes. If the
+            // current entry[level] was one off the end of the node, it will now point at a proper
+            // entry.
+            debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries());
+        } else if usize::from(self.entry[level]) >= pool[self.node[level]].entries() {
+            // There's no right sibling at this level, so the node can't be rebalanced.
+            // Check if we are in an off-the-end position.
+            self.size = 0;
+        }
+    }
+
+    /// The current node at `level` has become empty.
+    ///
+    /// Remove the node from its parent node and leave the path in a normalized state. This means
+    /// that the path at this level will go through the right sibling of this node.
+    ///
+    /// If the current node has no right sibling, set `self.size = 0`.
+    ///
+    /// Returns true if the tree becomes empty.
+    fn empty_node(&mut self, level: usize, pool: &mut NodePool<F>) -> bool {
+        pool.free_node(self.node[level]);
+        if level == 0 {
+            // We just deleted the root node, so the tree is now empty.
+            return true;
+        }
+
+        // Get the right sibling node before recursively removing nodes.
+        let rhs_node = self.right_sibling(level, pool).map(|(_, n)| n);
+
+        // Remove the current sub-tree from the parent node.
+        let pl = level - 1;
+        let pe = self.entry[pl].into();
+        let status = pool[self.node[pl]].inner_remove(pe);
+        self.heal_level(status, pl, pool);
+
+        // Finally update the path at this level.
+        match rhs_node {
+            // We'll leave `self.entry[level]` unchanged. It can be non-zero after moving node
+            // entries to the right sibling node.
+            Some(rhs) => self.node[level] = rhs,
+            // We have no right sibling, so we must have deleted the right-most
+            // entry. The path should be moved to the "off-the-end" position.
+            None => self.size = 0,
+        }
+        false
+    }
+
+    /// Find the level where the right sibling to the current node at `level` branches off.
+    ///
+    /// This will be an inner node with two adjacent sub-trees: In one the current node at level is
+    /// a right-most node, in the other, the right sibling is a left-most node.
+    ///
+    /// Returns `None` if the current node is a right-most node so no right sibling exists.
+    fn right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize> {
+        (0..level).rposition(|l| match pool[self.node[l]] {
+            NodeData::Inner { size, .. } => self.entry[l] < size,
+            _ => panic!("Expected inner node"),
+        })
+    }
+
+    /// Find the level where the left sibling to the current node at `level` branches off.
+    fn left_sibling_branch_level(&self, level: usize) -> Option<usize> {
+        self.entry[0..level].iter().rposition(|&e| e != 0)
+    }
+
+    /// Get the right sibling node to the current node at `level`.
+    /// Also return the critical key between the current node and the right sibling.
+    fn right_sibling(&self, level: usize, pool: &NodePool<F>) -> Option<(F::Key, Node)> {
+        // Find the critical level: The deepest level where two sibling subtrees contain the
+        // current node and its right sibling.
+        self.right_sibling_branch_level(level, pool).map(|bl| {
+            // Extract the critical key and the `bl+1` node.
+            let be = usize::from(self.entry[bl]);
+            let crit_key;
+            let mut node;
+            {
+                let (keys, tree) = pool[self.node[bl]].unwrap_inner();
+                crit_key = keys[be];
+                node = tree[be + 1];
+            }
+
+            // Follow left-most links back down to `level`.
+            for _ in bl + 1..level {
+                node = pool[node].unwrap_inner().1[0];
+            }
+
+            (crit_key, node)
+        })
+    }
+
+    /// Update the critical key for the right sibling node at `level`.
+    fn update_right_crit_key(&self, level: usize, crit_key: F::Key, pool: &mut NodePool<F>) {
+        let bl = self
+            .right_sibling_branch_level(level, pool)
+            .expect("No right sibling exists");
+        match pool[self.node[bl]] {
+            NodeData::Inner { ref mut keys, .. } => {
+                keys[usize::from(self.entry[bl])] = crit_key;
+            }
+            _ => panic!("Expected inner node"),
+        }
+    }
+
+    /// Normalize the path position such that it is either pointing at a real entry or `size=0`
+    /// indicating "off-the-end".
+    pub fn normalize(&mut self, pool: &mut NodePool<F>) {
+        if let Some((leaf, entry)) = self.leaf_pos() {
+            if entry >= pool[leaf].entries() {
+                let leaf_level = self.size - 1;
+                self.next_node(leaf_level, pool);
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+impl<F: Forest> Path<F> {
+    /// Check the internal consistency of this path.
+    pub fn verify(&self, pool: &NodePool<F>) {
+        for level in 0..self.size {
+            match pool[self.node[level]] {
+                NodeData::Inner { size, tree, .. } => {
+                    assert!(
+                        level < self.size - 1,
+                        "Expected leaf node at level {}",
+                        level
+                    );
+                    assert!(
+                        self.entry[level] <= size,
+                        "OOB inner entry {}/{} at level {}",
+                        self.entry[level],
+                        size,
+                        level
+                    );
+                    assert_eq!(
+                        self.node[level + 1],
+                        tree[usize::from(self.entry[level])],
+                        "Node mismatch at level {}",
+                        level
+                    );
+                }
+                NodeData::Leaf { size, .. } => {
+                    assert_eq!(level, self.size - 1, "Expected inner node");
+                    assert!(
+                        self.entry[level] <= size,
+                        "OOB leaf entry {}/{}",
+                        self.entry[level],
+                        size,
+                    );
+                }
+                NodeData::Free { .. } => {
+                    panic!("Free {} in path", self.node[level]);
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+impl<F: Forest> fmt::Display for Path<F> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.size == 0 {
+            write!(f, "<empty path>")
+        } else {
+            write!(f, "{}[{}]", self.node[0], self.entry[0])?;
+            for i in 1..self.size {
+                write!(f, "--{}[{}]", self.node[i], self.entry[i])?;
+            }
+            Ok(())
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::super::{Forest, NodeData, NodePool};
+    use super::*;
+    use std::cmp::Ordering;
+
+    struct TC();
+
+    impl Comparator<i32> for TC {
+        fn cmp(&self, a: i32, b: i32) -> Ordering {
+            a.cmp(&b)
+        }
+    }
+
+    struct TF();
+
+    impl Forest for TF {
+        type Key = i32;
+        type Value = char;
+        type LeafKeys = [i32; 7];
+        type LeafValues = [char; 7];
+
+        fn splat_key(key: Self::Key) -> Self::LeafKeys {
+            [key; 7]
+        }
+
+        fn splat_value(value: Self::Value) -> Self::LeafValues {
+            [value; 7]
+        }
+    }
+
+    #[test]
+    fn search_single_leaf() {
+        // Testing Path::new() for trees with a single leaf node.
+        let mut pool = NodePool::<TF>::new();
+        let root = pool.alloc_node(NodeData::leaf(10, 'a'));
+        let mut p = Path::default();
+        let comp = TC();
+
+        // Search for key less than stored key.
+        assert_eq!(p.find(5, root, &pool, &comp), None);
+        assert_eq!(p.size, 1);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 0);
+
+        // Search for stored key.
+        assert_eq!(p.find(10, root, &pool, &comp), Some('a'));
+        assert_eq!(p.size, 1);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 0);
+
+        // Search for key greater than stored key.
+        assert_eq!(p.find(15, root, &pool, &comp), None);
+        assert_eq!(p.size, 1);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 1);
+
+        // Modify leaf node to contain two values.
+        match pool[root] {
+            NodeData::Leaf {
+                ref mut size,
+                ref mut keys,
+                ref mut vals,
+            } => {
+                *size = 2;
+                keys[1] = 20;
+                vals[1] = 'b';
+            }
+            _ => unreachable!(),
+        }
+
+        // Search for key between stored keys.
+        assert_eq!(p.find(15, root, &pool, &comp), None);
+        assert_eq!(p.size, 1);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 1);
+
+        // Search for key greater than stored keys.
+        assert_eq!(p.find(25, root, &pool, &comp), None);
+        assert_eq!(p.size, 1);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 2);
+    }
+
+    #[test]
+    fn search_single_inner() {
+        // Testing Path::new() for trees with a single inner node and two leaves.
+        let mut pool = NodePool::<TF>::new();
+        let leaf1 = pool.alloc_node(NodeData::leaf(10, 'a'));
+        let leaf2 = pool.alloc_node(NodeData::leaf(20, 'b'));
+        let root = pool.alloc_node(NodeData::inner(leaf1, 20, leaf2));
+        let mut p = Path::default();
+        let comp = TC();
+
+        // Search for key less than stored keys.
+        assert_eq!(p.find(5, root, &pool, &comp), None);
+        assert_eq!(p.size, 2);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 0);
+        assert_eq!(p.node[1], leaf1);
+        assert_eq!(p.entry[1], 0);
+
+        assert_eq!(p.find(10, root, &pool, &comp), Some('a'));
+        assert_eq!(p.size, 2);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 0);
+        assert_eq!(p.node[1], leaf1);
+        assert_eq!(p.entry[1], 0);
+
+        // Midway between the two leaf nodes.
+        assert_eq!(p.find(15, root, &pool, &comp), None);
+        assert_eq!(p.size, 2);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 0);
+        assert_eq!(p.node[1], leaf1);
+        assert_eq!(p.entry[1], 1);
+
+        assert_eq!(p.find(20, root, &pool, &comp), Some('b'));
+        assert_eq!(p.size, 2);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 1);
+        assert_eq!(p.node[1], leaf2);
+        assert_eq!(p.entry[1], 0);
+
+        assert_eq!(p.find(25, root, &pool, &comp), None);
+        assert_eq!(p.size, 2);
+        assert_eq!(p.node[0], root);
+        assert_eq!(p.entry[0], 1);
+        assert_eq!(p.node[1], leaf2);
+        assert_eq!(p.entry[1], 1);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/pool.rs
@@ -0,0 +1,218 @@
+//! B+-tree node pool.
+
+#[cfg(test)]
+use super::Comparator;
+use super::{Forest, Node, NodeData};
+use entity::PrimaryMap;
+#[cfg(test)]
+use std::fmt;
+use std::ops::{Index, IndexMut};
+
+/// A pool of nodes, including a free list.
+pub(super) struct NodePool<F: Forest> {
+    nodes: PrimaryMap<Node, NodeData<F>>,
+    freelist: Option<Node>,
+}
+
+impl<F: Forest> NodePool<F> {
+    /// Allocate a new empty pool of nodes.
+    pub fn new() -> Self {
+        Self {
+            nodes: PrimaryMap::new(),
+            freelist: None,
+        }
+    }
+
+    /// Free all nodes.
+    pub fn clear(&mut self) {
+        self.nodes.clear();
+        self.freelist = None;
+    }
+
+    /// Allocate a new node containing `data`.
+    pub fn alloc_node(&mut self, data: NodeData<F>) -> Node {
+        debug_assert!(!data.is_free(), "can't allocate free node");
+        match self.freelist {
+            Some(node) => {
+                // Remove this node from the free list.
+                match self.nodes[node] {
+                    NodeData::Free { next } => self.freelist = next,
+                    _ => panic!("Invalid {} on free list", node),
+                }
+                self.nodes[node] = data;
+                node
+            }
+            None => {
+                // The free list is empty. Allocate a new node.
+                self.nodes.push(data)
+            }
+        }
+    }
+
+    /// Free a node.
+    pub fn free_node(&mut self, node: Node) {
+        // Quick check for a double free.
+        debug_assert!(!self.nodes[node].is_free(), "{} is already free", node);
+        self.nodes[node] = NodeData::Free {
+            next: self.freelist,
+        };
+        self.freelist = Some(node);
+    }
+
+    /// Free the entire tree rooted at `node`.
+    pub fn free_tree(&mut self, node: Node) {
+        if let NodeData::Inner { size, tree, .. } = self[node] {
+            // Note that we have to capture `tree` by value to avoid borrow checker trouble.
+            #[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
+            for i in 0..usize::from(size + 1) {
+                // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,
+                // and since most trees have less than a handful of nodes, it is worthwhile to
+                // avoid the heap allocation for an iterative tree traversal.
+                self.free_tree(tree[i]);
+            }
+        }
+        self.free_node(node);
+    }
+}
+
+#[cfg(test)]
+impl<F: Forest> NodePool<F> {
+    /// Verify the consistency of the tree rooted at `node`.
+    pub fn verify_tree<C: Comparator<F::Key>>(&self, node: Node, comp: &C)
+    where
+        NodeData<F>: fmt::Display,
+        F::Key: fmt::Display,
+    {
+        use entity::SparseSet;
+        use std::borrow::Borrow;
+        use std::cmp::Ordering;
+        use std::vec::Vec;
+
+        // The root node can't be an inner node with just a single sub-tree. It should have been
+        // pruned.
+        if let &NodeData::Inner { size, .. } = &self[node] {
+            assert!(size > 0, "Root must have more than one sub-tree");
+        }
+
+        let mut done = SparseSet::new();
+        let mut todo = Vec::new();
+
+        // Todo-list entries are:
+        // 1. Optional LHS key which must be <= all node entries.
+        // 2. The node reference.
+        // 3. Optional RHS key which must be > all node entries.
+        todo.push((None, node, None));
+
+        while let Some((lkey, node, rkey)) = todo.pop() {
+            assert_eq!(
+                done.insert(node),
+                None,
+                "Node appears more than once in tree"
+            );
+            let mut lower = lkey;
+
+            match self[node] {
+                NodeData::Inner { size, keys, tree } => {
+                    let size = size as usize;
+                    let capacity = tree.len();
+                    let keys = &keys[0..size];
+
+                    // Verify occupancy.
+                    // Right-most nodes can be small, but others must be at least half full.
+                    assert!(
+                        rkey.is_none() || (size + 1) * 2 >= capacity,
+                        "Only {}/{} entries in {}:{}, upper={}",
+                        size + 1,
+                        capacity,
+                        node,
+                        self[node],
+                        rkey.unwrap()
+                    );
+
+                    // Queue up the sub-trees, checking for duplicates.
+                    for i in 0..size + 1 {
+                        // Get an upper bound for node[i].
+                        let upper = keys.get(i).cloned().or(rkey);
+
+                        // Check that keys are strictly monotonic.
+                        if let (Some(a), Some(b)) = (lower, upper) {
+                            assert_eq!(
+                                comp.cmp(a, b),
+                                Ordering::Less,
+                                "Key order {} < {} failed in {}: {}",
+                                a,
+                                b,
+                                node,
+                                self[node]
+                            );
+                        }
+
+                        // Queue up the sub-tree.
+                        todo.push((lower, tree[i], upper));
+
+                        // Set a lower bound for the next tree.
+                        lower = upper;
+                    }
+                }
+                NodeData::Leaf { size, keys, .. } => {
+                    let size = size as usize;
+                    let capacity = keys.borrow().len();
+                    let keys = &keys.borrow()[0..size];
+
+                    // Verify occupancy.
+                    // Right-most nodes can be small, but others must be at least half full.
+                    assert!(size > 0, "Leaf {} is empty", node);
+                    assert!(
+                        rkey.is_none() || size * 2 >= capacity,
+                        "Only {}/{} entries in {}:{}, upper={}",
+                        size,
+                        capacity,
+                        node,
+                        self[node],
+                        rkey.unwrap()
+                    );
+
+                    for i in 0..size + 1 {
+                        let upper = keys.get(i).cloned().or(rkey);
+
+                        // Check that keys are strictly monotonic.
+                        if let (Some(a), Some(b)) = (lower, upper) {
+                            let wanted = if i == 0 {
+                                Ordering::Equal
+                            } else {
+                                Ordering::Less
+                            };
+                            assert_eq!(
+                                comp.cmp(a, b),
+                                wanted,
+                                "Key order for {} - {} failed in {}: {}",
+                                a,
+                                b,
+                                node,
+                                self[node]
+                            );
+                        }
+
+                        // Set a lower bound for the next key.
+                        lower = upper;
+                    }
+                }
+                NodeData::Free { .. } => panic!("Free {} reached", node),
+            }
+        }
+    }
+}
+
+impl<F: Forest> Index<Node> for NodePool<F> {
+    type Output = NodeData<F>;
+
+    fn index(&self, index: Node) -> &Self::Output {
+        self.nodes.index(index)
+    }
+}
+
+impl<F: Forest> IndexMut<Node> for NodePool<F> {
+    fn index_mut(&mut self, index: Node) -> &mut Self::Output {
+        self.nodes.index_mut(index)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-bforest/src/set.rs
@@ -0,0 +1,601 @@
+//! Forest of sets.
+
+use super::{Comparator, Forest, Node, NodeData, NodePool, Path, SetValue, INNER_SIZE};
+use packed_option::PackedOption;
+#[cfg(test)]
+use std::fmt;
+use std::marker::PhantomData;
+#[cfg(test)]
+use std::string::String;
+
+/// Tag type defining forest types for a set.
+struct SetTypes<K>(PhantomData<K>);
+
+impl<K> Forest for SetTypes<K>
+where
+    K: Copy,
+{
+    type Key = K;
+    type Value = SetValue;
+    type LeafKeys = [K; 2 * INNER_SIZE - 1];
+    type LeafValues = [SetValue; 2 * INNER_SIZE - 1];
+
+    fn splat_key(key: Self::Key) -> Self::LeafKeys {
+        [key; 2 * INNER_SIZE - 1]
+    }
+
+    fn splat_value(value: Self::Value) -> Self::LeafValues {
+        [value; 2 * INNER_SIZE - 1]
+    }
+}
+
+/// Memory pool for a forest of `Set` instances.
+pub struct SetForest<K>
+where
+    K: Copy,
+{
+    nodes: NodePool<SetTypes<K>>,
+}
+
+impl<K> SetForest<K>
+where
+    K: Copy,
+{
+    /// Create a new empty forest.
+    pub fn new() -> Self {
+        Self {
+            nodes: NodePool::new(),
+        }
+    }
+
+    /// Clear all sets in the forest.
+    ///
+    /// All `Set` instances belong to this forest are invalidated and should no longer be used.
+    pub fn clear(&mut self) {
+        self.nodes.clear();
+    }
+}
+
+/// B-tree representing an ordered set of `K`s using `C` for comparing elements.
+///
+/// This is not a general-purpose replacement for `BTreeSet`. See the [module
+/// documentation](index.html) for more information about design tradeoffs.
+///
+/// Sets can be cloned, but that operation should only be used as part of cloning the whole forest
+/// they belong to. *Cloning a set does not allocate new memory for the clone*. It creates an alias
+/// of the same memory.
+#[derive(Clone)]
+pub struct Set<K>
+where
+    K: Copy,
+{
+    root: PackedOption<Node>,
+    unused: PhantomData<K>,
+}
+
+impl<K> Set<K>
+where
+    K: Copy,
+{
+    /// Make an empty set.
+    pub fn new() -> Self {
+        Self {
+            root: None.into(),
+            unused: PhantomData,
+        }
+    }
+
+    /// Is this an empty set?
+    pub fn is_empty(&self) -> bool {
+        self.root.is_none()
+    }
+
+    /// Does the set contain `key`?.
+    pub fn contains<C: Comparator<K>>(&self, key: K, forest: &SetForest<K>, comp: &C) -> bool {
+        self.root
+            .expand()
+            .and_then(|root| Path::default().find(key, root, &forest.nodes, comp))
+            .is_some()
+    }
+
+    /// Try to insert `key` into the set.
+    ///
+    /// If the set did not contain `key`, insert it and return true.
+    ///
+    /// If `key` is already present, don't change the set and return false.
+    pub fn insert<C: Comparator<K>>(
+        &mut self,
+        key: K,
+        forest: &mut SetForest<K>,
+        comp: &C,
+    ) -> bool {
+        self.cursor(forest, comp).insert(key)
+    }
+
+    /// Remove `key` from the set and return true.
+    ///
+    /// If `key` was not present in the set, return false.
+    pub fn remove<C: Comparator<K>>(
+        &mut self,
+        key: K,
+        forest: &mut SetForest<K>,
+        comp: &C,
+    ) -> bool {
+        let mut c = self.cursor(forest, comp);
+        if c.goto(key) {
+            c.remove();
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Remove all entries.
+    pub fn clear(&mut self, forest: &mut SetForest<K>) {
+        if let Some(root) = self.root.take() {
+            forest.nodes.free_tree(root);
+        }
+    }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// Remove all elements where the predicate returns false.
+    pub fn retain<F>(&mut self, forest: &mut SetForest<K>, mut predicate: F)
+    where
+        F: FnMut(K) -> bool,
+    {
+        let mut path = Path::default();
+        if let Some(root) = self.root.expand() {
+            path.first(root, &forest.nodes);
+        }
+        while let Some((node, entry)) = path.leaf_pos() {
+            if predicate(forest.nodes[node].unwrap_leaf().0[entry]) {
+                path.next(&forest.nodes);
+            } else {
+                self.root = path.remove(&mut forest.nodes).into();
+            }
+        }
+    }
+
+    /// Create a cursor for navigating this set. The cursor is initially positioned off the end of
+    /// the set.
+    pub fn cursor<'a, C: Comparator<K>>(
+        &'a mut self,
+        forest: &'a mut SetForest<K>,
+        comp: &'a C,
+    ) -> SetCursor<'a, K, C> {
+        SetCursor::new(self, forest, comp)
+    }
+
+    /// Create an iterator traversing this set. The iterator type is `K`.
+    pub fn iter<'a>(&'a self, forest: &'a SetForest<K>) -> SetIter<'a, K> {
+        SetIter {
+            root: self.root,
+            pool: &forest.nodes,
+            path: Path::default(),
+        }
+    }
+}
+
+impl<K> Default for Set<K>
+where
+    K: Copy,
+{
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A position in a `Set` used to navigate and modify the ordered set.
+///
+/// A cursor always points at an element in the set, or "off the end" which is a position after the
+/// last element in the set.
+pub struct SetCursor<'a, K, C>
+where
+    K: 'a + Copy,
+    C: 'a + Comparator<K>,
+{
+    root: &'a mut PackedOption<Node>,
+    pool: &'a mut NodePool<SetTypes<K>>,
+    comp: &'a C,
+    path: Path<SetTypes<K>>,
+}
+
+impl<'a, K, C> SetCursor<'a, K, C>
+where
+    K: Copy,
+    C: Comparator<K>,
+{
+    /// Create a cursor with a default (invalid) location.
+    fn new(
+        container: &'a mut Set<K>,
+        forest: &'a mut SetForest<K>,
+        comp: &'a C,
+    ) -> SetCursor<'a, K, C> {
+        SetCursor {
+            root: &mut container.root,
+            pool: &mut forest.nodes,
+            comp,
+            path: Path::default(),
+        }
+    }
+
+    /// Is this cursor pointing to an empty set?
+    pub fn is_empty(&self) -> bool {
+        self.root.is_none()
+    }
+
+    /// Move cursor to the next element and return it.
+    ///
+    /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end
+    /// position.
+    pub fn next(&mut self) -> Option<K> {
+        self.path.next(self.pool).map(|(k, _)| k)
+    }
+
+    /// Move cursor to the previous element and return it.
+    ///
+    /// If the cursor is already pointing at the first element, leave it there and return `None`.
+    pub fn prev(&mut self) -> Option<K> {
+        self.root
+            .expand()
+            .and_then(|root| self.path.prev(root, self.pool).map(|(k, _)| k))
+    }
+
+    /// Get the current element, or `None` if the cursor is at the end.
+    pub fn elem(&self) -> Option<K> {
+        self.path
+            .leaf_pos()
+            .and_then(|(node, entry)| self.pool[node].unwrap_leaf().0.get(entry).cloned())
+    }
+
+    /// Move this cursor to `elem`.
+    ///
+    /// If `elem` is in the set, place the cursor at `elem` and return true.
+    ///
+    /// If `elem` is not in the set, place the cursor at the next larger element (or the end) and
+    /// return false.
+    pub fn goto(&mut self, elem: K) -> bool {
+        match self.root.expand() {
+            None => false,
+            Some(root) => {
+                if self.path.find(elem, root, self.pool, self.comp).is_some() {
+                    true
+                } else {
+                    self.path.normalize(self.pool);
+                    false
+                }
+            }
+        }
+    }
+
+    /// Move this cursor to the first element.
+    pub fn goto_first(&mut self) -> Option<K> {
+        self.root.map(|root| self.path.first(root, self.pool).0)
+    }
+
+    /// Try to insert `elem` into the set and leave the cursor at the inserted element.
+    ///
+    /// If the set did not contain `elem`, insert it and return true.
+    ///
+    /// If `elem` is already present, don't change the set, place the cursor at `goto(elem)`, and
+    /// return false.
+    pub fn insert(&mut self, elem: K) -> bool {
+        match self.root.expand() {
+            None => {
+                let root = self.pool.alloc_node(NodeData::leaf(elem, SetValue()));
+                *self.root = root.into();
+                self.path.set_root_node(root);
+                true
+            }
+            Some(root) => {
+                // TODO: Optimize the case where `self.path` is already at the correct insert pos.
+                if self.path.find(elem, root, self.pool, self.comp).is_none() {
+                    *self.root = self.path.insert(elem, SetValue(), self.pool).into();
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+    }
+
+    /// Remove the current element (if any) and return it.
+    /// This advances the cursor to the next element after the removed one.
+    pub fn remove(&mut self) -> Option<K> {
+        let elem = self.elem();
+        if elem.is_some() {
+            *self.root = self.path.remove(self.pool).into();
+        }
+        elem
+    }
+}
+
+#[cfg(test)]
+impl<'a, K, C> SetCursor<'a, K, C>
+where
+    K: Copy + fmt::Display,
+    C: Comparator<K>,
+{
+    fn verify(&self) {
+        self.path.verify(self.pool);
+        self.root.map(|root| self.pool.verify_tree(root, self.comp));
+    }
+
+    /// Get a text version of the path to the current position.
+    fn tpath(&self) -> String {
+        use std::string::ToString;
+        self.path.to_string()
+    }
+}
+
+/// An iterator visiting the elements of a `Set`.
+pub struct SetIter<'a, K>
+where
+    K: 'a + Copy,
+{
+    root: PackedOption<Node>,
+    pool: &'a NodePool<SetTypes<K>>,
+    path: Path<SetTypes<K>>,
+}
+
+impl<'a, K> Iterator for SetIter<'a, K>
+where
+    K: 'a + Copy,
+{
+    type Item = K;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // We use `self.root` to indicate if we need to go to the first element. Reset to `None`
+        // once we've returned the first element. This also works for an empty tree since the
+        // `path.next()` call returns `None` when the path is empty. This also fuses the iterator.
+        match self.root.take() {
+            Some(root) => Some(self.path.first(root, self.pool).0),
+            None => self.path.next(self.pool).map(|(k, _)| k),
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::super::NodeData;
+    use super::*;
+    use std::mem;
+    use std::vec::Vec;
+
+    #[test]
+    fn node_size() {
+        // check that nodes are cache line sized when keys are 32 bits.
+        type F = SetTypes<u32>;
+        assert_eq!(mem::size_of::<NodeData<F>>(), 64);
+    }
+
+    #[test]
+    fn empty() {
+        let mut f = SetForest::<u32>::new();
+        f.clear();
+
+        let mut s = Set::<u32>::new();
+        assert!(s.is_empty());
+        s.clear(&mut f);
+        assert!(!s.contains(7, &f, &()));
+
+        // Iterator for an empty set.
+        assert_eq!(s.iter(&f).next(), None);
+
+        s.retain(&mut f, |_| unreachable!());
+
+        let mut c = SetCursor::new(&mut s, &mut f, &());
+        c.verify();
+        assert_eq!(c.elem(), None);
+
+        assert_eq!(c.goto_first(), None);
+        assert_eq!(c.tpath(), "<empty path>");
+    }
+
+    #[test]
+    fn simple_cursor() {
+        let mut f = SetForest::<u32>::new();
+        let mut s = Set::<u32>::new();
+        let mut c = SetCursor::new(&mut s, &mut f, &());
+
+        assert!(c.insert(50));
+        c.verify();
+        assert_eq!(c.elem(), Some(50));
+
+        assert!(c.insert(100));
+        c.verify();
+        assert_eq!(c.elem(), Some(100));
+
+        assert!(c.insert(10));
+        c.verify();
+        assert_eq!(c.elem(), Some(10));
+
+        // Basic movement.
+        assert_eq!(c.next(), Some(50));
+        assert_eq!(c.next(), Some(100));
+        assert_eq!(c.next(), None);
+        assert_eq!(c.next(), None);
+        assert_eq!(c.prev(), Some(100));
+        assert_eq!(c.prev(), Some(50));
+        assert_eq!(c.prev(), Some(10));
+        assert_eq!(c.prev(), None);
+        assert_eq!(c.prev(), None);
+
+        assert!(c.goto(50));
+        assert_eq!(c.elem(), Some(50));
+        assert_eq!(c.remove(), Some(50));
+        c.verify();
+
+        assert_eq!(c.elem(), Some(100));
+        assert_eq!(c.remove(), Some(100));
+        c.verify();
+        assert_eq!(c.elem(), None);
+        assert_eq!(c.remove(), None);
+        c.verify();
+    }
+
+    #[test]
+    fn two_level_sparse_tree() {
+        let mut f = SetForest::<u32>::new();
+        let mut s = Set::<u32>::new();
+        let mut c = SetCursor::new(&mut s, &mut f, &());
+
+        // Insert enough elements that we get a two-level tree.
+        // Each leaf node holds 8 elements
+        assert!(c.is_empty());
+        for i in 0..50 {
+            assert!(c.insert(i));
+            assert_eq!(c.elem(), Some(i));
+        }
+        assert!(!c.is_empty());
+
+        assert_eq!(c.goto_first(), Some(0));
+        assert_eq!(c.tpath(), "node2[0]--node0[0]");
+
+        assert_eq!(c.prev(), None);
+        for i in 1..50 {
+            assert_eq!(c.next(), Some(i));
+        }
+        assert_eq!(c.next(), None);
+        for i in (0..50).rev() {
+            assert_eq!(c.prev(), Some(i));
+        }
+        assert_eq!(c.prev(), None);
+
+        assert!(c.goto(25));
+        for i in 25..50 {
+            assert_eq!(c.remove(), Some(i));
+            assert!(!c.is_empty());
+            c.verify();
+        }
+
+        for i in (0..25).rev() {
+            assert!(!c.is_empty());
+            assert_eq!(c.elem(), None);
+            assert_eq!(c.prev(), Some(i));
+            assert_eq!(c.remove(), Some(i));
+            c.verify();
+        }
+        assert_eq!(c.elem(), None);
+        assert!(c.is_empty());
+    }
+
+    #[test]
+    fn three_level_sparse_tree() {
+        let mut f = SetForest::<u32>::new();
+        let mut s = Set::<u32>::new();
+        let mut c = SetCursor::new(&mut s, &mut f, &());
+
+        // Insert enough elements that we get a 3-level tree.
+        // Each leaf node holds 8 elements when filled up sequentially.
+        // Inner nodes hold 8 node pointers.
+        assert!(c.is_empty());
+        for i in 0..150 {
+            assert!(c.insert(i));
+            assert_eq!(c.elem(), Some(i));
+        }
+        assert!(!c.is_empty());
+
+        assert!(c.goto(0));
+        assert_eq!(c.tpath(), "node11[0]--node2[0]--node0[0]");
+
+        assert_eq!(c.prev(), None);
+        for i in 1..150 {
+            assert_eq!(c.next(), Some(i));
+        }
+        assert_eq!(c.next(), None);
+        for i in (0..150).rev() {
+            assert_eq!(c.prev(), Some(i));
+        }
+        assert_eq!(c.prev(), None);
+
+        assert!(c.goto(125));
+        for i in 125..150 {
+            assert_eq!(c.remove(), Some(i));
+            assert!(!c.is_empty());
+            c.verify();
+        }
+
+        for i in (0..125).rev() {
+            assert!(!c.is_empty());
+            assert_eq!(c.elem(), None);
+            assert_eq!(c.prev(), Some(i));
+            assert_eq!(c.remove(), Some(i));
+            c.verify();
+        }
+        assert_eq!(c.elem(), None);
+        assert!(c.is_empty());
+    }
+
+    // Generate a densely populated 4-level tree.
+    //
+    // Level 1: 1 root
+    // Level 2: 8 inner
+    // Level 3: 64 inner
+    // Level 4: 512 leafs, up to 7680 elements
+    //
+    // A 3-level tree can hold at most 960 elements.
+    fn dense4l(f: &mut SetForest<i32>) -> Set<i32> {
+        f.clear();
+        let mut s = Set::new();
+
+        // Insert 400 elements in 7 passes over the range to avoid the half-full leaf node pattern
+        // that comes from sequential insertion. This will generate a normal leaf layer.
+        for n in 0..4000 {
+            assert!(s.insert((n * 7) % 4000, f, &()));
+        }
+        s
+    }
+
+    #[test]
+    fn four_level() {
+        let mut f = SetForest::<i32>::new();
+        let mut s = dense4l(&mut f);
+
+        assert_eq!(
+            s.iter(&f).collect::<Vec<_>>()[0..10],
+            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+        );
+
+        let mut c = s.cursor(&mut f, &());
+
+        c.verify();
+
+        // Peel off a whole sub-tree of the root by deleting from the front.
+        // The 900 element is near the front of the second sub-tree.
+        assert!(c.goto(900));
+        assert_eq!(c.tpath(), "node48[1]--node47[0]--node26[0]--node20[4]");
+        assert!(c.goto(0));
+        for i in 0..900 {
+            assert!(!c.is_empty());
+            assert_eq!(c.remove(), Some(i));
+        }
+        c.verify();
+        assert_eq!(c.elem(), Some(900));
+
+        // Delete backwards from somewhere in the middle.
+        assert!(c.goto(3000));
+        for i in (2000..3000).rev() {
+            assert_eq!(c.prev(), Some(i));
+            assert_eq!(c.remove(), Some(i));
+            assert_eq!(c.elem(), Some(3000));
+        }
+        c.verify();
+
+        // Remove everything in a scattered manner, triggering many collapsing patterns.
+        for i in 0..4000 {
+            if c.goto((i * 7) % 4000) {
+                c.remove();
+            }
+        }
+        assert!(c.is_empty());
+    }
+
+    #[test]
+    fn four_level_clear() {
+        let mut f = SetForest::<i32>::new();
+        let mut s = dense4l(&mut f);
+        s.clear(&mut f);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"410de243e172b6d8597ca3cf2d2e8da264762966755ccd4d99496ba4b4034a98","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/base/mod.rs":"9320dfed2250bdb0347e01862b2ff7bf7db78920dae1719834b374de11131e87","src/base/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/cdsl/mod.rs":"1ed81ef8c6bc01384a840fa01f434c20ddd6c90ba10cdc5dc8b39dab7c647a70","src/cdsl/types.rs":"53e9f0e6d9c2cf0321a0c02324c0408fc14b01d1d3c16771f133169d57ff7a19","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_types.rs":"4b6be1877ce80205bdda954a0e7d4c04083d35811f3907619be18475a005eed3","src/lib.rs":"b6fc7d24e86439a5d62a0662865bf937e921fd6607cbabda616445a7219ec2f5","src/srcgen.rs":"3e6874cb3cb1155dc10ee9043b2a7ca4dfc3373d1079a864f931fc54aa325c9d"},"package":"1da3daa0109e7a0b7b322cea666cc223fb6a0d5170e83d23b3d5d2deaddca5f3"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/Cargo.toml
@@ -0,0 +1,25 @@
+# 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]
+name = "cranelift-codegen-meta"
+version = "0.20.0"
+authors = ["The Cranelift Project Developers"]
+description = "Metaprogram for cranelift-codegen code generator library"
+readme = "README.md"
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/CraneStation/cranelift"
+[badges.maintenance]
+status = "experimental"
+
+[badges.travis-ci]
+repository = "CraneStation/cranelift"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/LICENSE
@@ -0,0 +1,219 @@
+
+                                 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.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/README.md
@@ -0,0 +1,2 @@
+This crate contains the metaprogram used by cranelift-codegen. It's not
+useful on its own.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/base/mod.rs
@@ -0,0 +1,3 @@
+//! Definitions for the base Cranelift language.
+
+pub mod types;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/base/types.rs
@@ -0,0 +1,188 @@
+//! This module predefines all the Cranelift scalar types.
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum Bool {
+    /// 1-bit bool.
+    B1 = 1,
+    /// 8-bit bool.
+    B8 = 8,
+    /// 16-bit bool.
+    B16 = 16,
+    /// 32-bit bool.
+    B32 = 32,
+    /// 64-bit bool.
+    B64 = 64,
+}
+
+/// This provides an iterator through all of the supported bool variants.
+pub struct BoolIterator {
+    index: u8,
+}
+
+impl BoolIterator {
+    pub fn new() -> Self {
+        Self { index: 0 }
+    }
+}
+
+impl Iterator for BoolIterator {
+    type Item = Bool;
+    fn next(&mut self) -> Option<Self::Item> {
+        let res = match self.index {
+            0 => Some(Bool::B1),
+            1 => Some(Bool::B8),
+            2 => Some(Bool::B16),
+            3 => Some(Bool::B32),
+            4 => Some(Bool::B64),
+            _ => return None,
+        };
+        self.index += 1;
+        res
+    }
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum Int {
+    /// 8-bit int.
+    I8 = 8,
+    /// 16-bit int.
+    I16 = 16,
+    /// 32-bit int.
+    I32 = 32,
+    /// 64-bit int.
+    I64 = 64,
+}
+
+/// This provides an iterator through all of the supported int variants.
+pub struct IntIterator {
+    index: u8,
+}
+
+impl IntIterator {
+    pub fn new() -> Self {
+        Self { index: 0 }
+    }
+}
+
+impl Iterator for IntIterator {
+    type Item = Int;
+    fn next(&mut self) -> Option<Self::Item> {
+        let res = match self.index {
+            0 => Some(Int::I8),
+            1 => Some(Int::I16),
+            2 => Some(Int::I32),
+            3 => Some(Int::I64),
+            _ => return None,
+        };
+        self.index += 1;
+        res
+    }
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum Float {
+    F32 = 32,
+    F64 = 64,
+}
+
+/// Iterator through the variants of the Float enum.
+pub struct FloatIterator {
+    index: u8,
+}
+
+impl FloatIterator {
+    pub fn new() -> Self {
+        Self { index: 0 }
+    }
+}
+
+/// This provides an iterator through all of the supported float variants.
+impl Iterator for FloatIterator {
+    type Item = Float;
+    fn next(&mut self) -> Option<Self::Item> {
+        let res = match self.index {
+            0 => Some(Float::F32),
+            1 => Some(Float::F64),
+            _ => return None,
+        };
+        self.index += 1;
+        res
+    }
+}
+
+/// A type representing CPU flags.
+///
+/// Flags can't be stored in memory.
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum Flag {
+    /// CPU flags from an integer comparison.
+    IFlags,
+    /// CPU flags from a floating point comparison.
+    FFlags,
+}
+
+/// Iterator through the variants of the Flag enum.
+pub struct FlagIterator {
+    index: u8,
+}
+
+impl FlagIterator {
+    pub fn new() -> Self {
+        Self { index: 0 }
+    }
+}
+
+impl Iterator for FlagIterator {
+    type Item = Flag;
+    fn next(&mut self) -> Option<Self::Item> {
+        let res = match self.index {
+            0 => Some(Flag::IFlags),
+            1 => Some(Flag::FFlags),
+            _ => return None,
+        };
+        self.index += 1;
+        res
+    }
+}
+
+#[cfg(test)]
+mod iter_tests {
+    use super::*;
+
+    #[test]
+    fn bool_iter_works() {
+        let mut bool_iter = BoolIterator::new();
+        assert_eq!(bool_iter.next(), Some(Bool::B1));
+        assert_eq!(bool_iter.next(), Some(Bool::B8));
+        assert_eq!(bool_iter.next(), Some(Bool::B16));
+        assert_eq!(bool_iter.next(), Some(Bool::B32));
+        assert_eq!(bool_iter.next(), Some(Bool::B64));
+        assert_eq!(bool_iter.next(), None);
+    }
+
+    #[test]
+    fn int_iter_works() {
+        let mut int_iter = IntIterator::new();
+        assert_eq!(int_iter.next(), Some(Int::I8));
+        assert_eq!(int_iter.next(), Some(Int::I16));
+        assert_eq!(int_iter.next(), Some(Int::I32));
+        assert_eq!(int_iter.next(), Some(Int::I64));
+        assert_eq!(int_iter.next(), None);
+    }
+
+    #[test]
+    fn float_iter_works() {
+        let mut float_iter = FloatIterator::new();
+        assert_eq!(float_iter.next(), Some(Float::F32));
+        assert_eq!(float_iter.next(), Some(Float::F64));
+        assert_eq!(float_iter.next(), None);
+    }
+
+    #[test]
+    fn flag_iter_works() {
+        let mut flag_iter = FlagIterator::new();
+        assert_eq!(flag_iter.next(), Some(Flag::IFlags));
+        assert_eq!(flag_iter.next(), Some(Flag::FFlags));
+        assert_eq!(flag_iter.next(), None);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs
@@ -0,0 +1,38 @@
+//! Cranelift DSL classes.
+//!
+//! This module defines the classes that are used to define Cranelift
+//! instructions and other entitties.
+
+pub mod types;
+
+/// Convert the string `s` to CamelCase.
+fn _camel_case(s: &str) -> String {
+    let mut output_chars = String::with_capacity(s.len());
+
+    let mut capitalize = true;
+    for curr_char in s.chars() {
+        if curr_char == '_' {
+            capitalize = true;
+        } else {
+            if capitalize {
+                output_chars.extend(curr_char.to_uppercase());
+            } else {
+                output_chars.push(curr_char);
+            }
+            capitalize = false;
+        }
+    }
+
+    output_chars
+}
+
+#[cfg(test)]
+mod tests {
+    use super::_camel_case as camel_case;
+
+    #[test]
+    fn camel_case_works() {
+        assert_eq!(camel_case("x"), "X");
+        assert_eq!(camel_case("camel_case"), "CamelCase");
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs
@@ -0,0 +1,473 @@
+//! Cranelift ValueType hierarchy
+
+// Temporary disabled: Unused at the moment.
+// use std::collections::HashMap;
+
+use std::fmt;
+
+use base::types as base_types;
+
+// Numbering scheme for value types:
+//
+// 0: Void
+// 0x01-0x6f: Special types
+// 0x70-0x7f: Lane types
+// 0x80-0xff: Vector types
+//
+// Vector types are encoded with the lane type in the low 4 bits and log2(lanes)
+// in the high 4 bits, giving a range of 2-256 lanes.
+static LANE_BASE: u8 = 0x70;
+
+// Rust name prefix used for the `rust_name` method.
+static _RUST_NAME_PREFIX: &'static str = "ir::types::";
+
+// ValueType variants (i8, i32, ...) are provided in `base::types.rs`.
+
+/// A concrete SSA value type.
+///
+/// All SSA values have a type that is described by an instance of `ValueType`
+/// or one of its subclasses.
+#[derive(Debug)]
+pub enum ValueType {
+    BV(BVType),
+    Lane(LaneType),
+    Special(SpecialType),
+    Vector(VectorType),
+}
+
+impl ValueType {
+    /// Iterate through all of the lane types.
+    pub fn all_lane_types() -> LaneTypeIterator {
+        LaneTypeIterator::new()
+    }
+
+    /// Iterate through all of the special types (neither lanes nor vectors).
+    pub fn all_special_types() -> SpecialTypeIterator {
+        SpecialTypeIterator::new()
+    }
+
+    /// Return a string containing the documentation comment for this type.
+    pub fn doc(&self) -> String {
+        match *self {
+            ValueType::BV(ref b) => b.doc(),
+            ValueType::Lane(l) => l.doc(),
+            ValueType::Special(s) => s.doc(),
+            ValueType::Vector(ref v) => v.doc(),
+        }
+    }
+
+    /// Return the number of bits in a lane.
+    pub fn lane_bits(&self) -> u64 {
+        match *self {
+            ValueType::BV(ref b) => b.lane_bits(),
+            ValueType::Lane(l) => l.lane_bits(),
+            ValueType::Special(s) => s.lane_bits(),
+            ValueType::Vector(ref v) => v.lane_bits(),
+        }
+    }
+
+    /// Return the number of lanes.
+    pub fn lane_count(&self) -> u64 {
+        match *self {
+            ValueType::Vector(ref v) => v.lane_count(),
+            _ => 1,
+        }
+    }
+
+    /// Find the number of bytes that this type occupies in memory.
+    pub fn membytes(&self) -> u64 {
+        self.width() / 8
+    }
+
+    /// Get the name of this type.
+    pub fn name(&self) -> String {
+        match *self {
+            ValueType::BV(ref b) => b.name(),
+            ValueType::Lane(l) => l.name(),
+            ValueType::Special(s) => s.name(),
+            ValueType::Vector(ref v) => v.name(),
+        }
+    }
+
+    /// Find the unique number associated with this type.
+    pub fn number(&self) -> Option<u8> {
+        match *self {
+            ValueType::BV(_) => None,
+            ValueType::Lane(l) => Some(l.number()),
+            ValueType::Special(s) => Some(s.number()),
+            ValueType::Vector(ref v) => Some(v.number()),
+        }
+    }
+
+    /// Return the name of this type for generated Rust source files.
+    pub fn _rust_name(&self) -> String {
+        format!("{}{}", _RUST_NAME_PREFIX, self.name().to_uppercase())
+    }
+
+    /// Return true iff:
+    ///     1. self and other have equal number of lanes
+    ///     2. each lane in self has at least as many bits as a lane in other
+    pub fn _wider_or_equal(&self, rhs: &ValueType) -> bool {
+        (self.lane_count() == rhs.lane_count()) && (self.lane_bits() >= rhs.lane_bits())
+    }
+
+    /// Return the total number of bits of an instance of this type.
+    pub fn width(&self) -> u64 {
+        self.lane_count() * self.lane_bits()
+    }
+}
+
+impl fmt::Display for ValueType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.name())
+    }
+}
+
+/// Create a ValueType from a given bitvector type.
+impl From<BVType> for ValueType {
+    fn from(bv: BVType) -> Self {
+        ValueType::BV(bv)
+    }
+}
+
+/// Create a ValueType from a given lane type.
+impl From<LaneType> for ValueType {
+    fn from(lane: LaneType) -> Self {
+        ValueType::Lane(lane)
+    }
+}
+
+/// Create a ValueType from a given special type.
+impl From<SpecialType> for ValueType {
+    fn from(spec: SpecialType) -> Self {
+        ValueType::Special(spec)
+    }
+}
+
+/// Create a ValueType from a given vector type.
+impl From<VectorType> for ValueType {
+    fn from(vector: VectorType) -> Self {
+        ValueType::Vector(vector)
+    }
+}
+
+/// A concrete scalar type that can appear as a vector lane too.
+#[derive(Clone, Copy)]
+pub enum LaneType {
+    BoolType(base_types::Bool),
+    FloatType(base_types::Float),
+    IntType(base_types::Int),
+}
+
+impl LaneType {
+    /// Return a string containing the documentation comment for this lane type.
+    pub fn doc(&self) -> String {
+        match *self {
+            LaneType::BoolType(_) => format!("A boolean type with {} bits.", self.lane_bits()),
+            LaneType::FloatType(base_types::Float::F32) => String::from(
+                "A 32-bit floating point type represented in the IEEE 754-2008
+                *binary32* interchange format. This corresponds to the :c:type:`float`
+                type in most C implementations.",
+            ),
+            LaneType::FloatType(base_types::Float::F64) => String::from(
+                "A 64-bit floating point type represented in the IEEE 754-2008
+                *binary64* interchange format. This corresponds to the :c:type:`double`
+                type in most C implementations.",
+            ),
+            LaneType::IntType(_) if self.lane_bits() < 32 => format!(
+                "An integer type with {} bits.
+                WARNING: arithmetic on {}bit integers is incomplete",
+                self.lane_bits(),
+                self.lane_bits()
+            ),
+            LaneType::IntType(_) => format!("An integer type with {} bits.", self.lane_bits()),
+        }
+    }
+
+    /// Return the number of bits in a lane.
+    pub fn lane_bits(&self) -> u64 {
+        match *self {
+            LaneType::BoolType(ref b) => *b as u64,
+            LaneType::FloatType(ref f) => *f as u64,
+            LaneType::IntType(ref i) => *i as u64,
+        }
+    }
+
+    /// Get the name of this lane type.
+    pub fn name(&self) -> String {
+        match *self {
+            LaneType::BoolType(_) => format!("b{}", self.lane_bits()),
+            LaneType::FloatType(_) => format!("f{}", self.lane_bits()),
+            LaneType::IntType(_) => format!("i{}", self.lane_bits()),
+        }
+    }
+
+    /// Find the unique number associated with this lane type.
+    pub fn number(&self) -> u8 {
+        LANE_BASE + match *self {
+            LaneType::BoolType(base_types::Bool::B1) => 0,
+            LaneType::BoolType(base_types::Bool::B8) => 1,
+            LaneType::BoolType(base_types::Bool::B16) => 2,
+            LaneType::BoolType(base_types::Bool::B32) => 3,
+            LaneType::BoolType(base_types::Bool::B64) => 4,
+            LaneType::IntType(base_types::Int::I8) => 5,
+            LaneType::IntType(base_types::Int::I16) => 6,
+            LaneType::IntType(base_types::Int::I32) => 7,
+            LaneType::IntType(base_types::Int::I64) => 8,
+            LaneType::FloatType(base_types::Float::F32) => 9,
+            LaneType::FloatType(base_types::Float::F64) => 10,
+        }
+    }
+}
+
+impl fmt::Debug for LaneType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let inner_msg = format!("bits={}", self.lane_bits());
+        write!(
+            f,
+            "{}",
+            match *self {
+                LaneType::BoolType(_) => format!("BoolType({})", inner_msg),
+                LaneType::FloatType(_) => format!("FloatType({})", inner_msg),
+                LaneType::IntType(_) => format!("IntType({})", inner_msg),
+            }
+        )
+    }
+}
+
+/// Create a LaneType from a given bool variant.
+impl From<base_types::Bool> for LaneType {
+    fn from(b: base_types::Bool) -> Self {
+        LaneType::BoolType(b)
+    }
+}
+
+/// Create a LaneType from a given float variant.
+impl From<base_types::Float> for LaneType {
+    fn from(f: base_types::Float) -> Self {
+        LaneType::FloatType(f)
+    }
+}
+
+/// Create a LaneType from a given int variant.
+impl From<base_types::Int> for LaneType {
+    fn from(i: base_types::Int) -> Self {
+        LaneType::IntType(i)
+    }
+}
+
+/// An iterator for different lane types.
+pub struct LaneTypeIterator {
+    bool_iter: base_types::BoolIterator,
+    int_iter: base_types::IntIterator,
+    float_iter: base_types::FloatIterator,
+}
+
+impl LaneTypeIterator {
+    /// Create a new lane type iterator.
+    fn new() -> Self {
+        Self {
+            bool_iter: base_types::BoolIterator::new(),
+            int_iter: base_types::IntIterator::new(),
+            float_iter: base_types::FloatIterator::new(),
+        }
+    }
+}
+
+impl Iterator for LaneTypeIterator {
+    type Item = LaneType;
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(b) = self.bool_iter.next() {
+            Some(LaneType::from(b))
+        } else if let Some(i) = self.int_iter.next() {
+            Some(LaneType::from(i))
+        } else if let Some(f) = self.float_iter.next() {
+            Some(LaneType::from(f))
+        } else {
+            None
+        }
+    }
+}
+
+/// A concrete SIMD vector type.
+///
+/// A vector type has a lane type which is an instance of `LaneType`,
+/// and a positive number of lanes.
+pub struct VectorType {
+    base: LaneType,
+    lanes: u64,
+}
+
+impl VectorType {
+    /// Initialize a new integer type with `n` bits.
+    pub fn new(base: LaneType, lanes: u64) -> VectorType {
+        VectorType { base, lanes }
+    }
+
+    /// Return a string containing the documentation comment for this vector type.
+    pub fn doc(&self) -> String {
+        format!(
+            "A SIMD vector with {} lanes containing a `{}` each.",
+            self.lane_count(),
+            self.base.name()
+        )
+    }
+
+    /// Return the number of bits in a lane.
+    pub fn lane_bits(&self) -> u64 {
+        self.base.lane_bits()
+    }
+
+    /// Return the number of lanes.
+    pub fn lane_count(&self) -> u64 {
+        self.lanes
+    }
+
+    /// Get the name of this vector type.
+    pub fn name(&self) -> String {
+        format!("{}x{}", self.base.name(), self.lane_count())
+    }
+
+    /// Find the unique number associated with this vector type.
+    ///
+    /// Vector types are encoded with the lane type in the low 4 bits and
+    /// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes.
+    pub fn number(&self) -> u8 {
+        let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
+        let base_num = u32::from(self.base.number());
+        let num = (lanes_log_2 << 4) + base_num;
+        num as u8
+    }
+}
+
+impl fmt::Debug for VectorType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "VectorType(base={}, lanes={})",
+            self.base.name(),
+            self.lane_count()
+        )
+    }
+}
+
+/// A flat bitvector type. Used for semantics description only.
+pub struct BVType {
+    bits: u64,
+}
+
+impl BVType {
+    /// Initialize a new bitvector type with `n` bits.
+    pub fn _new(bits: u64) -> Self {
+        Self { bits }
+    }
+
+    /// Return a string containing the documentation comment for this bitvector type.
+    pub fn doc(&self) -> String {
+        format!("A bitvector type with {} bits.", self.bits)
+    }
+
+    /// Return the number of bits in a lane.
+    pub fn lane_bits(&self) -> u64 {
+        self.bits
+    }
+
+    /// Get the name of this bitvector type.
+    pub fn name(&self) -> String {
+        format!("bv{}", self.bits)
+    }
+}
+
+impl fmt::Debug for BVType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "BVType(bits={})", self.lane_bits())
+    }
+}
+
+/// A concrete scalar type that is neither a vector nor a lane type.
+///
+/// Special types cannot be used to form vectors.
+#[derive(Clone, Copy)]
+pub enum SpecialType {
+    Flag(base_types::Flag),
+}
+
+impl SpecialType {
+    /// Return a string containing the documentation comment for this special type.
+    pub fn doc(&self) -> String {
+        match *self {
+            SpecialType::Flag(base_types::Flag::IFlags) => String::from(
+                "CPU flags representing the result of an integer comparison. These flags
+                can be tested with an :type:`intcc` condition code.",
+            ),
+            SpecialType::Flag(base_types::Flag::FFlags) => String::from(
+                "CPU flags representing the result of a floating point comparison. These
+                flags can be tested with a :type:`floatcc` condition code.",
+            ),
+        }
+    }
+
+    /// Return the number of bits in a lane.
+    pub fn lane_bits(&self) -> u64 {
+        match *self {
+            SpecialType::Flag(_) => 0,
+        }
+    }
+
+    /// Get the name of this special type.
+    pub fn name(&self) -> String {
+        match *self {
+            SpecialType::Flag(base_types::Flag::IFlags) => "iflags".to_string(),
+            SpecialType::Flag(base_types::Flag::FFlags) => "fflags".to_string(),
+        }
+    }
+
+    /// Find the unique number associated with this special type.
+    pub fn number(&self) -> u8 {
+        match *self {
+            SpecialType::Flag(base_types::Flag::IFlags) => 1,
+            SpecialType::Flag(base_types::Flag::FFlags) => 2,
+        }
+    }
+}
+
+impl fmt::Debug for SpecialType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match *self {
+                SpecialType::Flag(_) => format!("FlagsType({})", self.name()),
+            }
+        )
+    }
+}
+
+impl From<base_types::Flag> for SpecialType {
+    fn from(f: base_types::Flag) -> Self {
+        SpecialType::Flag(f)
+    }
+}
+
+pub struct SpecialTypeIterator {
+    flag_iter: base_types::FlagIterator,
+}
+
+impl SpecialTypeIterator {
+    fn new() -> Self {
+        Self {
+            flag_iter: base_types::FlagIterator::new(),
+        }
+    }
+}
+
+impl Iterator for SpecialTypeIterator {
+    type Item = SpecialType;
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(f) = self.flag_iter.next() {
+            Some(SpecialType::from(f))
+        } else {
+            None
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/error.rs
@@ -0,0 +1,47 @@
+use std::fmt;
+use std::io;
+
+/// An error that occurred when the cranelift_codegen_meta crate was generating
+/// source files for the cranelift_codegen crate.
+#[derive(Debug)]
+pub struct Error {
+    inner: Box<ErrorInner>,
+}
+
+impl Error {
+    /// Create a new error object with the given message.
+    pub fn with_msg<S: Into<String>>(msg: S) -> Error {
+        Error {
+            inner: Box::new(ErrorInner::Msg(msg.into())),
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.inner)
+    }
+}
+
+impl From<io::Error> for Error {
+    fn from(e: io::Error) -> Self {
+        Error {
+            inner: Box::new(ErrorInner::IoError(e)),
+        }
+    }
+}
+
+#[derive(Debug)]
+enum ErrorInner {
+    Msg(String),
+    IoError(io::Error),
+}
+
+impl fmt::Display for ErrorInner {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ErrorInner::Msg(ref s) => write!(f, "{}", s),
+            ErrorInner::IoError(ref e) => write!(f, "{}", e),
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_types.rs
@@ -0,0 +1,74 @@
+//! Generate sources with type info.
+//!
+//! This generates a `types.rs` file which is included in
+//! `lib/codegen/ir/types.rs`. The file provides constant definitions for the
+//! most commonly used types, including all of the scalar types.
+//!
+//! This ensures that the metaprogram and the generated program see the same
+//! type numbering.
+
+use cdsl::types as cdsl_types;
+use error;
+use srcgen;
+
+/// Emit a constant definition of a single value type.
+fn emit_type(ty: &cdsl_types::ValueType, fmt: &mut srcgen::Formatter) -> Result<(), error::Error> {
+    let name = ty.name().to_uppercase();
+    let number = ty.number().ok_or_else(|| {
+        error::Error::with_msg(format!(
+            "Could not emit type `{}` which has no number.",
+            name
+        ))
+    })?;
+
+    let definition = format!("pub const {}: Type = Type({:#x});\n", name, number);
+
+    fmt.doc_comment(&ty.doc());
+    fmt.line(&definition);
+
+    Ok(())
+}
+
+/// Emit definition for all vector types with `bits` total size.
+fn emit_vectors(bits: u64, fmt: &mut srcgen::Formatter) -> Result<(), error::Error> {
+    let vec_size: u64 = bits / 8;
+    for vec in cdsl_types::ValueType::all_lane_types()
+        .map(|ty| (ty, cdsl_types::ValueType::from(ty).membytes()))
+        .filter(|&(_, lane_size)| lane_size != 0 && lane_size < vec_size)
+        .map(|(ty, lane_size)| (ty, vec_size / lane_size))
+        .map(|(ty, lanes)| cdsl_types::VectorType::new(ty, lanes))
+    {
+        emit_type(&cdsl_types::ValueType::from(vec), fmt)?;
+    }
+
+    Ok(())
+}
+
+/// Emit types using the given formatter object.
+fn emit_types(fmt: &mut srcgen::Formatter) -> Result<(), error::Error> {
+    // Emit all of the special types, such as types for CPU flags.
+    for spec in cdsl_types::ValueType::all_special_types().map(|ty| cdsl_types::ValueType::from(ty))
+    {
+        emit_type(&spec, fmt)?;
+    }
+
+    // Emit all of the lane types, such integers, floats, and booleans.
+    for ty in cdsl_types::ValueType::all_lane_types().map(cdsl_types::ValueType::from) {
+        emit_type(&ty, fmt)?;
+    }
+
+    // Emit vector definitions for common SIMD sizes.
+    for vec_size in &[64_u64, 128, 256, 512] {
+        emit_vectors(*vec_size, fmt)?;
+    }
+
+    Ok(())
+}
+
+/// Generate the types file.
+pub fn generate(filename: &str, out_dir: &str) -> Result<(), error::Error> {
+    let mut fmt = srcgen::Formatter::new();
+    emit_types(&mut fmt)?;
+    fmt.update_file(filename, out_dir)?;
+    Ok(())
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/lib.rs
@@ -0,0 +1,6 @@
+pub mod error;
+pub mod gen_types;
+
+mod base;
+mod cdsl;
+mod srcgen;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/srcgen.rs
@@ -0,0 +1,316 @@
+//! Source code generator.
+//!
+//! The `srcgen` module contains generic helper routines and classes for
+//! generating source code.
+
+use std::collections::{BTreeMap, HashSet};
+use std::fs;
+use std::io::Write;
+use std::path;
+
+use error;
+
+static SHIFTWIDTH: usize = 4;
+
+struct _IndentedScope {
+    fmt: Formatter,
+    after: Option<String>,
+}
+
+impl _IndentedScope {
+    fn _enter(&mut self) {
+        self.fmt._indent_push();
+    }
+
+    fn _exit(&mut self) {
+        self.fmt._indent_pop();
+        if let Some(ref s) = self.after {
+            self.fmt.line(&s);
+        }
+    }
+}
+
+pub struct Formatter {
+    indent: usize,
+    lines: Vec<String>,
+}
+
+impl Formatter {
+    /// Source code formatter class. Used to collect source code to be written
+    /// to a file, and keep track of indentation.
+    pub fn new() -> Formatter {
+        Formatter {
+            indent: 0,
+            lines: Vec::new(),
+        }
+    }
+
+    /// Increase current indentation level by one.
+    pub fn _indent_push(&mut self) {
+        self.indent += 1;
+    }
+
+    /// Decrease indentation by one level.
+    pub fn _indent_pop(&mut self) {
+        assert!(self.indent > 0, "Already at top level indentation");
+        self.indent -= 1;
+    }
+
+    /// Get the current whitespace indentation in the form of a String.
+    fn get_indent(&self) -> String {
+        if self.indent == 0 {
+            String::new()
+        } else {
+            format!("{:-1$}", " ", self.indent * SHIFTWIDTH)
+        }
+    }
+
+    /// Get a string containing whitespace outdented one level. Used for
+    /// lines of code that are inside a single indented block.
+    fn _get_outdent(&mut self) -> String {
+        self._indent_push();
+        let s = self.get_indent();
+        self._indent_pop();
+        s
+    }
+
+    /// Add an indented line.
+    pub fn line(&mut self, contents: &str) {
+        let indented_line = format!("{}{}\n", self.get_indent(), contents);
+        self.lines.push(indented_line);
+    }
+
+    /// Emit a line outdented one level.
+    pub fn _outdented_line(&mut self, s: &str) {
+        let new_line = format!("{}{}", self._get_outdent(), s);
+        self.lines.push(new_line);
+    }
+
+    /// Write `self.lines` to a file.
+    pub fn update_file(&self, filename: &str, directory: &str) -> Result<(), error::Error> {
+        #[cfg(target_family = "windows")]
+        let path_str = format!("{}\\{}", directory, filename);
+        #[cfg(not(target_family = "windows"))]
+        let path_str = format!("{}/{}", directory, filename);
+
+        let path = path::Path::new(&path_str);
+        let mut f = fs::File::create(path)?;
+
+        for l in self.lines.iter().map(|l| l.as_bytes()) {
+            f.write_all(l)?;
+        }
+
+        Ok(())
+    }
+
+    /// Return a scope object for use with a `with` statement.
+    /// The optional `before` and `after` parameters are surrounding lines
+    /// which are *not* indented.
+    fn _indented(&self, _before: Option<&str>, _after: Option<&str>) -> _IndentedScope {
+        unimplemented!();
+    }
+
+    /// Add one or more lines after stripping common indentation.
+    pub fn _multi_line(&mut self, s: &str) {
+        parse_multiline(s).into_iter().for_each(|l| self.line(&l));
+    }
+
+    /// Add a comment line.
+    pub fn _comment(&mut self, s: &str) {
+        let commented_line = format!("// {}", s);
+        self.line(&commented_line);
+    }
+
+    /// Add a (multi-line) documentation comment.
+    pub fn doc_comment(&mut self, contents: &str) {
+        parse_multiline(contents)
+            .iter()
+            .map(|l| format!("/// {}", l))
+            .for_each(|s| self.line(s.as_str()));
+    }
+
+    /// Add a match expression.
+    fn _add_match(&mut self, _m: &_Match) {
+        unimplemented!();
+    }
+}
+
+/// Compute the indentation of s, or None of an empty line.
+fn _indent(s: &str) -> Option<usize> {
+    if s.is_empty() {
+        None
+    } else {
+        let t = s.trim_left();
+        Some(s.len() - t.len())
+    }
+}
+
+/// Given a multi-line string, split it into a sequence of lines after
+/// stripping a common indentation. This is useful for strings defined with
+/// doc strings.
+fn parse_multiline(s: &str) -> Vec<String> {
+    // Convert tabs into spaces.
+    let expanded_tab = format!("{:-1$}", " ", SHIFTWIDTH);
+    let lines: Vec<String> = s.lines().map(|l| l.replace("\t", &expanded_tab)).collect();
+
+    // Determine minimum indentation, ignoring the first line.
+    let indent = lines
+        .iter()
+        .skip(1)
+        .map(|l| l.len() - l.trim_left().len())
+        .filter(|&i| i > 0)
+        .min();
+
+    // Strip off leading blank lines.
+    let mut lines_iter = lines.iter().skip_while(|l| l.is_empty());
+    let mut trimmed = Vec::with_capacity(lines.len());
+
+    // Remove indentation (first line is special)
+    if let Some(s) = lines_iter.next().map(|l| l.trim()).map(|l| l.to_string()) {
+        trimmed.push(s);
+    }
+
+    // Remove trailing whitespace from other lines.
+    let mut other_lines = if let Some(indent) = indent {
+        lines_iter
+            .map(|l| &l[indent..])
+            .map(|l| l.trim_right())
+            .map(|l| l.to_string())
+            .collect::<Vec<_>>()
+    } else {
+        lines_iter
+            .map(|l| l.trim_right())
+            .map(|l| l.to_string())
+            .collect::<Vec<_>>()
+    };
+
+    trimmed.append(&mut other_lines);
+
+    // Strip off trailing blank lines.
+    while let Some(s) = trimmed.pop() {
+        if s.is_empty() {
+            continue;
+        } else {
+            trimmed.push(s);
+            break;
+        }
+    }
+
+    trimmed
+}
+
+/// Match formatting class.
+///
+/// Match objects collect all the information needed to emit a Rust `match`
+/// expression, automatically deduplicating overlapping identical arms.
+///
+/// Note that this class is ignorant of Rust types, and considers two fields
+/// with the same name to be equivalent. A BTreeMap is used to represent the
+/// arms in order to make the order deterministic.
+struct _Match<'a> {
+    _expr: &'a str,
+    arms: BTreeMap<(Vec<&'a str>, &'a str), HashSet<&'a str>>,
+}
+
+impl<'a> _Match<'a> {
+    /// Create a new match statement on `expr`.
+    fn _new(expr: &'a str) -> Self {
+        Self {
+            _expr: expr,
+            arms: BTreeMap::new(),
+        }
+    }
+
+    /// Add an arm to the Match statement.
+    fn _arm(&mut self, name: &'a str, fields: Vec<&'a str>, body: &'a str) {
+        // let key = (fields, body);
+        let match_arm = self.arms.entry((fields, body)).or_insert_with(HashSet::new);
+        match_arm.insert(name);
+    }
+}
+
+#[cfg(test)]
+mod srcgen_tests {
+    use super::_Match;
+    use super::parse_multiline;
+    use super::Formatter;
+
+    #[test]
+    fn adding_arms_works() {
+        let mut m = _Match::_new("x");
+        m._arm("Orange", vec!["a", "b"], "some body");
+        m._arm("Yellow", vec!["a", "b"], "some body");
+        m._arm("Green", vec!["a", "b"], "different body");
+        m._arm("Blue", vec!["x", "y"], "some body");
+        assert_eq!(m.arms.len(), 3);
+    }
+
+    #[test]
+    fn parse_multiline_works() {
+        let input = "\n    hello\n    world\n";
+        let expected = vec!["hello", "world"];
+        let output = parse_multiline(input);
+        assert_eq!(output, expected);
+    }
+
+    #[test]
+    fn formatter_basic_example_works() {
+        let mut fmt = Formatter::new();
+        fmt.line("Hello line 1");
+        fmt._indent_push();
+        fmt._comment("Nested comment");
+        fmt._indent_pop();
+        fmt.line("Back home again");
+        let expected_lines = vec![
+            "Hello line 1\n",
+            "    // Nested comment\n",
+            "Back home again\n",
+        ];
+        assert_eq!(fmt.lines, expected_lines);
+    }
+
+    #[test]
+    fn get_indent_works() {
+        let mut fmt = Formatter::new();
+        let expected_results = vec!["", "    ", "        ", ""];
+
+        let actual_results = Vec::with_capacity(4);
+        (0..3).for_each(|_| {
+            fmt.get_indent();
+            fmt._indent_push();
+        });
+        (0..3).for_each(|_| fmt._indent_pop());
+        fmt.get_indent();
+
+        actual_results
+            .into_iter()
+            .zip(expected_results.into_iter())
+            .for_each(|(actual, expected): (String, &str)| assert_eq!(&actual, expected));
+    }
+
+    #[test]
+    fn fmt_can_add_type_to_lines() {
+        let mut fmt = Formatter::new();
+        fmt.line(&format!("pub const {}: Type = Type({:#x});", "example", 0,));
+        let expected_lines = vec!["pub const example: Type = Type(0x0);\n"];
+        assert_eq!(fmt.lines, expected_lines);
+    }
+
+    #[test]
+    fn fmt_can_add_indented_line() {
+        let mut fmt = Formatter::new();
+        fmt.line("hello");
+        fmt._indent_push();
+        fmt.line("world");
+        let expected_lines = vec!["hello\n", "    world\n"];
+        assert_eq!(fmt.lines, expected_lines);
+    }
+
+    #[test]
+    fn fmt_can_add_doc_comments() {
+        let mut fmt = Formatter::new();
+        fmt.doc_comment("documentation\nis\ngood");
+        let expected_lines = vec!["/// documentation\n", "/// is\n", "/// good\n"];
+        assert_eq!(fmt.lines, expected_lines);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"7d2b91fa0c8cba9be977b41f792fd41646183b455b8736f1c617fa55c7abf454","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"ea5ff1e3ebe7f6f06f9c39c2458268fea3aceb8121d31a3ad311b391631e8408","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"0e146dd56dfb93cac88f9557a3501c9804cff584c2723db27435842bb5e2a1b7","meta-python/base/formats.py":"791e5321fa5030a8a247f3d6e2e395e013e477be3e08059b2ccda66cece96bf9","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"df02d335baf5eba7f1b607b058cf4412cab0c1c81e026cbee923f74146419b77","meta-python/base/legalize.py":"e677e7c97547847731a23fd0fb2a695881beaee6991a7b7a3bb10157c9a17c1c","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"b59efbf787aeae5117eb89f05fc494b6b84e414e7be360613f30adfee6b3d318","meta-python/base/types.py":"98bdfe14ef94090ba8dfbe3e3ca1135e4e2ece4e25d6bac4d15dc72d9a1e5d21","meta-python/build.py":"7aab54a39b555fec3eb9fd771cb2d9467708e3402f8411e88cf11cb32d0c44ca","meta-python/cdsl/__init__.py":"b531693b8228553ca8bd07e1dcd1aa5855f1ad3741b431d758fc27fdd162b024","meta-python/cdsl/ast.py":"552a9a74aa19031ec730912a1e83e405738de9c4df0ddc7fd811b4bd8c2f40fc","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"9ba1b30ed90f2192845e22093179338f2f47e6fe7e15c583cbda2879c006a751","meta-python/cdsl/isa.py":"92bd937c833015f4808f7550f517c4cbc09c6c2e16ecc663d33abb551d124020","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"8663e3b797c7a7313e940456be1d90c3c3cec022aa523b9a9e76fa17e7af51d3","meta-python/cdsl/registers.py":"a8cee541134d34d732926a43f31eb388f684974103d1b1a9645164b0446a3b90","meta-python/cdsl/settings.py":"18dc27dd98a82c814c6aeb2686b40d1fed23661bef5e8b4cbf0fb4e7d39f4755","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"06ac251260a6623d2d58ffbc94529d5faf45a49e5b9c7ec575a84201eb18bece","meta-python/cdsl/test_typevar.py":"714b2d564af1a843629279501436d681cd6590d1988b59e9f50ec940506538bb","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"60019250844ce6b1cdc197f78e02a037223aa65eb18cfb5f17369d84d93d4fe7","meta-python/cdsl/types.py":"d332fe96c0be47d33f651b6cb6339a8c91e7e170832ec2f27b8a5b02bd549a6a","meta-python/cdsl/typevar.py":"a1a405149343011255ff69edb44cf5f960559d1351b6ec07cf6d0bd668d87c4b","meta-python/cdsl/xform.py":"b9db7dd9a4b32e2cfc34def1d2e3213f1fb250a0f66b3aca2c1f30129437d4b6","meta-python/check.sh":"9e2f70f2d762c840f1d49519b024b4c1b93168137184b5e3e605e55813c62ea5","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"3920c5c89451c26102f7d87c61de64c94e915a545bc8a35d2e49106aecf019ec","meta-python/gen_encoding.py":"73a216007ec6e90acf74f51657516de0465fbb692d08c9db0885b1c2aec502a9","meta-python/gen_instr.py":"e9f71675ebc82ee6151c1d671449418939f1e258a504f9b16bebe799788771df","meta-python/gen_legalizer.py":"187a47f1702e07487fb8a13076aadcf9c2de3e801d367424dc847ff7b0ed70f1","meta-python/gen_registers.py":"cfde66d3d75ac7e647afa5a0a7051f5fc1ac757cf142b497f549e57ceb6ff54b","meta-python/gen_settings.py":"44c231ab8d2aa4f18cbe4fb5a33fb72103503d58f5af22c7b545eeffbf97da79","meta-python/gen_types.py":"0cff50db1ecebc2ba67d7e02ed6ab975713d460083cb03ee8a9bc58d021e3ca2","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"bfc32c901e3e5f46cb6d50167736b967862d2e4f54535986ce20b38f933e4588","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"b964bd028aedc5422e1ef3a088f456dac4feb10e6d310858cee9245479fa3547","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"f92e8b3007198bb85139172d2d19fb5b3462d92012282e1877b05e1c07673332","meta-python/isa/x86/registers.py":"60a9f42fede6330cd7ef001d85ece9f7095cbc20fc4004de65a3dd9972236293","meta-python/isa/x86/settings.py":"d779a768475cf00c2a8d3ddb5cd0a70ce34662e0ebb52ee26a7e1a495ec41aa2","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"3df36e0a986fd90d0b69740b02671251ecd2853873998dcb6d379894a4f9460b","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"825edfbb9221bf59c02fea26e55d17cf32194da7a9f56ed0e035c44353481055","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_gen_legalizer.py":"f16edce7cb2ce53e55b1fc56b6f5ba6a0fc61b291ee4513ec859e36d69f0e285","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"29f505fdfcb6ec14e561bb408b99ab30ab69b96d1e283a1dcd55db9aff02dbe4","src/binemit/memorysink.rs":"85adb793c5eb5711aca64534225eb4fc98ae0c79cea42dd6d86e9c193dec97cc","src/binemit/mod.rs":"95ed53492873dfbed44cd185085740ab20f9e7543a26855f0466e7a607f6ff54","src/binemit/relaxation.rs":"dd8b50f32ba9688c7f6d0e2957c120192e3d26d8301db405038ab1ece4777746","src/binemit/shrink.rs":"6b5622701f4496c6fc540555236716749f053e126102f73e63b03f3306e50670","src/bitset.rs":"67fd02dd2acb9af73e45426e5cab1d2a74d568a11d11ee17ae6a4421f96cf741","src/cfg_printer.rs":"1bbe85c44002222c38a54f1c741f99e4ba6eb1e90e377907e62504ede847ef93","src/constant_hash.rs":"493cdf8f607eab01bb52f93d616fb6190c7c86d3a02e530b0ced30993d4bfda0","src/context.rs":"29222884fd459d3d056ab1f490165a7bb8b9d27fe1ed297fd8f06a6ad7c9f46f","src/cursor.rs":"7dd7cc957c0d1ad0850162b6a0d3f13b8f0d8cc00e22d481458df7b2486611a7","src/dbg.rs":"bae915e1f7544f725817b368aed00a6aaa9e394a454dc847d65ad44e54d78cb9","src/dce.rs":"6d015824ae0325f01bb523606d7e15dd5feeb72a75b947f40385feeba94555c8","src/divconst_magic_numbers.rs":"eac50e2353e17ab6f7d1da3bd8e0e8dc9e3122a160efba594d407eb6a8936cc7","src/dominator_tree.rs":"595031c03afa61020b26eb071a26d6c4949361f5e4e0e8b516e5a04adf200fe3","src/flowgraph.rs":"337341ed7d9070e46fc0048f1069a95c985ffe4b405f9a10e606a38b5e05851f","src/fx.rs":"2fb53f141b3e6be1882a1e4afac4bc607ce694f045d9329ee823e0aca415898e","src/ir/builder.rs":"740fead2c1986e5f3a836de06b37e6a45188a7d40c64f86c5097624e92c6e9d6","src/ir/condcodes.rs":"5456a25798516245b0923c9e12ae0af5cc98c097fc6f3bc0bf2d7af5008667f7","src/ir/dfg.rs":"0e61ea5a0515a73ae57d7625b0a67d82d6f8b5c0ba6673d1eae0d3b48745edbc","src/ir/entities.rs":"1505347c2baa256b04f69384d1391f52e007d533cb4319d3826cf3046ec1df27","src/ir/extfunc.rs":"69a838ddeb29fec19c6b308540259b971eb85be0fbab84647d68bd36d1f79c3d","src/ir/extname.rs":"839e3d694e5c109bb594fe31c7d9dfe4f156bbc2eb695f3412fd39c325374b91","src/ir/function.rs":"05808190e4764acdda07dd2f5750853310f06aa8848e3612dfce074f17837261","src/ir/globalvalue.rs":"8c9bc996332f6c7cb549a1d1296ed9f5783d364c1a5c9b5250745d412729f2be","src/ir/heap.rs":"dc9d4f0eade20d58b3e2678c329452fbd5965c46d6121cbf5889f2588ae88772","src/ir/immediates.rs":"0f1806af474a6bef2a4a488fae7b42482c6b05b4cf658069c6881b48b6b68ab0","src/ir/instructions.rs":"40a41505497fc03d2e0f25b3739378252a94566383b446016fa3be0879ddc1c8","src/ir/jumptable.rs":"7dae4bbc9538d05a6fc969800146327eb96b7d75aff976807edece5c6166537c","src/ir/layout.rs":"daf934675b0cfc227080538cfa2329b519f748dcc9e21539ba903670801b86a1","src/ir/libcall.rs":"c4405665b00fc199c520e6b5d637189736307e69793db6ada67242feecabc852","src/ir/memflags.rs":"988a07cf60facaee75c867b093332e311664ecfe405e2cf29ef5c59376f2ef61","src/ir/mod.rs":"2ac265cd091915aee161dd34c34f3b17d3590412bc41c09c763fa2d92a6bb626","src/ir/progpoint.rs":"d5191447f82bb612ae25ebceb5ecc2099a902be5aaecd5b9d418dcbd8a2747a5","src/ir/sourceloc.rs":"79eb71609b844839994fc735cd72edf53179eb659303a4150634928e207cee4f","src/ir/stackslot.rs":"669fb7b1692012d7c51fa53c3a1e49774045fc68d9c4a47995aeb7fb3e0027d4","src/ir/table.rs":"810e92631257e1e54577563df1da9709134438d0eab3db5e540500e69437a16b","src/ir/trapcode.rs":"233d73e4a2abbfc767aac7868d4adbb24cedaf8e7e42a640d590bda2e776784a","src/ir/types.rs":"50c3b48a60be236b37342063ee473ec4115d6d965a12673ac1588b050025f030","src/ir/valueloc.rs":"5055897d9acba6d9c396b126889f9b2c7ff3f54a27c1ec5fe70d1a059d633b36","src/isa/arm32/abi.rs":"50ca3161a0f11ba1c2d5b0ff7523d332503cb6a6182695246e4284a486e18cab","src/isa/arm32/binemit.rs":"3197df7b15c223f3a9f2708311375ff423bb247381cf21e26da079f7933f5279","src/isa/arm32/enc_tables.rs":"dacb50bdacfa2085a6283818563e19874590d223e5decb5c91b968e0348e2bf7","src/isa/arm32/mod.rs":"da68e5ad27697b75ef34440cea045d077d8050026b6f279e40536c44be64a1b3","src/isa/arm32/registers.rs":"0e5c32a218d685c6d37fb46788baedf6bede6be7d4f715808c13620636dfc472","src/isa/arm32/settings.rs":"145f59227c6087e7872f66a6d2183c66e061c40466e7b427a733136e41e41207","src/isa/arm64/abi.rs":"bfd0065a6c26eb407872959c9d7f64169591afa4d69816370e0900aa1ad4e46f","src/isa/arm64/binemit.rs":"159ab9eca03ac4aa7f55d51ab20585a5971d95a74c61953d1899ac863b06e2ec","src/isa/arm64/enc_tables.rs":"00ec8f53402f6cb73716db1adb3aca564574833cab58dc12b4dc6ba8c4529a73","src/isa/arm64/mod.rs":"be67ce9475a2b2fdeee12ff4eae76fe3d2a6919807f1d015b501e16135e82471","src/isa/arm64/registers.rs":"7a8b207ed28737efc737e8e65ce79e7e7d3eecd23599890230dca8474c985026","src/isa/arm64/settings.rs":"7b466fcc2c58bc1846a72f08ec58900b3cf622ab2922ee9128e6dfe254907bf5","src/isa/constraints.rs":"324d7c8655565f13b90a6c9587c9fb6c545ab3086201f434e1324fc5d6e5b3c7","src/isa/enc_tables.rs":"b6cf1a2e58a34170360681f517d89bb7aac1ed7586792e3d36156ca7326abcc5","src/isa/encoding.rs":"c8746f8c432a02e092dae80a9342734da760ad055854d598ffb395a47ed9d884","src/isa/mod.rs":"f86fad997fd136a3c44c70d3d7ca221a6bce64e8c1e69bea32fe1554bca9642b","src/isa/registers.rs":"9116fa8eb488b5d1e96f6718825cc4220a3f283ba629548a44267167c9683df8","src/isa/riscv/abi.rs":"1de6d0070126e0127ca6a63551a14d1b5c030cf9628538fd732301fd2bd34b5e","src/isa/riscv/binemit.rs":"3bdad2791447f51bfe5ecedb73b1aed8a6a8809790b1f26e3ff624a89163a026","src/isa/riscv/enc_tables.rs":"9c0303ef10098dc0a99021cddc3432e222874bff1d4b8f8ddc7daa05c6b77ddb","src/isa/riscv/mod.rs":"9a7a6ca8ba9273f772b3b7507072ec46975d067f572f71d86067bb8ed854b077","src/isa/riscv/registers.rs":"794ac61343a8db66dc99b2ca964ea3986b47b37fe8b72575c644c1cdaabd2991","src/isa/riscv/settings.rs":"78ced69b82d89f83b5612a91d0acdac2616f9091b380ee3e4715adb31f95b232","src/isa/stack.rs":"ec96130c446cd7d637722f1603e38d5164498368b652f4b0454baf3227385ad4","src/isa/x86/abi.rs":"bccfac45421a01002aae42acf8a14fdbc17e44299f08e10abaf0507578e744e3","src/isa/x86/binemit.rs":"48df284ed2cff76cea1e94cd08a6badd513787123ddf4984c495d745d6e59756","src/isa/x86/enc_tables.rs":"ac913a8fc45b1d5a863ce3dd760692e32ccb5f4f47fadd6b9f26f9df51b963d2","src/isa/x86/mod.rs":"146d059936b85ceb4983b3bcc9b875b7eaccbc5c1a9d34c435b8c4f7a737d87d","src/isa/x86/registers.rs":"783ebbe4c3b4711fe1eac2cfd3bbea7c31a53c15c6028397c038ef4eb0b2aa06","src/isa/x86/settings.rs":"dcce098045c1115cd55f256dcd3e0ccaa5a0c9ad93b14fb8a4c680e95caf2b73","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"d070da577a4a11a3bed9adbfdf94bec8aff368b4d176b1b85a44739545561a1c","src/legalizer/call.rs":"12f380d126765f0bc2da1cf298088fa98451e2d6bf56c34b755ff7077d14a4f1","src/legalizer/globalvalue.rs":"eb5d19a653928e2da0b78e38555b1d41f9549eeeca9fb6295a7dc5197ebd3c3f","src/legalizer/heap.rs":"c44a0845254187dfe7456b0b9efbfea25ae566772bc64b41ed93dd32a71f8e8a","src/legalizer/libcall.rs":"bf18267f502bf9bfbc3ff51bc05df480293a84422ea7f4c37dd0c75e97952766","src/legalizer/mod.rs":"c3707143cdd2b215b15ce7c0fa95d0df36a2cbf2e13dbe08d7166afa2e416f7a","src/legalizer/split.rs":"ae07854aad2ff2aa83a6ba08276b49a462dda0591faa9a61bdc7ca787451078f","src/legalizer/table.rs":"2aca27ea564c2ef02ed833c495156b9e1ddcee3c8a1b1e70347ab5907a381605","src/lib.rs":"95e48756b120856a91094e76c0acfc34abe86d93fe0bb9771063e7aec1af8315","src/licm.rs":"9657ccfdcf7a52eca1ba201d455f1d538f17aaa6295b9651282de9f7c79a53b9","src/loop_analysis.rs":"9b622be0af7a36f9ed2fb91bd4b6905785b63e0fc88d5765dd5f18a06f2f7834","src/nan_canonicalization.rs":"e2b1f9935d14af9abe553de1eda5483cffdaa7098dd1a17ba9a98fa04280b22c","src/partition_slice.rs":"55b9e857f452baf4d6312779861f9ef93b3d5300467e752230ec6af14943efe3","src/postopt.rs":"6a182d8646d6964c7137320bcd4b3c5cada62cac31a34e41050d3d6eeeaa9a98","src/predicates.rs":"fdb15850c86b9b45a13a1e791ef51ce843460b20e360d44dbdfdf198f59dc40d","src/preopt.rs":"cfafd0398bba0b3e2b91b5bf10617bd4048ba2b22345b3e5bfc403239903960a","src/print_errors.rs":"89b9f516c0567bada88e8fa9aea7d8e9f5acadbaea3ae5cb8215619433f1e5ee","src/ref_slice.rs":"9be914b705eefcc6b4e38db573f56ad7b978f4b65c2f6f8f5516df78fb2206a4","src/regalloc/affinity.rs":"47e28f9ae7cebfc9b1006480143a3a5ab1b118ec761a163c4a670b63fdc47d0a","src/regalloc/coalescing.rs":"253e3fb916c37453f0fa4f963caf5336712d60447e39f63a6696c2ad22cb102f","src/regalloc/coloring.rs":"fdcb1bda766220a7be0f815d8431e317dfc007a409c2c095948b45032a98c3e7","src/regalloc/context.rs":"794f9f0fb3b980feb3be57b95c152767cb318b81aca48c27197b01b7d529c48d","src/regalloc/diversion.rs":"cbb942a197081f9e537f3fed71a7ec6d6d1edc18b8536fa46a1dda316f46c776","src/regalloc/live_value_tracker.rs":"054efd9e8da0f33a158082f67a7c2c14f7c8632b1fc28d54941ca7bc9d5a46d6","src/regalloc/liveness.rs":"b21e4855c0339c1b15b1b62e63bb1a569c4256b42d08c3c21b6e7fc4634c5e62","src/regalloc/liverange.rs":"c7395c8c3709996f8d17a196af541ddbb37a9a20b1c3c151dd10628000ece337","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"7c73ca1f54559b1d9f8ce587bdc067e74f3d47901058f7ae1e9277516624236f","src/regalloc/register_set.rs":"e1554d01a3a5a13acc4e0092681eb3fc090d9c68eb71f8a9985c01c7a3f2e3e2","src/regalloc/reload.rs":"cab64c91c57831d17e7e5ec217639f127b7608aedbfcb3c25cf3b9dfae36812d","src/regalloc/solver.rs":"853c6f16f68e75add56981b132d92e556a94d8cbd13fed311df2d75da08de03a","src/regalloc/spilling.rs":"eb7c625395c790ada187c0938dbcca6d43426a7f6d4a9ef0317778790a9dc38f","src/regalloc/virtregs.rs":"fb06b52b9b8ab0e139cb03105785ca94057c08c9277423317fb4c0040844ddde","src/result.rs":"d43abf9b22c5ad772200889bba339bcc4455c7abb9f2f3a2af65fbbaf1130009","src/scoped_hash_map.rs":"102797c380a588f7c16d26bf3b6c9cff28d37c2d8168a382b265194cd8969212","src/settings.rs":"2b0ddf77a4e18cf15292673502150b6b0af4d22ba03be9d1aadb654b6c1f91e1","src/simple_gvn.rs":"4d765fe40c527cbcac287a59d513dcc7b983d060893017579ec2b4f57b1411fc","src/stack_layout.rs":"ce0b4b188cc46fa5070139124ffb2d263d44acd08703e7043a40b5c1afa952fb","src/timing.rs":"d974dc0498ee814e90c5ecaaf60949f1b8d97213c4676114ed3d88affac56a02","src/topo_order.rs":"4ea901ec69bc1112ae496f26fea7de1f48cb2f1c1726525b367496fd3b4b3f23","src/unreachable_code.rs":"6fdea8f9afe9fbffe411bfef48fec7937cb41d51036fd190a3d0a5f0cc2894c6","src/verifier/cssa.rs":"8f41765d18474575faa7c44a0345549dabe0af07141e2f004a7db1c67486ce77","src/verifier/flags.rs":"80ecfdac53899ab4f35e8ba3f948b8cb32768184608bc0864029cf6d953d6c5c","src/verifier/liveness.rs":"6e827f05461bd6fb21b0ce99f02fae374f2d6ea6e7e14ba61e88983a1c6fac4b","src/verifier/locations.rs":"c3fbc688e021f5dabf20ea435cfa09da5e757229de6d9ef0465522898f44d0bd","src/verifier/mod.rs":"8fa2e17ef36a0a265b617a696edca33dc9fc5bcce5aace1519214f58d102bc60","src/write.rs":"f3bec214b6f6ef8f1ce11e056a5b14365d2adc122bbf725127b6ebb04c8dcc5b"},"package":"16f418f1d1e6221812a7d35cff5b9a572dc978c002e33792134bbd50c07cacca"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/Cargo.toml
@@ -0,0 +1,65 @@
+# 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]
+name = "cranelift-codegen"
+version = "0.20.0"
+authors = ["The Cranelift Project Developers"]
+build = "build.rs"
+description = "Low-level code generator library"
+documentation = "https://cranelift.readthedocs.io/"
+readme = "README.md"
+keywords = ["compile", "compiler", "jit"]
+categories = ["no-std"]
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/CraneStation/cranelift"
+[dependencies.cranelift-bforest]
+version = "0.20.0"
+default-features = false
+
+[dependencies.cranelift-entity]
+version = "0.20.0"
+default-features = false
+
+[dependencies.failure]
+version = "0.1.1"
+features = ["derive"]
+default-features = false
+
+[dependencies.failure_derive]
+version = "0.1.1"
+default-features = false
+
+[dependencies.hashmap_core]
+version = "0.1.9"
+optional = true
+
+[dependencies.log]
+version = "0.4.4"
+features = ["release_max_level_warn"]
+default-features = false
+
+[dependencies.target-lexicon]
+version = "0.0.3"
+default-features = false
+[build-dependencies.cranelift-codegen-meta]
+version = "0.20.0"
+
+[features]
+core = ["hashmap_core"]
+default = ["std"]
+std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"]
+[badges.maintenance]
+status = "experimental"
+
+[badges.travis-ci]
+repository = "CraneStation/cranelift"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/LICENSE
@@ -0,0 +1,219 @@
+
+                                 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.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/README.md
@@ -0,0 +1,2 @@
+This crate contains the core Cranelift code generator. It translates code from an
+intermediate representation into executable machine code.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/build.rs
@@ -0,0 +1,184 @@
+// Build script.
+//
+// This program is run by Cargo when building lib/codegen. It is used to generate Rust code from
+// the language definitions in the lib/codegen/meta directory.
+//
+// Environment:
+//
+// OUT_DIR
+//     Directory where generated files should be placed.
+//
+// TARGET
+//     Target triple provided by Cargo.
+//
+// CRANELIFT_TARGETS (Optional)
+//     A setting for conditional compilation of isa targets. Possible values can be "native" or
+//     known isa targets separated by ','.
+//
+// The build script expects to be run from the directory where this build.rs file lives. The
+// current directory is used to find the sources.
+
+extern crate cranelift_codegen_meta as meta;
+
+use std::env;
+use std::process;
+
+fn main() {
+    let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
+    let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
+    let cranelift_targets = env::var("CRANELIFT_TARGETS").ok();
+    let cranelift_targets = cranelift_targets.as_ref().map(|s| s.as_ref());
+    let python = identify_python();
+
+    // Configure isa targets cfg.
+    match isa_targets(cranelift_targets, &target_triple) {
+        Ok(isa_targets) => {
+            for isa in &isa_targets {
+                println!("cargo:rustc-cfg=build_{}", isa.name());
+            }
+        }
+        Err(err) => {
+            eprintln!("Error: {}", err);
+            process::exit(1);
+        }
+    }
+
+    println!("Build script generating files in {}", out_dir);
+
+    let cur_dir = env::current_dir().expect("Can't access current working directory");
+    let crate_dir = cur_dir.as_path();
+
+    // Make sure we rebuild if this build script changes.
+    // I guess that won't happen if you have non-UTF8 bytes in your path names.
+    // The `build.py` script prints out its own dependencies.
+    println!(
+        "cargo:rerun-if-changed={}",
+        crate_dir.join("build.rs").to_str().unwrap()
+    );
+
+    // Scripts are in `$crate_dir/meta-python`.
+    let meta_dir = crate_dir.join("meta-python");
+    let build_script = meta_dir.join("build.py");
+
+    // Launch build script with Python. We'll just find python in the path.
+    // Use -B to disable .pyc files, because they cause trouble for vendoring
+    // scripts, and this is a build step that isn't run very often anyway.
+    let status = process::Command::new(python)
+        .current_dir(crate_dir)
+        .arg("-B")
+        .arg(build_script)
+        .arg("--out-dir")
+        .arg(out_dir.clone())
+        .status()
+        .expect("Failed to launch second-level build script; is python installed?");
+    if !status.success() {
+        process::exit(status.code().unwrap());
+    }
+
+    // DEVELOPMENT:
+    // ------------------------------------------------------------------------
+    // Now that the Python build process is complete, generate files that are
+    // emitted by the `meta` crate.
+    // ------------------------------------------------------------------------
+    if let Err(err) = meta::gen_types::generate("new_types.rs", &out_dir) {
+        eprintln!("Error: {}", err);
+        process::exit(1);
+    }
+}
+
+fn identify_python() -> &'static str {
+    for python in &["python", "python3", "python2.7"] {
+        if process::Command::new(python)
+            .arg("--version")
+            .status()
+            .is_ok()
+        {
+            return python;
+        }
+    }
+    panic!("The Cranelift build requires Python (version 2.7 or version 3)");
+}
+
+/// Represents known ISA target.
+#[derive(Copy, Clone)]
+enum Isa {
+    Riscv,
+    X86,
+    Arm32,
+    Arm64,
+}
+
+impl Isa {
+    /// Creates isa target using name.
+    fn new(name: &str) -> Option<Self> {
+        Isa::all()
+            .iter()
+            .cloned()
+            .filter(|isa| isa.name() == name)
+            .next()
+    }
+
+    /// Creates isa target from arch.
+    fn from_arch(arch: &str) -> Option<Isa> {
+        Isa::all()
+            .iter()
+            .cloned()
+            .filter(|isa| isa.is_arch_applicable(arch))
+            .next()
+    }
+
+    /// Returns all supported isa targets.
+    fn all() -> [Isa; 4] {
+        [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
+    }
+
+    /// Returns name of the isa target.
+    fn name(&self) -> &'static str {
+        match *self {
+            Isa::Riscv => "riscv",
+            Isa::X86 => "x86",
+            Isa::Arm32 => "arm32",
+            Isa::Arm64 => "arm64",
+        }
+    }
+
+    /// Checks if arch is applicable for the isa target.
+    fn is_arch_applicable(&self, arch: &str) -> bool {
+        match *self {
+            Isa::Riscv => arch == "riscv",
+            Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
+            Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
+            Isa::Arm64 => arch == "aarch64",
+        }
+    }
+}
+
+/// Returns isa targets to configure conditional compilation.
+fn isa_targets(cranelift_targets: Option<&str>, target_triple: &str) -> Result<Vec<Isa>, String> {
+    match cranelift_targets {
+        Some("native") => Isa::from_arch(target_triple.split('-').next().unwrap())
+            .map(|isa| vec![isa])
+            .ok_or_else(|| {
+                format!(
+                    "no supported isa found for target triple `{}`",
+                    target_triple
+                )
+            }),
+        Some(targets) => {
+            let unknown_isa_targets = targets
+                .split(',')
+                .filter(|target| Isa::new(target).is_none())
+                .collect::<Vec<_>>();
+            let isa_targets = targets.split(',').flat_map(Isa::new).collect::<Vec<_>>();
+            match (unknown_isa_targets.is_empty(), isa_targets.is_empty()) {
+                (true, true) => Ok(Isa::all().to_vec()),
+                (true, _) => Ok(isa_targets),
+                (_, _) => Err(format!(
+                    "unknown isa targets: `{}`",
+                    unknown_isa_targets.join(", ")
+                )),
+            }
+        }
+        None => Ok(Isa::all().to_vec()),
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/meta-python/base/__init__.py
@@ -0,0 +1,1 @@
+"""Definitions for the base Cranelift language."""
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/meta-python/base/entities.py
@@ -0,0 +1,38 @@
+"""
+The `cranelift.entities` module predefines all the Cranelift entity reference
+operand types. There are corresponding definitions in the `cranelift.entities`
+Rust module.
+"""
+from __future__ import absolute_import
+from cdsl.operands import EntityRefKind
+
+
+#: A reference to an extended basic block in the same function.
+#: This is primarliy used in control flow instructions.
+ebb = EntityRefKind(
+        'ebb', 'An extended basic block in the same function.',
+        default_member='destination')
+
+#: A reference to a stack slot declared in the function preamble.
+stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
+
+#: A reference to a global value.
+global_value = EntityRefKind('global_value', 'A global value.')
+
+#: A reference to a function sugnature declared in the function preamble.
+#: This is used to provide the call signature in a call_indirect instruction.
+sig_ref = EntityRefKind('sig_ref', 'A function signature.')
+
+#: A reference to an external function declared in the function preamble.
+#: This is used to provide the callee and signature in a call instruction.
+func_ref = EntityRefKind('func_ref', 'An external function.')
+
+#: A reference to a jump table declared in the function preamble.
+jump_table = EntityRefKind(
+        'jump_table', 'A jump table.', default_member='table')
+
+#: A reference to a heap declared in the function preamble.
+heap = EntityRefKind('heap', 'A heap.')
+
+#: A reference to a table declared in the function preamble.
+table = EntityRefKind('table', 'A table.')
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/meta-python/base/formats.py
@@ -0,0 +1,86 @@
+"""
+The cranelift.formats defines all instruction formats.
+
+Every instruction format has a corresponding `InstructionData` variant in the
+Rust representation of Cranelift IR, so all instruction formats must be defined
+in this module.
+"""
+from __future__ import absolute_import
+from cdsl.formats import InstructionFormat
+from cdsl.operands import VALUE, VARIABLE_ARGS
+from .immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
+from .immediates import boolean, intcc, floatcc, memflags, regunit, trapcode
+from . import entities
+from .entities import ebb, sig_ref, func_ref, stack_slot, heap, table
+
+Unary = InstructionFormat(VALUE)
+UnaryImm = InstructionFormat(imm64)
+UnaryIeee32 = InstructionFormat(ieee32)
+UnaryIeee64 = InstructionFormat(ieee64)
+UnaryBool = InstructionFormat(boolean)
+UnaryGlobalValue = InstructionFormat(entities.global_value)
+
+Binary = InstructionFormat(VALUE, VALUE)
+BinaryImm = InstructionFormat(VALUE, imm64)
+
+# The select instructions are controlled by the second VALUE operand.
+# The first VALUE operand is the controlling flag which has a derived type.
+# The fma instruction has the same constraint on all inputs.
+Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1)
+
+# Catch-all for instructions with many outputs and inputs and no immediate
+# operands.
+MultiAry = InstructionFormat(VARIABLE_ARGS)
+
+NullAry = InstructionFormat()
+
+InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE)
+ExtractLane = InstructionFormat(VALUE, ('lane', uimm8))
+
+IntCompare = InstructionFormat(intcc, VALUE, VALUE)
+IntCompareImm = InstructionFormat(intcc, VALUE, imm64)
+IntCond = InstructionFormat(intcc, VALUE)
+FloatCompare = InstructionFormat(floatcc, VALUE, VALUE)
+FloatCond = InstructionFormat(floatcc, VALUE)
+
+IntSelect = InstructionFormat(intcc, VALUE, VALUE, VALUE)
+
+Jump = InstructionFormat(ebb, VARIABLE_ARGS)
+Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS)
+BranchInt = InstructionFormat(intcc, VALUE, ebb, VARIABLE_ARGS)
+BranchFloat = InstructionFormat(floatcc, VALUE, ebb, VARIABLE_ARGS)
+BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS)
+BranchTable = InstructionFormat(VALUE, entities.jump_table)
+
+Call = InstructionFormat(func_ref, VARIABLE_ARGS)
+CallIndirect = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
+FuncAddr = InstructionFormat(func_ref)
+
+Load = InstructionFormat(memflags, VALUE, offset32)
+LoadComplex = InstructionFormat(memflags, VARIABLE_ARGS, offset32)
+Store = InstructionFormat(memflags, VALUE, VALUE, offset32)
+StoreComplex = InstructionFormat(memflags, VALUE, VARIABLE_ARGS, offset32)
+
+StackLoad = InstructionFormat(stack_slot, offset32)
+StackStore = InstructionFormat(VALUE, stack_slot, offset32)
+
+# Accessing a WebAssembly heap.
+HeapAddr = InstructionFormat(heap, VALUE, uimm32)
+
+# Accessing a WebAssembly table.
+TableAddr = InstructionFormat(table, VALUE, offset32)
+
+RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))
+CopySpecial = InstructionFormat(('src', regunit), ('dst', regunit))
+RegSpill = InstructionFormat(
+        VALUE, ('src', regunit), ('dst', entities.stack_slot))
+RegFill = InstructionFormat(
+        VALUE, ('src', entities.stack_slot), ('dst', regunit))
+
+Trap = InstructionFormat(trapcode)
+CondTrap = InstructionFormat(VALUE, trapcode)
+IntCondTrap = InstructionFormat(intcc, VALUE, trapcode)
+FloatCondTrap = InstructionFormat(floatcc, VALUE, trapcode)
+
+# Finally extract the names of global values in this module.
+InstructionFormat.extract_names(globals())
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/meta-python/base/immediates.py
@@ -0,0 +1,123 @@
+"""
+The `cranelift.immediates` module predefines all the Cranelift immediate
+operand types.
+"""
+from __future__ import absolute_import
+from cdsl.operands import ImmediateKind
+
+#: A 64-bit immediate integer operand.
+#:
+#: This type of immediate integer can interact with SSA values with any
+#: :py:class:`cranelift.IntType` type.
+imm64 = ImmediateKind('imm64', 'A 64-bit immediate integer.')
+
+#: An unsigned 8-bit immediate integer operand.
+#:
+#: This small operand is used to indicate lane indexes in SIMD vectors and
+#: immediate bit counts on shift instructions.
+uimm8 = ImmediateKind('uimm8', 'An 8-bit immediate unsigned integer.')
+
+#: An unsigned 32-bit immediate integer operand.
+uimm32 = ImmediateKind('uimm32', 'A 32-bit immediate unsigned integer.')
+
+#: A 32-bit immediate signed offset.
+#:
+#: This is used to represent an immediate address offset in load/store
+#: instructions.
+offset32 = ImmediateKind(
+        'offset32',
+        'A 32-bit immediate signed offset.',
+        default_member='offset')
+
+#: A 32-bit immediate floating point operand.
+#:
+#: IEEE 754-2008 binary32 interchange format.
+ieee32 = ImmediateKind('ieee32', 'A 32-bit immediate floating point number.')
+
+#: A 64-bit immediate floating point operand.
+#:
+#: IEEE 754-2008 binary64 interchange format.
+ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.')
+
+#: An immediate boolean operand.
+#:
+#: This type of immediate boolean can interact with SSA values with any
+#: :py:class:`cranelift.BoolType` type.
+boolean = ImmediateKind('bool', 'An immediate boolean.',
+                        rust_type='bool')
+
+#: A condition code for comparing integer values.
+#:
+#: This enumerated operand kind is used for the :clif:inst:`icmp` instruction
+#: and corresponds to the `condcodes::IntCC` Rust type.
+intcc = ImmediateKind(
+        'intcc',
+        'An integer comparison condition code.',
+        default_member='cond',
+        rust_type='ir::condcodes::IntCC',
+        values={
+            'eq':  'Equal',
+            'ne':  'NotEqual',
+            'sge': 'SignedGreaterThanOrEqual',
+            'sgt': 'SignedGreaterThan',
+            'sle': 'SignedLessThanOrEqual',
+            'slt': 'SignedLessThan',
+            'uge': 'UnsignedGreaterThanOrEqual',
+            'ugt': 'UnsignedGreaterThan',
+            'ule': 'UnsignedLessThanOrEqual',
+            'ult': 'UnsignedLessThan',
+        })
+
+#: A condition code for comparing floating point values.
+#:
+#: This enumerated operand kind is used for the :clif:inst:`fcmp` instruction
+#: and corresponds to the `condcodes::FloatCC` Rust type.
+floatcc = ImmediateKind(
+        'floatcc',
+        'A floating point comparison condition code.',
+        default_member='cond',
+        rust_type='ir::condcodes::FloatCC',
+        values={
+            'ord': 'Ordered',
+            'uno': 'Unordered',
+            'eq':  'Equal',
+            'ne':  'NotEqual',
+            'one': 'OrderedNotEqual',
+            'ueq': 'UnorderedOrEqual',
+            'lt':  'LessThan',
+            'le':  'LessThanOrEqual',
+            'gt':  'GreaterThan',
+            'ge':  'GreaterThanOrEqual',
+            'ult': 'UnorderedOrLessThan',
+            'ule': 'UnorderedOrLessThanOrEqual',
+            'ugt': 'UnorderedOrGreaterThan',
+            'uge': 'UnorderedOrGreaterThanOrEqual',
+        })
+
+#: Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`.
+memflags = ImmediateKind(
+        'memflags',
+        'Memory operation flags',
+        default_member='flags', rust_type='ir::MemFlags')
+
+#: A register unit in the current target ISA.
+regunit = ImmediateKind(
+        'regunit',
+        'A register unit in the target ISA',
+        rust_type='isa::RegUnit')
+
+#: A trap code indicating the reason for trapping.
+#:
+#: The Rust enum type also has a `User(u16)` variant for user-provided trap
+#: codes.
+trapcode = ImmediateKind(
+        'trapcode',
+        'A trap reason code.',
+        default_member='code',
+        rust_type='ir::TrapCode',
+        values={
+            "stk_ovf": 'StackOverflow',
+            "heap_oob": 'HeapOutOfBounds',
+            "int_ovf": 'IntegerOverflow',
+            "int_divz": 'IntegerDivisionByZero',
+        })
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/meta-python/base/instructions.py
@@ -0,0 +1,1979 @@
+"""
+Cranelift base instruction set.
+
+This module defines the basic Cranelift instruction set that all targets
+support.
+"""
+from __future__ import absolute_import
+from cdsl.operands import Operand, VARIABLE_ARGS
+from cdsl.typevar import TypeVar
+from cdsl.instructions import Instruction, InstructionGroup
+from base.types import f32, f64, b1, iflags, fflags
+from base.immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
+from base.immediates import boolean, intcc, floatcc, memflags, regunit
+from base.immediates import trapcode
+from base import entities
+from cdsl.ti import WiderOrEq
+import base.formats  # noqa
+
+GROUP = InstructionGroup("base", "Shared base instruction set")
+
+Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
+Bool = TypeVar('Bool', 'A scalar or vector boolean type',
+               bools=True, simd=True)
+iB = TypeVar('iB', 'A scalar integer type', ints=True)
+iAddr = TypeVar('iAddr', 'An integer address type', ints=(32, 64))
+Testable = TypeVar(
+        'Testable', 'A scalar boolean or integer type',
+        ints=True, bools=True)
+TxN = TypeVar(
+        'TxN', 'A SIMD vector type',
+        ints=True, floats=True, bools=True, scalars=False, simd=True)
+Any = TypeVar(
+        'Any', 'Any integer, float, or boolean scalar or vector type',
+        ints=True, floats=True, bools=True, scalars=True, simd=True)
+Mem = TypeVar(
+        'Mem', 'Any type that can be stored in memory',
+        ints=True, floats=True, simd=True)
+MemTo = TypeVar(
+        'MemTo', 'Any type that can be stored in memory',
+        ints=True, floats=True, simd=True)
+
+addr = Operand('addr', iAddr)
+
+#
+# Control flow
+#
+c = Operand('c', Testable, doc='Controlling value to test')
+Cond = Operand('Cond', intcc)
+x = Operand('x', iB)
+y = Operand('y', iB)
+EBB = Operand('EBB', entities.ebb, doc='Destination extended basic block')
+args = Operand('args', VARIABLE_ARGS, doc='EBB arguments')
+
+jump = Instruction(
+        '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.
+        """,
+        ins=(EBB, args), is_branch=True, is_terminator=True)
+
+fallthrough = Instruction(
+        'fallthrough', r"""
+        Fall through to the next EBB.
+
+        This is the same as :inst:`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.
+        """,
+        ins=(EBB, args), is_branch=True, is_terminator=True)
+
+brz = Instruction(
+        'brz', r"""
+        Branch when zero.
+
+        If ``c`` is a :type:`b1` value, take the branch when ``c`` is false. If
+        ``c`` is an integer value, take the branch when ``c = 0``.
+        """,
+        ins=(c, EBB, args), is_branch=True)
+
+brnz = Instruction(
+        'brnz', r"""
+        Branch when non-zero.
+
+        If ``c`` is a :type:`b1` value, take the branch when ``c`` is true. If
+        ``c`` is an integer value, take the branch when ``c != 0``.
+        """,
+        ins=(c, EBB, args), is_branch=True)
+
+br_icmp = Instruction(
+        'br_icmp', r"""
+        Compare scalar integers and branch.
+
+        Compare ``x`` and ``y`` in the same way as the :inst:`icmp` instruction
+        and take the branch if the condition is true::
+
+            br_icmp ugt v1, v2, ebb4(v5, v6)
+
+        is semantically equivalent to::
+
+            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.
+        """,
+        ins=(Cond, x, y, EBB, args), is_branch=True)
+
+f = Operand('f', iflags)
+
+brif = Instruction(
+        'brif', r"""
+        Branch when condition is true in integer CPU flags.
+        """,
+        ins=(Cond, f, EBB, args), is_branch=True)
+
+Cond = Operand('Cond', floatcc)
+f = Operand('f', fflags)
+
+brff = Instruction(
+        'brff', r"""
+        Branch when condition is true in floating point CPU flags.
+        """,
+        ins=(Cond, f, EBB, args), is_branch=True)
+
+x = Operand('x', iB, doc='index into jump table')
+JT = Operand('JT', entities.jump_table)
+br_table = Instruction(
+        '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 fall through to the next instruction.
+
+        Note that this branch instruction can't pass arguments to the targeted
+        blocks. Split critical edges as needed to work around this.
+        """,
+        ins=(x, JT), is_branch=True)
+
+code = Operand('code', trapcode)
+trap = Instruction(
+        'trap', r"""
+        Terminate execution unconditionally.
+        """,
+        ins=code, is_terminator=True, can_trap=True)
+
+trapz = Instruction(
+        'trapz', r"""
+        Trap when zero.
+
+        if ``c`` is non-zero, execution continues at the following instruction.
+        """,
+        ins=(c, code), can_trap=True)
+
+trapnz = Instruction(
+        'trapnz', r"""
+        Trap when non-zero.
+
+        if ``c`` is zero, execution continues at the following instruction.
+        """,
+        ins=(c, code), can_trap=True)
+
+Cond = Operand('Cond', intcc)
+f = Operand('f', iflags)
+
+trapif = Instruction(
+        'trapif', r"""
+        Trap when condition is true in integer CPU flags.
+        """,
+        ins=(Cond, f, code), can_trap=True)
+
+Cond = Operand('Cond', floatcc)
+f = Operand('f', fflags)
+
+trapff = Instruction(
+        'trapff', r"""
+        Trap when condition is true in floating point CPU flags.
+        """,
+        ins=(Cond, f, code), can_trap=True)
+
+rvals = Operand('rvals', VARIABLE_ARGS, doc='return values')
+
+x_return = Instruction(
+        '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.
+        """,
+        ins=rvals, is_return=True, is_terminator=True)
+
+FN = Operand(
+        'FN',
+        entities.func_ref,
+        doc='function to call, declared by :inst:`function`')
+args = Operand('args', VARIABLE_ARGS, doc='call arguments')
+
+call = Instruction(
+        'call', r"""
+        Direct function call.
+
+        Call a function which has been declared in the preamble. The argument
+        types must match the function's signature.
+        """,
+        ins=(FN, args), outs=rvals, is_call=True)
+
+SIG = Operand('SIG', entities.sig_ref, doc='function signature')
+callee = Operand('callee', iAddr, doc='address of function to call')
+
+call_indirect = Instruction(
+        '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,
+        :inst:`table_addr` and :inst:`load` are used to obtain a native address
+        from a table.
+        """,
+        ins=(SIG, callee, args), outs=rvals, is_call=True)
+
+func_addr = Instruction(
+        '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
+        :inst:`call_indirect`. This is also a method for calling functions that
+        are too far away to be addressable by a direct :inst:`call`
+        instruction.
+        """,
+        ins=FN, outs=addr)
+
+#
+# Memory operations
+#
+
+SS = Operand('SS', entities.stack_slot)
+Offset = Operand('Offset', offset32, 'Byte offset from base address')
+x = Operand('x', Mem, doc='Value to be stored')
+a = Operand('a', Mem, doc='Value loaded')
+p = Operand('p', iAddr)
+MemFlags = Operand('MemFlags', memflags)
+args = Operand('args', VARIABLE_ARGS, doc='Address arguments')
+
+load = Instruction(
+        'load', r"""
+        Load from memory at ``p + Offset``.
+
+        This is a polymorphic instruction that can load any value type which
+        has a memory representation.
+        """,
+        ins=(MemFlags, p, Offset), outs=a, can_load=True)
+
+load_complex = Instruction(
+        'load_complex', r"""
+        Load from memory at ``sum(args) + Offset``.
+
+        This is a polymorphic instruction that can load any value type which
+        has a memory representation.
+        """,
+        ins=(MemFlags, args, Offset), outs=a, can_load=True)
+
+store = Instruction(
+        'store', r"""
+        Store ``x`` to memory at ``p + Offset``.
+
+        This is a polymorphic instruction that can store any value type with a
+        memory representation.
+        """,
+        ins=(MemFlags, x, p, Offset), can_store=True)
+
+store_complex = Instruction(
+        'store_complex', r"""
+        Store ``x`` to memory at ``sum(args) + Offset``.
+
+        This is a polymorphic instruction that can store any value type with a
+        memory representation.
+        """,
+        ins=(MemFlags, x, args, Offset), can_store=True)
+
+
+iExt8 = TypeVar(
+        'iExt8', 'An integer type with more than 8 bits',
+        ints=(16, 64))
+x = Operand('x', iExt8)
+a = Operand('a', iExt8)
+
+uload8 = Instruction(
+        'uload8', r"""
+        Load 8 bits from memory at ``p + Offset`` and zero-extend.
+
+        This is equivalent to ``load.i8`` followed by ``uextend``.
+        """,
+        ins=(MemFlags, p, Offset), outs=a, can_load=True)