├── .github ├── ISSUE_TEMPLATE │ ├── ---bug-report.md │ ├── ---feature-request.md │ └── --question.md └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── DEVELOPMENT.md ├── LICENSE ├── Makefile ├── README.md ├── build.gradle ├── examples ├── .gitignore ├── GreetExample.java ├── MemoryExample.java ├── SimpleExample.java ├── greet.rs ├── greet.wasm ├── memory.rs ├── memory.wasm ├── simple.rs └── simple.wasm ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── include ├── org_wasmer_Instance.h ├── org_wasmer_Memory.h └── org_wasmer_Module.h ├── settings.gradle ├── src ├── exception.rs ├── instance.rs ├── java │ └── org │ │ └── wasmer │ │ ├── Exports.java │ │ ├── Instance.java │ │ ├── Memory.java │ │ ├── Module.java │ │ ├── Native.java │ │ └── exports │ │ ├── Export.java │ │ └── Function.java ├── lib.rs ├── memory.rs ├── module.rs ├── types.rs └── value.rs └── tests ├── java └── org │ └── wasmer │ ├── InstanceTest.java │ ├── MemoryTest.java │ └── ModuleTest.java └── resources ├── invalid.wasm ├── no_memory.wasm ├── no_memory.wat ├── simple.rs ├── simple.wasm ├── tests.rs └── tests.wasm /.github/ISSUE_TEMPLATE/---bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41E Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: "\U0001F41E bug" 6 | assignees: '' 7 | 8 | --- 9 | 10 | Thanks for the bug report! 11 | 12 | ### Describe the bug 13 | 14 | A clear and concise description of what the bug is. 15 | 16 | ### Steps to reproduce 17 | 18 | 1. Go to '…' 19 | 2. Compile with '…' 20 | 3. Run '…' 21 | 4. See error 22 | 23 | If applicable, add a link to a test case (as a zip file or link to a repository we can clone). 24 | 25 | ### Expected behavior 26 | 27 | A clear and concise description of what you expected to happen. 28 | 29 | ### Actual behavior 30 | 31 | A clear and concise description of what actually happened. 32 | 33 | If applicable, add screenshots to help explain your problem. 34 | 35 | ### Additional context 36 | 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F389 Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: "\U0001F389 enhancement" 6 | assignees: '' 7 | 8 | --- 9 | 10 | Thanks for proposing a new feature! 11 | 12 | ### Motivation 13 | 14 | A clear and concise description of what the motivation for the new feature is, and what problem it is solving. 15 | 16 | ### Proposed solution 17 | 18 | A clear and concise description of the feature you would like to add, and how it solves the motivating problem. 19 | 20 | ### Alternatives 21 | 22 | A clear and concise description of any alternative solutions or features you've considered, and why you're proposed solution is better. 23 | 24 | ### Additional context 25 | 26 | Add any other context or screenshots about the feature request here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❓ Question" 3 | about: Ask a question about this project 4 | title: '' 5 | labels: "❓ question" 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Summary 11 | 12 | A clear and concise summary of your question. 13 | 14 | ### Additional details 15 | 16 | Provide any additional details here. 17 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '**' 7 | 8 | jobs: 9 | create_pre_release: 10 | name: Create pre-release 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | # The pre-release must be created only once, hence the split 16 | # into multiple jobs with different `strategy`. 17 | - name: Create a Github pre-release 18 | id: create_pre_release 19 | uses: actions/create-release@v1 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | with: 23 | tag_name: ${{ github.ref }} 24 | release_name: ${{ github.ref }} 25 | draft: false 26 | prerelease: true 27 | 28 | - name: Output `release_url` into a temporary file 29 | run: echo "${{ steps.create_pre_release.outputs.upload_url }}" > release_url.txt 30 | 31 | - name: Save the `release_url` temporary file 32 | uses: actions/upload-artifact@v1 33 | with: 34 | name: release_url 35 | path: release_url.txt 36 | 37 | publish_jar: 38 | name: Publish the JARs 39 | 40 | needs: [create_pre_release] 41 | 42 | strategy: 43 | matrix: 44 | # The job runs on 3 different OS. 45 | os: [ubuntu-latest, macos-latest, windows-latest] 46 | # The job runs on different Java versions (LTS). 47 | java: [8] 48 | # As soon as one job fails in the matrix, all the other 49 | # in-progress jobs are canceled. 50 | fail-fast: true 51 | 52 | runs-on: ${{ matrix.os }} 53 | 54 | steps: 55 | - name: Check out code 56 | uses: actions/checkout@v2 57 | 58 | - name: Set up Java ${{ matrix.version }} 59 | uses: actions/setup-java@v1 60 | with: 61 | java-version: ${{ matrix.java }} 62 | 63 | - name: Set up Rust 64 | uses: actions-rs/toolchain@v1 65 | with: 66 | toolchain: stable 67 | default: true 68 | override: true 69 | 70 | - name: Cache Cargo registry 71 | uses: actions/cache@v1 72 | with: 73 | path: ~/.cargo/registry 74 | key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 75 | 76 | - name: Cache Cargo bin 77 | uses: actions/cache@v1 78 | with: 79 | path: ~/.cargo/bin 80 | key: ${{ runner.os }}-cargo-bin-${{ hashFiles('**/Cargo.lock') }} 81 | 82 | - name: Cache Cargo build 83 | uses: actions/cache@v1 84 | with: 85 | path: target 86 | key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} 87 | 88 | - name: Run all the tests 89 | shell: bash 90 | run: | 91 | export PATH="$HOME/.cargo/bin:$PATH" 92 | make test 93 | 94 | - name: Create the JAR 95 | id: create_jar 96 | shell: bash 97 | run: | 98 | export PATH="$HOME/.cargo/bin:$PATH" 99 | make package 100 | 101 | - name: Load the `release_url` from the temporary file 102 | uses: actions/download-artifact@v1 103 | with: 104 | name: release_url 105 | 106 | - name: Read the `release_url` temporary file 107 | id: get_release_info 108 | shell: bash 109 | run: | 110 | value=$(cat release_url/release_url.txt) 111 | echo ::set-output name=upload_url::$value 112 | 113 | - name: Upload JAR as Github pre-release asset 114 | uses: actions/upload-release-asset@v1 115 | env: 116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 117 | with: 118 | upload_url: ${{ steps.get_release_info.outputs.upload_url }} 119 | asset_path: ${{ steps.create_jar.outputs.path }} 120 | asset_name: ${{ steps.create_jar.outputs.name }} 121 | asset_content_type: application/java-archive 122 | 123 | - name: Upload JAR to Bintray (JCenter) 124 | env: 125 | BINTRAY_USER: ${{ secrets.BINTRAY_USER }} 126 | BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} 127 | shell: bash 128 | run: | 129 | export PATH="$HOME/.cargo/bin:$PATH" 130 | make publish 131 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | # The `test` job. 7 | test: 8 | name: Test 9 | 10 | strategy: 11 | matrix: 12 | # The job runs on 3 different OS. 13 | os: [ubuntu-latest, macos-latest, windows-latest] 14 | # The job runs on different Java versions (LTS). 15 | java: [8] 16 | # As soon as one job fails in the matrix, all the other 17 | # in-progress jobs are canceled. 18 | fail-fast: true 19 | 20 | runs-on: ${{ matrix.os }} 21 | 22 | steps: 23 | - name: Check out code 24 | uses: actions/checkout@v2 25 | 26 | - name: Set up Java ${{ matrix.version }} 27 | uses: actions/setup-java@v1 28 | with: 29 | java-version: ${{ matrix.java }} 30 | 31 | - name: Set up Rust 32 | uses: actions-rs/toolchain@v1 33 | with: 34 | toolchain: stable 35 | default: true 36 | override: true 37 | 38 | - name: Run all the tests 39 | shell: bash 40 | run: | 41 | export PATH="$HOME/.cargo/bin:$PATH" 42 | make test 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /artifacts 3 | /build 4 | /include/org/ 5 | /target 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "addr2line" 5 | version = "0.14.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" 8 | dependencies = [ 9 | "gimli 0.23.0", 10 | ] 11 | 12 | [[package]] 13 | name = "adler" 14 | version = "0.2.3" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 17 | 18 | [[package]] 19 | name = "arrayref" 20 | version = "0.3.6" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 23 | 24 | [[package]] 25 | name = "arrayvec" 26 | version = "0.5.2" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 29 | 30 | [[package]] 31 | name = "ascii" 32 | version = "0.9.3" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" 35 | 36 | [[package]] 37 | name = "autocfg" 38 | version = "1.0.1" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 41 | 42 | [[package]] 43 | name = "backtrace" 44 | version = "0.3.55" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" 47 | dependencies = [ 48 | "addr2line", 49 | "cfg-if 1.0.0", 50 | "libc", 51 | "miniz_oxide", 52 | "object", 53 | "rustc-demangle", 54 | ] 55 | 56 | [[package]] 57 | name = "bincode" 58 | version = "1.3.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" 61 | dependencies = [ 62 | "byteorder", 63 | "serde", 64 | ] 65 | 66 | [[package]] 67 | name = "bitflags" 68 | version = "1.2.1" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 71 | 72 | [[package]] 73 | name = "blake3" 74 | version = "0.3.7" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" 77 | dependencies = [ 78 | "arrayref", 79 | "arrayvec", 80 | "cc", 81 | "cfg-if 0.1.10", 82 | "constant_time_eq", 83 | "crypto-mac", 84 | "digest", 85 | ] 86 | 87 | [[package]] 88 | name = "byteorder" 89 | version = "1.3.4" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 92 | 93 | [[package]] 94 | name = "cc" 95 | version = "1.0.66" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" 98 | 99 | [[package]] 100 | name = "cesu8" 101 | version = "1.1.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" 104 | 105 | [[package]] 106 | name = "cfg-if" 107 | version = "0.1.10" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 110 | 111 | [[package]] 112 | name = "cfg-if" 113 | version = "1.0.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 116 | 117 | [[package]] 118 | name = "combine" 119 | version = "3.8.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" 122 | dependencies = [ 123 | "ascii", 124 | "byteorder", 125 | "either", 126 | "memchr", 127 | "unreachable", 128 | ] 129 | 130 | [[package]] 131 | name = "const_fn" 132 | version = "0.4.4" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" 135 | 136 | [[package]] 137 | name = "constant_time_eq" 138 | version = "0.1.5" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 141 | 142 | [[package]] 143 | name = "cranelift-bforest" 144 | version = "0.68.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "9221545c0507dc08a62b2d8b5ffe8e17ac580b0a74d1813b496b8d70b070fbd0" 147 | dependencies = [ 148 | "cranelift-entity", 149 | ] 150 | 151 | [[package]] 152 | name = "cranelift-codegen" 153 | version = "0.68.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "7e9936ea608b6cd176f107037f6adbb4deac933466fc7231154f96598b2d3ab1" 156 | dependencies = [ 157 | "byteorder", 158 | "cranelift-bforest", 159 | "cranelift-codegen-meta", 160 | "cranelift-codegen-shared", 161 | "cranelift-entity", 162 | "gimli 0.22.0", 163 | "log", 164 | "regalloc", 165 | "smallvec", 166 | "target-lexicon", 167 | "thiserror", 168 | ] 169 | 170 | [[package]] 171 | name = "cranelift-codegen-meta" 172 | version = "0.68.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "4ef2b2768568306540f4c8db3acce9105534d34c4a1e440529c1e702d7f8c8d7" 175 | dependencies = [ 176 | "cranelift-codegen-shared", 177 | "cranelift-entity", 178 | ] 179 | 180 | [[package]] 181 | name = "cranelift-codegen-shared" 182 | version = "0.68.0" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" 185 | 186 | [[package]] 187 | name = "cranelift-entity" 188 | version = "0.68.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "86badbce14e15f52a45b666b38abe47b204969dd7f8fb7488cb55dd46b361fa6" 191 | dependencies = [ 192 | "serde", 193 | ] 194 | 195 | [[package]] 196 | name = "cranelift-frontend" 197 | version = "0.68.0" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" 200 | dependencies = [ 201 | "cranelift-codegen", 202 | "log", 203 | "smallvec", 204 | "target-lexicon", 205 | ] 206 | 207 | [[package]] 208 | name = "crc32fast" 209 | version = "1.2.1" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 212 | dependencies = [ 213 | "cfg-if 1.0.0", 214 | ] 215 | 216 | [[package]] 217 | name = "crossbeam-channel" 218 | version = "0.5.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" 221 | dependencies = [ 222 | "cfg-if 1.0.0", 223 | "crossbeam-utils", 224 | ] 225 | 226 | [[package]] 227 | name = "crossbeam-deque" 228 | version = "0.8.0" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" 231 | dependencies = [ 232 | "cfg-if 1.0.0", 233 | "crossbeam-epoch", 234 | "crossbeam-utils", 235 | ] 236 | 237 | [[package]] 238 | name = "crossbeam-epoch" 239 | version = "0.9.1" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" 242 | dependencies = [ 243 | "cfg-if 1.0.0", 244 | "const_fn", 245 | "crossbeam-utils", 246 | "lazy_static", 247 | "memoffset", 248 | "scopeguard", 249 | ] 250 | 251 | [[package]] 252 | name = "crossbeam-utils" 253 | version = "0.8.1" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" 256 | dependencies = [ 257 | "autocfg", 258 | "cfg-if 1.0.0", 259 | "lazy_static", 260 | ] 261 | 262 | [[package]] 263 | name = "crypto-mac" 264 | version = "0.8.0" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 267 | dependencies = [ 268 | "generic-array", 269 | "subtle", 270 | ] 271 | 272 | [[package]] 273 | name = "darling" 274 | version = "0.10.2" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" 277 | dependencies = [ 278 | "darling_core", 279 | "darling_macro", 280 | ] 281 | 282 | [[package]] 283 | name = "darling_core" 284 | version = "0.10.2" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" 287 | dependencies = [ 288 | "fnv", 289 | "ident_case", 290 | "proc-macro2", 291 | "quote", 292 | "strsim", 293 | "syn", 294 | ] 295 | 296 | [[package]] 297 | name = "darling_macro" 298 | version = "0.10.2" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" 301 | dependencies = [ 302 | "darling_core", 303 | "quote", 304 | "syn", 305 | ] 306 | 307 | [[package]] 308 | name = "digest" 309 | version = "0.9.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 312 | dependencies = [ 313 | "generic-array", 314 | ] 315 | 316 | [[package]] 317 | name = "either" 318 | version = "1.6.1" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 321 | 322 | [[package]] 323 | name = "enumset" 324 | version = "1.0.1" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "959a80a2062fedd66ed41d99736212de987b3a8c83a4c2cef243968075256bd1" 327 | dependencies = [ 328 | "enumset_derive", 329 | "num-traits", 330 | ] 331 | 332 | [[package]] 333 | name = "enumset_derive" 334 | version = "0.5.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "74bef436ac71820c5cf768d7af9ba33121246b09a00e09a55d94ef8095a875ac" 337 | dependencies = [ 338 | "darling", 339 | "proc-macro2", 340 | "quote", 341 | "syn", 342 | ] 343 | 344 | [[package]] 345 | name = "error-chain" 346 | version = "0.12.4" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" 349 | dependencies = [ 350 | "backtrace", 351 | "version_check", 352 | ] 353 | 354 | [[package]] 355 | name = "fallible-iterator" 356 | version = "0.2.0" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 359 | 360 | [[package]] 361 | name = "fnv" 362 | version = "1.0.7" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 365 | 366 | [[package]] 367 | name = "generic-array" 368 | version = "0.14.4" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 371 | dependencies = [ 372 | "typenum", 373 | "version_check", 374 | ] 375 | 376 | [[package]] 377 | name = "getrandom" 378 | version = "0.1.16" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 381 | dependencies = [ 382 | "cfg-if 1.0.0", 383 | "libc", 384 | "wasi", 385 | ] 386 | 387 | [[package]] 388 | name = "gimli" 389 | version = "0.22.0" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" 392 | dependencies = [ 393 | "fallible-iterator", 394 | "indexmap", 395 | "stable_deref_trait", 396 | ] 397 | 398 | [[package]] 399 | name = "gimli" 400 | version = "0.23.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" 403 | 404 | [[package]] 405 | name = "hashbrown" 406 | version = "0.9.1" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 409 | 410 | [[package]] 411 | name = "hermit-abi" 412 | version = "0.1.17" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" 415 | dependencies = [ 416 | "libc", 417 | ] 418 | 419 | [[package]] 420 | name = "hex" 421 | version = "0.4.2" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" 424 | 425 | [[package]] 426 | name = "ident_case" 427 | version = "1.0.1" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 430 | 431 | [[package]] 432 | name = "indexmap" 433 | version = "1.6.1" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" 436 | dependencies = [ 437 | "autocfg", 438 | "hashbrown", 439 | "serde", 440 | ] 441 | 442 | [[package]] 443 | name = "jni" 444 | version = "0.16.0" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "22bbdc25b49340bc4fc3d9c96dd84d878c4beeca35e3651efa53db51a68d7d4d" 447 | dependencies = [ 448 | "cesu8", 449 | "combine", 450 | "error-chain", 451 | "jni-sys", 452 | "log", 453 | "walkdir", 454 | ] 455 | 456 | [[package]] 457 | name = "jni-sys" 458 | version = "0.3.0" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 461 | 462 | [[package]] 463 | name = "lazy_static" 464 | version = "1.4.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 467 | 468 | [[package]] 469 | name = "leb128" 470 | version = "0.2.4" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" 473 | 474 | [[package]] 475 | name = "libc" 476 | version = "0.2.81" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" 479 | 480 | [[package]] 481 | name = "libloading" 482 | version = "0.6.6" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc" 485 | dependencies = [ 486 | "cfg-if 1.0.0", 487 | "winapi", 488 | ] 489 | 490 | [[package]] 491 | name = "log" 492 | version = "0.4.11" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" 495 | dependencies = [ 496 | "cfg-if 0.1.10", 497 | ] 498 | 499 | [[package]] 500 | name = "mach" 501 | version = "0.3.2" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" 504 | dependencies = [ 505 | "libc", 506 | ] 507 | 508 | [[package]] 509 | name = "memchr" 510 | version = "2.3.4" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 513 | 514 | [[package]] 515 | name = "memmap2" 516 | version = "0.2.0" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "e73be3b7d04a0123e933fea1d50d126cc7196bbc0362c0ce426694f777194eee" 519 | dependencies = [ 520 | "libc", 521 | ] 522 | 523 | [[package]] 524 | name = "memoffset" 525 | version = "0.6.1" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" 528 | dependencies = [ 529 | "autocfg", 530 | ] 531 | 532 | [[package]] 533 | name = "miniz_oxide" 534 | version = "0.4.3" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" 537 | dependencies = [ 538 | "adler", 539 | "autocfg", 540 | ] 541 | 542 | [[package]] 543 | name = "more-asserts" 544 | version = "0.2.1" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" 547 | 548 | [[package]] 549 | name = "num-traits" 550 | version = "0.2.14" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 553 | dependencies = [ 554 | "autocfg", 555 | ] 556 | 557 | [[package]] 558 | name = "num_cpus" 559 | version = "1.13.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 562 | dependencies = [ 563 | "hermit-abi", 564 | "libc", 565 | ] 566 | 567 | [[package]] 568 | name = "object" 569 | version = "0.22.0" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" 572 | dependencies = [ 573 | "crc32fast", 574 | "indexmap", 575 | ] 576 | 577 | [[package]] 578 | name = "pin-project-lite" 579 | version = "0.2.0" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" 582 | 583 | [[package]] 584 | name = "ppv-lite86" 585 | version = "0.2.10" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 588 | 589 | [[package]] 590 | name = "proc-macro-error" 591 | version = "1.0.4" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 594 | dependencies = [ 595 | "proc-macro-error-attr", 596 | "proc-macro2", 597 | "quote", 598 | "syn", 599 | "version_check", 600 | ] 601 | 602 | [[package]] 603 | name = "proc-macro-error-attr" 604 | version = "1.0.4" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 607 | dependencies = [ 608 | "proc-macro2", 609 | "quote", 610 | "version_check", 611 | ] 612 | 613 | [[package]] 614 | name = "proc-macro2" 615 | version = "1.0.24" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 618 | dependencies = [ 619 | "unicode-xid", 620 | ] 621 | 622 | [[package]] 623 | name = "quote" 624 | version = "1.0.8" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" 627 | dependencies = [ 628 | "proc-macro2", 629 | ] 630 | 631 | [[package]] 632 | name = "rand" 633 | version = "0.7.3" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 636 | dependencies = [ 637 | "getrandom", 638 | "libc", 639 | "rand_chacha", 640 | "rand_core", 641 | "rand_hc", 642 | ] 643 | 644 | [[package]] 645 | name = "rand_chacha" 646 | version = "0.2.2" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 649 | dependencies = [ 650 | "ppv-lite86", 651 | "rand_core", 652 | ] 653 | 654 | [[package]] 655 | name = "rand_core" 656 | version = "0.5.1" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 659 | dependencies = [ 660 | "getrandom", 661 | ] 662 | 663 | [[package]] 664 | name = "rand_hc" 665 | version = "0.2.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 668 | dependencies = [ 669 | "rand_core", 670 | ] 671 | 672 | [[package]] 673 | name = "raw-cpuid" 674 | version = "7.0.4" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "beb71f708fe39b2c5e98076204c3cc094ee5a4c12c4cdb119a2b72dc34164f41" 677 | dependencies = [ 678 | "bitflags", 679 | "cc", 680 | "rustc_version", 681 | ] 682 | 683 | [[package]] 684 | name = "rayon" 685 | version = "1.5.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" 688 | dependencies = [ 689 | "autocfg", 690 | "crossbeam-deque", 691 | "either", 692 | "rayon-core", 693 | ] 694 | 695 | [[package]] 696 | name = "rayon-core" 697 | version = "1.9.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" 700 | dependencies = [ 701 | "crossbeam-channel", 702 | "crossbeam-deque", 703 | "crossbeam-utils", 704 | "lazy_static", 705 | "num_cpus", 706 | ] 707 | 708 | [[package]] 709 | name = "redox_syscall" 710 | version = "0.1.57" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 713 | 714 | [[package]] 715 | name = "regalloc" 716 | version = "0.0.31" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" 719 | dependencies = [ 720 | "log", 721 | "rustc-hash", 722 | "smallvec", 723 | ] 724 | 725 | [[package]] 726 | name = "region" 727 | version = "2.2.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" 730 | dependencies = [ 731 | "bitflags", 732 | "libc", 733 | "mach", 734 | "winapi", 735 | ] 736 | 737 | [[package]] 738 | name = "remove_dir_all" 739 | version = "0.5.3" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 742 | dependencies = [ 743 | "winapi", 744 | ] 745 | 746 | [[package]] 747 | name = "rustc-demangle" 748 | version = "0.1.18" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" 751 | 752 | [[package]] 753 | name = "rustc-hash" 754 | version = "1.1.0" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 757 | 758 | [[package]] 759 | name = "rustc_version" 760 | version = "0.2.3" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 763 | dependencies = [ 764 | "semver", 765 | ] 766 | 767 | [[package]] 768 | name = "same-file" 769 | version = "1.0.6" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 772 | dependencies = [ 773 | "winapi-util", 774 | ] 775 | 776 | [[package]] 777 | name = "scopeguard" 778 | version = "1.1.0" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 781 | 782 | [[package]] 783 | name = "semver" 784 | version = "0.9.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 787 | dependencies = [ 788 | "semver-parser", 789 | ] 790 | 791 | [[package]] 792 | name = "semver-parser" 793 | version = "0.7.0" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 796 | 797 | [[package]] 798 | name = "serde" 799 | version = "1.0.118" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" 802 | dependencies = [ 803 | "serde_derive", 804 | ] 805 | 806 | [[package]] 807 | name = "serde_bytes" 808 | version = "0.11.5" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" 811 | dependencies = [ 812 | "serde", 813 | ] 814 | 815 | [[package]] 816 | name = "serde_derive" 817 | version = "1.0.118" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" 820 | dependencies = [ 821 | "proc-macro2", 822 | "quote", 823 | "syn", 824 | ] 825 | 826 | [[package]] 827 | name = "smallvec" 828 | version = "1.6.0" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" 831 | 832 | [[package]] 833 | name = "stable_deref_trait" 834 | version = "1.2.0" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 837 | 838 | [[package]] 839 | name = "strsim" 840 | version = "0.9.3" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 843 | 844 | [[package]] 845 | name = "subtle" 846 | version = "2.4.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" 849 | 850 | [[package]] 851 | name = "syn" 852 | version = "1.0.56" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" 855 | dependencies = [ 856 | "proc-macro2", 857 | "quote", 858 | "unicode-xid", 859 | ] 860 | 861 | [[package]] 862 | name = "target-lexicon" 863 | version = "0.11.1" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "4ee5a98e506fb7231a304c3a1bd7c132a55016cf65001e0282480665870dfcb9" 866 | 867 | [[package]] 868 | name = "tempfile" 869 | version = "3.1.0" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 872 | dependencies = [ 873 | "cfg-if 0.1.10", 874 | "libc", 875 | "rand", 876 | "redox_syscall", 877 | "remove_dir_all", 878 | "winapi", 879 | ] 880 | 881 | [[package]] 882 | name = "thiserror" 883 | version = "1.0.23" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" 886 | dependencies = [ 887 | "thiserror-impl", 888 | ] 889 | 890 | [[package]] 891 | name = "thiserror-impl" 892 | version = "1.0.23" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" 895 | dependencies = [ 896 | "proc-macro2", 897 | "quote", 898 | "syn", 899 | ] 900 | 901 | [[package]] 902 | name = "tracing" 903 | version = "0.1.22" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" 906 | dependencies = [ 907 | "cfg-if 1.0.0", 908 | "pin-project-lite", 909 | "tracing-attributes", 910 | "tracing-core", 911 | ] 912 | 913 | [[package]] 914 | name = "tracing-attributes" 915 | version = "0.1.11" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" 918 | dependencies = [ 919 | "proc-macro2", 920 | "quote", 921 | "syn", 922 | ] 923 | 924 | [[package]] 925 | name = "tracing-core" 926 | version = "0.1.17" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" 929 | dependencies = [ 930 | "lazy_static", 931 | ] 932 | 933 | [[package]] 934 | name = "typenum" 935 | version = "1.12.0" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 938 | 939 | [[package]] 940 | name = "unicode-xid" 941 | version = "0.2.1" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 944 | 945 | [[package]] 946 | name = "unreachable" 947 | version = "1.0.0" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 950 | dependencies = [ 951 | "void", 952 | ] 953 | 954 | [[package]] 955 | name = "version_check" 956 | version = "0.9.2" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 959 | 960 | [[package]] 961 | name = "void" 962 | version = "1.0.2" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 965 | 966 | [[package]] 967 | name = "walkdir" 968 | version = "2.3.1" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" 971 | dependencies = [ 972 | "same-file", 973 | "winapi", 974 | "winapi-util", 975 | ] 976 | 977 | [[package]] 978 | name = "wasi" 979 | version = "0.9.0+wasi-snapshot-preview1" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 982 | 983 | [[package]] 984 | name = "wasmer" 985 | version = "1.0.0" 986 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 987 | dependencies = [ 988 | "cfg-if 0.1.10", 989 | "indexmap", 990 | "more-asserts", 991 | "target-lexicon", 992 | "thiserror", 993 | "wasmer-compiler", 994 | "wasmer-compiler-cranelift", 995 | "wasmer-derive", 996 | "wasmer-engine", 997 | "wasmer-engine-jit", 998 | "wasmer-engine-native", 999 | "wasmer-types", 1000 | "wasmer-vm", 1001 | "wat", 1002 | "winapi", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "wasmer-cache" 1007 | version = "1.0.0" 1008 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1009 | dependencies = [ 1010 | "blake3", 1011 | "hex", 1012 | "thiserror", 1013 | "wasmer", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "wasmer-compiler" 1018 | version = "1.0.0" 1019 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1020 | dependencies = [ 1021 | "enumset", 1022 | "raw-cpuid", 1023 | "serde", 1024 | "serde_bytes", 1025 | "smallvec", 1026 | "target-lexicon", 1027 | "thiserror", 1028 | "wasmer-types", 1029 | "wasmer-vm", 1030 | "wasmparser", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "wasmer-compiler-cranelift" 1035 | version = "1.0.0" 1036 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1037 | dependencies = [ 1038 | "cranelift-codegen", 1039 | "cranelift-frontend", 1040 | "gimli 0.22.0", 1041 | "more-asserts", 1042 | "rayon", 1043 | "serde", 1044 | "smallvec", 1045 | "tracing", 1046 | "wasmer-compiler", 1047 | "wasmer-types", 1048 | "wasmer-vm", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "wasmer-derive" 1053 | version = "1.0.0" 1054 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1055 | dependencies = [ 1056 | "proc-macro-error", 1057 | "proc-macro2", 1058 | "quote", 1059 | "syn", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "wasmer-engine" 1064 | version = "1.0.0" 1065 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1066 | dependencies = [ 1067 | "backtrace", 1068 | "bincode", 1069 | "lazy_static", 1070 | "memmap2", 1071 | "more-asserts", 1072 | "rustc-demangle", 1073 | "serde", 1074 | "serde_bytes", 1075 | "target-lexicon", 1076 | "thiserror", 1077 | "wasmer-compiler", 1078 | "wasmer-types", 1079 | "wasmer-vm", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "wasmer-engine-jit" 1084 | version = "1.0.0" 1085 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1086 | dependencies = [ 1087 | "bincode", 1088 | "cfg-if 0.1.10", 1089 | "region", 1090 | "serde", 1091 | "serde_bytes", 1092 | "wasmer-compiler", 1093 | "wasmer-engine", 1094 | "wasmer-types", 1095 | "wasmer-vm", 1096 | "winapi", 1097 | ] 1098 | 1099 | [[package]] 1100 | name = "wasmer-engine-native" 1101 | version = "1.0.0" 1102 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1103 | dependencies = [ 1104 | "bincode", 1105 | "cfg-if 0.1.10", 1106 | "leb128", 1107 | "libloading", 1108 | "serde", 1109 | "tempfile", 1110 | "tracing", 1111 | "wasmer-compiler", 1112 | "wasmer-engine", 1113 | "wasmer-object", 1114 | "wasmer-types", 1115 | "wasmer-vm", 1116 | "which", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "wasmer-jni" 1121 | version = "0.3.0" 1122 | dependencies = [ 1123 | "jni", 1124 | "wasmer", 1125 | "wasmer-runtime", 1126 | "wasmer-runtime-core", 1127 | ] 1128 | 1129 | [[package]] 1130 | name = "wasmer-object" 1131 | version = "1.0.0" 1132 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1133 | dependencies = [ 1134 | "object", 1135 | "thiserror", 1136 | "wasmer-compiler", 1137 | "wasmer-types", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "wasmer-runtime" 1142 | version = "0.18.0" 1143 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1144 | dependencies = [ 1145 | "wasmer-runtime-core", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "wasmer-runtime-core" 1150 | version = "0.18.0" 1151 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1152 | dependencies = [ 1153 | "blake3", 1154 | "lazy_static", 1155 | "wasmer", 1156 | "wasmer-cache", 1157 | "wasmer-compiler", 1158 | "wasmer-compiler-cranelift", 1159 | "wasmer-engine", 1160 | "wasmer-engine-jit", 1161 | "wasmer-types", 1162 | "wasmer-vm", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "wasmer-types" 1167 | version = "1.0.0" 1168 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1169 | dependencies = [ 1170 | "cranelift-entity", 1171 | "serde", 1172 | "thiserror", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "wasmer-vm" 1177 | version = "1.0.0" 1178 | source = "git+https://github.com/wasmerio/wasmer?rev=1.0.0#aa03cab26cbe49d7701cabe5e063a1d76f4fbb0f" 1179 | dependencies = [ 1180 | "backtrace", 1181 | "cc", 1182 | "cfg-if 0.1.10", 1183 | "indexmap", 1184 | "libc", 1185 | "memoffset", 1186 | "more-asserts", 1187 | "region", 1188 | "serde", 1189 | "thiserror", 1190 | "wasmer-types", 1191 | "winapi", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "wasmparser" 1196 | version = "0.65.0" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" 1199 | 1200 | [[package]] 1201 | name = "wast" 1202 | version = "30.0.0" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "9b79907b22f740634810e882d8d1d9d0f9563095a8ab94e786e370242bff5cd2" 1205 | dependencies = [ 1206 | "leb128", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "wat" 1211 | version = "1.0.31" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "a8279a02835bf12e61ed2b3c3cbc6ecf9918762fd97e036917c11a09ec20ca44" 1214 | dependencies = [ 1215 | "wast", 1216 | ] 1217 | 1218 | [[package]] 1219 | name = "which" 1220 | version = "4.0.2" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" 1223 | dependencies = [ 1224 | "libc", 1225 | "thiserror", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "winapi" 1230 | version = "0.3.9" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1233 | dependencies = [ 1234 | "winapi-i686-pc-windows-gnu", 1235 | "winapi-x86_64-pc-windows-gnu", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "winapi-i686-pc-windows-gnu" 1240 | version = "0.4.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1243 | 1244 | [[package]] 1245 | name = "winapi-util" 1246 | version = "0.1.5" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1249 | dependencies = [ 1250 | "winapi", 1251 | ] 1252 | 1253 | [[package]] 1254 | name = "winapi-x86_64-pc-windows-gnu" 1255 | version = "0.4.0" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1258 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | publish = false 3 | name = "wasmer-jni" 4 | version = "0.3.0" 5 | authors = ["Ivan Enderlin "] 6 | edition = "2018" 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | wasmer = { git = "https://github.com/wasmerio/wasmer", rev = "1.0.0" } 13 | wasmer-runtime = { git = "https://github.com/wasmerio/wasmer", rev = "1.0.0" } 14 | wasmer-runtime-core = { git = "https://github.com/wasmerio/wasmer", rev = "1.0.0" } 15 | jni = "0.16" 16 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # How Java and Rust communicate 2 | 3 | Java allows to write native code, and to expose it through a Java 4 | interface. For example, in `Instance.java`, we can read: 5 | 6 | ```java 7 | class Instance { 8 | private native long nativeInstantiate(Instance self, byte[] moduleBytes) throws RuntimeException; 9 | // … 10 | } 11 | ``` 12 | 13 | We define a public method to call a native method, such as: 14 | ```java 15 | public Instance(byte[] moduleBytes) throws RuntimeException { 16 | long instancePointer = this.instantiate(this, moduleBytes); 17 | 18 | this.instancePointer = instancePointer; 19 | } 20 | ``` 21 | 22 | The native implementation is written in Rust. First, a C header is generated 23 | with `just build-headers` which is located in `include/`. The generated code for 24 | `nativeInstantiate` is the following: 25 | 26 | ```c 27 | /* 28 | * Class: org_wasmer_Instance 29 | * Method: nativeInstantiate 30 | * Signature: (Lorg/wasmer/Instance;[B)J 31 | */ 32 | JNIEXPORT jlong JNICALL Java_org_wasmer_Instance_nativeInstantiate 33 | (JNIEnv *, jobject, jobject, jbyteArray); 34 | ``` 35 | 36 | Second, on the Rust side, we have to declare a function with the same naming: 37 | ```rust 38 | #[no_mangle] 39 | pub extern "system" fn Java_org_wasmer_Instance_nativeInstantiate( 40 | env: JNIEnv, 41 | _class: JClass, 42 | this: JObject, 43 | module_bytes: jbyteArray, 44 | ) -> jptr { 45 | // … 46 | } 47 | ``` 48 | 49 | And the dynamic linking does the rest (it's done with the 50 | `java.library.path` configuration on the Java side). It uses a shared 51 | library (`.dylib` on macOS, `.so` on Linux, `.dll` on Windows). 52 | 53 | Then, we have to convert “Java data” to “Rust data”. [`jni-rs`'s 54 | documentation](https://docs.rs/jni/0.14.0/jni/index.html) is our best 55 | friend here. 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-present Wasmer, Inc. and its affiliates. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | build_os := windows 3 | build_arch := amd64 4 | else 5 | UNAME_S := $(shell uname -s) 6 | 7 | ifeq ($(UNAME_S),Darwin) 8 | build_os := darwin 9 | endif 10 | 11 | ifeq ($(UNAME_S),Linux) 12 | build_os := linux 13 | endif 14 | 15 | ARCH := $(shell uname -m) 16 | 17 | ifeq ($(ARCH),x86_64) 18 | build_arch = amd64 19 | else ifeq ($(ARCH),arm64) 20 | build_arch = arm64 21 | else 22 | $(error Architecture not supported yet) 23 | endif 24 | endif 25 | 26 | # Compile everything! 27 | build: build-headers build-rust build-java 28 | 29 | # Compile the Rust part (only for one target). 30 | # We relay this command to the others, to make sure that 31 | # artifacts are set properly. 32 | build-rust: build-rust-$(build_arch)-$(build_os) 33 | 34 | # Compile the Rust part. 35 | build-rust-all-targets: build-rust-amd64-darwin build-rust-arm64-darwin build-rust-amd64-linux build-rust-amd64-windows 36 | 37 | build-rust-amd64-darwin: 38 | rustup target add x86_64-apple-darwin 39 | cargo build --release --target=x86_64-apple-darwin 40 | mkdir -p artifacts/darwin-amd64 41 | cp target/x86_64-apple-darwin/release/libwasmer_jni.dylib artifacts/darwin-amd64 42 | install_name_tool -id "@rpath/libwasmer_jni.dylib" ./artifacts/darwin-amd64/libwasmer_jni.dylib 43 | test -h target/current || ln -s x86_64-apple-darwin/release target/current 44 | 45 | build-rust-arm64-darwin: 46 | rustup target add aarch64-apple-darwin 47 | cargo build --release --target=aarch64-apple-darwin 48 | mkdir -p artifacts/darwin-arm64 49 | cp target/aarch64-apple-darwin/release/libwasmer_jni.dylib artifacts/darwin-arm64 50 | install_name_tool -id "@rpath/libwasmer_jni.dylib" ./artifacts/darwin-arm64/libwasmer_jni.dylib 51 | test -h target/current || ln -s aarch64-apple-darwin/release target/current 52 | 53 | build-rust-amd64-linux: 54 | rustup target add x86_64-unknown-linux-gnu 55 | cargo build --release --target=x86_64-unknown-linux-gnu 56 | mkdir -p artifacts/linux-amd64 57 | cp target/x86_64-unknown-linux-gnu/release/libwasmer_jni.so artifacts/linux-amd64/ 58 | test -h target/current || ln -s x86_64-unknown-linux-gnu/release target/current 59 | 60 | build-rust-amd64-windows: 61 | rustup target add x86_64-pc-windows-msvc 62 | cargo build --release --target=x86_64-pc-windows-msvc 63 | mkdir -p artifacts/windows-amd64 64 | cp target/x86_64-pc-windows-msvc/release/wasmer_jni.dll artifacts/windows-amd64/ 65 | mkdir -p target/current 66 | cp target/x86_64-pc-windows-msvc/release/wasmer_jni.dll target/current/ 67 | 68 | # Compile the Java part (incl. `build-test`, see `gradlew`). 69 | build-java: 70 | "./gradlew" --info build 71 | 72 | # Generate the Java C headers. 73 | build-headers: 74 | "./gradlew" --info generateJniHeaders 75 | 76 | # Run the tests. 77 | test: build-headers build-rust test-rust build-java 78 | 79 | # Run the Rust tests. 80 | test-rust: test-rust-$(build_arch)-$(build_os) 81 | 82 | test-rust-amd64-darwin: 83 | cargo test --lib --release --target=x86_64-apple-darwin 84 | 85 | test-rust-arm64-darwin: 86 | cargo test --lib --release --target=aarch64-apple-darwin 87 | 88 | test-rust-amd64-linux: 89 | cargo test --lib --release --target=x86_64-unknown-linux-gnu 90 | 91 | test-rust-amd64-windows: 92 | cargo test --lib --release --target=x86_64-pc-windows-msvc 93 | 94 | # Run the Java tests. 95 | test-java: 96 | "./gradlew" --info test 97 | 98 | # Test the examples. 99 | test-examples: 100 | @for example in $(shell find examples -name "*Example.java") ; do \ 101 | example=$${example#examples/}; \ 102 | example=$${example%Example.java}; \ 103 | echo "Testing $${example}"; \ 104 | make run-example EXAMPLE=$${example}; \ 105 | done 106 | 107 | # Generate JavaDoc. 108 | javadoc: 109 | "./gradlew" javadoc 110 | @echo "\n\n"'Open `build/docs/javadoc/index.html`.' 111 | 112 | # Make a JAR-file. 113 | package: 114 | "./gradlew" --info jar 115 | 116 | # Publish the package artifact to a public repository 117 | publish: 118 | "./gradlew" --info uploadToBintray 119 | 120 | # Run a specific example, with `make run-example EXAMPLE=Simple` for instance. 121 | run-example: 122 | $(eval JAR := $(shell find ./build/libs/ -name "wasmer-jni-*.jar")) 123 | @cd examples; \ 124 | javac -classpath "../${JAR}" ${EXAMPLE}Example.java; \ 125 | java -Djava.library.path=$(CURDIR)/artifacts/$(build_os)-$(build_arch) -classpath ".:../${JAR}" -enableassertions ${EXAMPLE}Example 126 | 127 | # Clean 128 | clean: 129 | cargo clean 130 | rm -rf build 131 | rm -rf artifacts 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | Wasmer logo 4 | 5 | 6 |

Wasmer Java

7 | 8 |

9 | 10 | Build Status 11 | 12 | 13 | License 14 | 15 | 16 | Go Package 17 | 18 | 19 | API Documentation 20 | 21 |

22 | 23 |

24 | Website 25 | 26 | Docs 27 | 28 | Slack Channel 29 |

30 | 31 |
32 | 33 |
34 | 35 | A complete and mature WebAssembly runtime for Java based on [Wasmer]. 36 | 37 | Features: 38 | 39 | * **Easy to use**: The `wasmer` API mimics the standard WebAssembly API, 40 | * **Fast**: The Wasmer JNI executes the WebAssembly modules as fast as 41 | possible, close to **native speed**, 42 | * **Safe**: All calls to WebAssembly will be fast, but more 43 | importantly, completely safe and sandboxed. 44 | 45 | [Wasmer]: https://github.com/wasmerio/wasmer 46 | 47 | # Install 48 | 49 | The Wasmer package is published in [Bintray](https://bintray.com/) on [the 50 | `wasmer/wasmer-jni` 51 | repository](https://bintray.com/wasmer/wasmer-jni/wasmer-jni). 52 | 53 | The JAR files are named as follows: 54 | `wasmer-jni-$(architecture)-$(os)-$(version).jar`. Thus, to include 55 | Wasmer JNI as a dependency, write for instance: 56 | 57 | ```gradle 58 | dependencies { 59 | implementation "org.wasmer:wasmer-jni-amd64-linux:0.3.0" 60 | } 61 | ``` 62 | 63 | > Note: It is also possible to download the Java JAR file from the [Github 64 | releases page](https://github.com/wasmerio/wasmer-java/releases)! 65 | > If you need to produce a JAR for your own platform and 66 | architecture, see [the Development Section](#development) to learn 67 | more. 68 | 69 | # Example 70 | 71 | There is a toy program in `java/src/test/resources/simple.rs`, written 72 | in Rust (or any other language that compiles to WebAssembly): 73 | 74 | ```rust 75 | #[no_mangle] 76 | pub extern fn sum(x: i32, y: i32) -> i32 { 77 | x + y 78 | } 79 | ``` 80 | 81 | After compilation to WebAssembly, the 82 | [`tests/resources/simple.wasm`](https://github.com/wasmerio/wasmer-java/blob/master/tests/resources/simple.wasm) 83 | binary file is generated. ([Download 84 | it](https://github.com/wasmerio/wasmer-java/raw/master/tests/resources/simple.wasm)). 85 | 86 | Then, we can execute it in Java: 87 | 88 | ```java 89 | class Example { 90 | public static void main(String[] args) { 91 | // `simple.wasm` is located at `tests/resources/`. 92 | Path wasmPath = Paths.get(new Example().getClass().getClassLoader().getResource("simple.wasm").getPath()); 93 | 94 | // Reads the WebAssembly module as bytes. 95 | byte[] wasmBytes = Files.readAllBytes(wasmPath); 96 | 97 | // Instantiates the WebAssembly module. 98 | Instance instance = new Instance(wasmBytes); 99 | 100 | // Calls an exported function, and returns an object array. 101 | Object[] results = instance.exports.getFunction("sum").apply(5, 37); 102 | 103 | System.out.println((Integer) results[0]); // 42 104 | 105 | // Drops an instance object pointer which is stored in Rust. 106 | instance.close(); 107 | } 108 | } 109 | ``` 110 | 111 | There is more examples in the `examples/` directory. Run them with the 112 | `Makefile`, such as: `make run-example EXAMPLE=Simple` to run the 113 | `SimpleExample` example. 114 | 115 | # API of the `wasmer` library 116 | 117 | The root namespace is `org.wasmer`. 118 | 119 | ## The `Instance` class 120 | 121 | The `Instance` constructor compiles and instantiates a WebAssembly 122 | module. It is built upon bytes. From here, it is possible to call 123 | exported functions, or exported memories. For example: 124 | 125 | ```java 126 | // Instantiates the WebAssembly module. 127 | Instance instance = new Instance(wasmBytes); 128 | 129 | // Calls an exported function. 130 | Object[] results = instance.exports.getFunction("sum").apply(1, 2); 131 | 132 | // Casts an object to an integer object because the result is an object array. 133 | int result = (Integer) results[0]; 134 | 135 | System.out.println(result); // 3 136 | 137 | // Drops an instance object pointer manually. Note that the garbage collector 138 | // will call this method before an object is removed from the memory. 139 | instance.close(); 140 | ``` 141 | 142 | ### Exports 143 | 144 | All exports, like functions or memories, are accessible on the 145 | `Instance.exports` field, which is of kind `Exports` (a read-only 146 | wrapper around a map of kind `Map`). The 147 | `Exports.get` method returns an object of type `Export`. To 148 | downcast it to an exported function or to an exported memory, you can 149 | use the respective `getFunction` or `getMemory` methods. The following 150 | sections describe each exports in details. 151 | 152 | #### Exported functions 153 | 154 | An exported function is a native Java closure (represented by the 155 | `exports.Function` class), where all arguments are automatically 156 | casted to WebAssembly values if possible, and all results are of type 157 | `Object`, which can be typed to `Integer` or `Float` for instance. 158 | 159 | ```java 160 | Function sum = instance.exports.getFunction("sum"); 161 | Object[] results = sum.apply(1, 2); 162 | 163 | System.out.println((Integer) results[0]); // 3 164 | ``` 165 | 166 | #### Exported memories 167 | 168 | An exported memory is a regular `Memory` class. 169 | 170 | ```java 171 | Memory memory = instance.exports.getMemory("memory_1"); 172 | ``` 173 | 174 | See the [`Memory`](#the-memory-class) class section for more information. 175 | 176 | ## The `Module` class 177 | 178 | The `Module.validate` static method checks whether a sequence of bytes 179 | represents a valid WebAssembly module: 180 | 181 | ```java 182 | // Checks that given bytes represent a valid WebAssembly module. 183 | boolean isValid = Module.validate(wasmBytes); 184 | ``` 185 | 186 | The `Module` constructor compiles a sequence of bytes into a 187 | WebAssembly module. From here, it is possible to instantiate it: 188 | 189 | ```java 190 | // Compiles the bytes into a WebAssembly module. 191 | Module module = new Module(wasmBytes); 192 | 193 | // Instantiates the WebAssembly module. 194 | Instance instance = module.instantiate(); 195 | ``` 196 | 197 | ### Serialization and deserialization 198 | 199 | The `Module.serialize` method and its complementary 200 | `Module.deserialize` static method help to respectively serialize and 201 | deserialize a _compiled_ WebAssembly module, thus saving the compilation 202 | time for the next use: 203 | 204 | ```java 205 | // Compiles the bytes into a WebAssembly module. 206 | Module module1 = new Module(wasmBytes); 207 | 208 | // Serializes the module. 209 | byte[] serializedModule = module1.serialize(); 210 | 211 | // Let's forget about the module for this example. 212 | module1 = null; 213 | 214 | // Deserializes the module. 215 | Module module2 = Module.deserialize(serializedModule); 216 | 217 | // Instantiates and uses it. 218 | Object[] results = module2.instantiate().exports.getFunction("sum").apply(1, 2); 219 | 220 | System.out.println((Integer) results[0]); // 3 221 | ``` 222 | 223 | ## The `Memory` class 224 | 225 | A WebAssembly instance has a linear memory, represented by the 226 | `Memory` class. Let's see how to read it. Consider the following Rust 227 | program: 228 | 229 | ```rust 230 | #[no_mangle] 231 | pub extern fn return_hello() -> *const u8 { 232 | b"Hello, World!\0".as_ptr() 233 | } 234 | ``` 235 | 236 | The `return_hello` function returns a pointer to a string. This string 237 | is stored in the WebAssembly memory. Let's read it. 238 | 239 | ```java 240 | Instance instance = new Instance(wasmBytes); 241 | 242 | // Gets the memory by specifying its exported name. 243 | Memory memory = instance.exports.getMemory("memory"); 244 | 245 | // Gets the pointer value as an integer. 246 | int pointer = (Integer) instance.exports.getFunction("return_hello").apply()[0]; 247 | 248 | // Reads the data from the memory. 249 | ByteBuffer memoryBuffer = memory.buffer(); 250 | byte[] stringBytes = new byte[13]; 251 | memoryBuffer.position(pointer); 252 | memoryBuffer.get(stringBytes); 253 | 254 | System.out.println(new String(stringBytes)); // Hello, World! 255 | 256 | instance.close(); 257 | ``` 258 | 259 | ### Memory grow 260 | 261 | The `Memory.grow` methods allows to grow the memory by a number of pages (of 64KiB each). 262 | 263 | ```java 264 | // Grows the memory by the specified number of pages, and returns the number of old pages. 265 | int oldPageSize = memory.grow(1); 266 | ``` 267 | 268 | ## Development 269 | 270 | The Wasmer JNI library is based on the [Wasmer 271 | runtime](https://github.com/wasmerio/wasmer), which is written in 272 | [Rust](https://www.rust-lang.org/), and is compiled to a shared 273 | library. For your convenience, we produce one JAR (Java Archive) per 274 | architecture and platform. By now, the following are supported, 275 | consistently tested, and pre-packaged: 276 | 277 | - `amd64-darwin`, 278 | - `amd64-linux`, 279 | - `amd64-windows`. 280 | 281 | More architectures and more platforms will be added in a close 282 | future. If you need a specific one, [feel free to 283 | ask](https://github.com/wasmerio/wasmer-java/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=)! 284 | 285 | If you want to build the extension you will need the following tools: 286 | 287 | - [Gradle](https://gradle.org/), a package management tool, 288 | - [Rust](https://rust-lang.org/), the Rust programming language, 289 | - [Java](https://www.java.com/), because it's a Java project ;-). 290 | 291 | ```sh 292 | $ git clone https://github.com/wasmerio/wasmer-java/ 293 | $ cd wasmer-java 294 | ``` 295 | 296 | To build the entire project, run the following command: 297 | 298 | ```sh 299 | $ make build 300 | ``` 301 | 302 | To build the JAR package: 303 | 304 | ```sh 305 | $ make package 306 | ``` 307 | 308 | This will generate the file `build/libs/wasmer-jni-$(architecture)-$(os)-0.3.0.jar`. 309 | 310 | #### Automatic dependencies per architecture and platform 311 | 312 |
313 | It is possible to infer the archive appendix automatically, see how. 314 | 315 | According the [Gradle Jar 316 | API](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:appendix), 317 | the `$(architecture)-$(os)` part is called the _archive prefix_. To 318 | infer that appendix automatically to configure your dependencies, you 319 | can use the following `inferWasmerJarAppendix` function: 320 | 321 | ```gradle 322 | String inferWasmerJarAppendix() { 323 | def nativePlatform = new org.gradle.nativeplatform.platform.internal.DefaultNativePlatform("current") 324 | def arch = nativePlatform.architecture 325 | def os = nativePlatform.operatingSystem 326 | 327 | def arch_name 328 | 329 | switch (arch.getName()) { 330 | case ["x86_64", "x64", "x86-64"]: 331 | arch_name = "amd64" 332 | break; 333 | 334 | default: 335 | throw new RuntimeException("`wasmer-jni` has no pre-compiled archive for the architecture " + arch.getName()) 336 | } 337 | 338 | def os_name 339 | 340 | if (os.isMacOsX()) { 341 | os_name = "darwin" 342 | } else if (os.isLinux()) { 343 | os_name = "linux" 344 | } else if (os.isWindows()) { 345 | os_name = "windows" 346 | } else { 347 | throw new RuntimeException("`wasmer-jni` has no pre-compiled archive for the platform " + os.getName()) 348 | } 349 | 350 | return arch_name + "-" + os_name 351 | } 352 | ``` 353 | 354 | Finally, you can configure your dependencies such as: 355 | 356 | ```gradle 357 | dependencies { 358 | implementation "org.wasmer:wasmer-jni-" + inferWasmerJarAppendix() + ":0.3.0" 359 | } 360 | ``` 361 | 362 |
363 | 364 | ### Testing 365 | 366 | Run the following command: 367 | 368 | ```sh 369 | $ make test 370 | ``` 371 | 372 | Note: Testing automatically builds the project. 373 | 374 | ### Documentation 375 | 376 | Run the following command: 377 | 378 | ```sh 379 | $ make javadoc 380 | ``` 381 | 382 | Then open `build/docs/javadoc/index.html`. 383 | 384 | # What is WebAssembly? 385 | 386 | Quoting [the WebAssembly site](https://webassembly.org/): 387 | 388 | > WebAssembly (abbreviated Wasm) is a binary instruction format for a 389 | > stack-based virtual machine. Wasm is designed as a portable target 390 | > for compilation of high-level languages like C/C++/Rust, enabling 391 | > deployment on the web for client and server applications. 392 | 393 | About speed: 394 | 395 | > WebAssembly aims to execute at native speed by taking advantage of 396 | > [common hardware 397 | > capabilities](https://webassembly.org/docs/portability/#assumptions-for-efficient-execution) 398 | > available on a wide range of platforms. 399 | 400 | About safety: 401 | 402 | > WebAssembly describes a memory-safe, sandboxed [execution 403 | > environment](https://webassembly.org/docs/semantics/#linear-memory) […]. 404 | 405 | # License 406 | 407 | The entire project is under the MIT License. Please read [the 408 | `LICENSE` file][license]. 409 | 410 | [license]: https://github.com/wasmerio/wasmer/blob/master/LICENSE 411 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | // As Wasmer is a package, we need tools to build the JARs and so 4 | id "java-library" 5 | id "com.jfrog.bintray" version "1.8.5" 6 | } 7 | 8 | allprojects { 9 | group "org.wasmer" 10 | version "0.3.0" 11 | } 12 | 13 | // This is needed for the Java plugin to make sure 14 | // the generated class files are compatible with 15 | // old versions of Java. 16 | sourceCompatibility = 1.8 17 | targetCompatibility = 1.8 18 | 19 | sourceSets { 20 | main { 21 | java { 22 | srcDirs = ["src/java"] 23 | } 24 | resources { 25 | srcDirs = ["$buildDir/toArtifact"] 26 | } 27 | } 28 | test { 29 | java { 30 | srcDirs = ["tests"] 31 | } 32 | resources { 33 | srcDirs = ["tests/resources"] 34 | } 35 | } 36 | } 37 | 38 | javadoc { 39 | options.links "https://docs.oracle.com/javase/8/docs/api/" 40 | // TODO: change when https://github.com/gradle/gradle/issues/2354 is fixed 41 | options.addStringOption "Xdoclint:all", "-Xdoclint:-missing" 42 | } 43 | 44 | repositories { 45 | jcenter() 46 | google() 47 | maven { 48 | url "https://plugins.gradle.org/m2/" 49 | } 50 | } 51 | 52 | dependencies { 53 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.4.2") 54 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.4.2") 55 | } 56 | 57 | test { 58 | useJUnitPlatform() 59 | } 60 | 61 | jar { 62 | manifest { 63 | attributes("Implementation-Title": project.name, 64 | "Implementation-Version": project.version) 65 | } 66 | 67 | // The JAR name is defined as 68 | // `${baseName}-${appendix}-${version}-${classifier}.${extension}`. 69 | archiveAppendix = inferWasmerJarAppendix() 70 | } 71 | 72 | String inferWasmerJarAppendix() { 73 | def nativePlatform = new org.gradle.nativeplatform.platform.internal.DefaultNativePlatform("current") 74 | def arch = nativePlatform.architecture 75 | def os = nativePlatform.operatingSystem 76 | 77 | def arch_name 78 | 79 | switch (arch.getName()) { 80 | case ["x86_64", "x64", "x86-64"]: 81 | arch_name = "amd64" 82 | break; 83 | 84 | case ["aarch64", "arm-v8"]: 85 | arch_name = "arm64" 86 | break; 87 | 88 | default: 89 | throw new RuntimeException("Architecture " + arch.getName() + " is not supported.") 90 | } 91 | 92 | def os_name 93 | 94 | if (os.isMacOsX()) { 95 | os_name = "darwin" 96 | } else if (os.isLinux()) { 97 | os_name = "linux" 98 | } else if (os.isWindows()) { 99 | os_name = "windows" 100 | } else { 101 | throw new RuntimeException("Platform " + os.getName() + " is not supported.") 102 | } 103 | 104 | return arch_name + "-" + os_name 105 | } 106 | 107 | task generateJniHeaders(type: JavaCompile) { 108 | description "Generate the JNI header files (in `include/`)." 109 | 110 | classpath = sourceSets.main.compileClasspath 111 | destinationDir file("include") 112 | source = sourceSets.main.java 113 | options.compilerArgs += [ 114 | "-h", file("include"), 115 | ] 116 | options.verbose = true 117 | } 118 | 119 | task buildRust(type: Exec) { 120 | dependsOn generateJniHeaders 121 | 122 | description "Build the Rust project." 123 | 124 | commandLine "make", "build-rust" 125 | } 126 | 127 | task copyAllArtifacts(type: Copy) { 128 | dependsOn buildRust 129 | 130 | description "Copy build artifacts to the `build/` directory." 131 | 132 | from "artifacts" 133 | include "**/*" 134 | into "$buildDir/toArtifact/org/wasmer/native/" 135 | } 136 | 137 | tasks.withType(Test) { 138 | // We add the path, so the Java Tests can find the 139 | // shared object file 140 | systemProperty "java.library.path", "target/current/" 141 | 142 | testLogging { 143 | outputs.upToDateWhen { false } 144 | 145 | // Don"t capture the standard output. 146 | showStandardStreams = true 147 | } 148 | } 149 | 150 | jar.doLast() { 151 | // Display specific “action outputs” for Github Actions. 152 | def jar_name = project.archivesBaseName + "-" + inferWasmerJarAppendix() + "-" + project.version + ".jar" 153 | println(jar_name) 154 | println("::set-output name=path::./build/libs/" + jar_name) 155 | println("::set-output name=name::" + jar_name) 156 | } 157 | 158 | jar.outputs.upToDateWhen { false } 159 | 160 | // We build the integration before running any test 161 | compileTestJava.dependsOn buildRust 162 | processResources.dependsOn copyAllArtifacts 163 | 164 | // Publishing on bintray. 165 | task uploadToBintray { 166 | dependsOn bintrayUpload 167 | 168 | apply plugin: "maven" 169 | apply plugin: "maven-publish" 170 | 171 | /// First, set up a POM configuration. 172 | def pomConfig = { 173 | name "wasmer-jni" 174 | packaging "jar" 175 | description "Wasmer JNI is a library to execute WebAssembly binaries" 176 | url "https://wasmer.io" 177 | scm { 178 | connection "scm:git:git@github.com:wasmerio/wasmer-java.git" 179 | developerConnection "scm:git:git@github.com:wasmerio/wasmer-java.git" 180 | url "git@github.com:wasmerio/wasmer-java.git" 181 | } 182 | licenses { 183 | license { 184 | name "MIT License" 185 | url "https://opensource.org/licenses/MIT" 186 | } 187 | } 188 | developers { 189 | developer { 190 | id "hywan" 191 | name "Ivan Enderlin" 192 | url "https://github.com/Hywan" 193 | } 194 | } 195 | } 196 | 197 | publishing { 198 | publications { 199 | MyPublication(MavenPublication) { 200 | from components.java 201 | groupId "org.wasmer" 202 | artifactId "wasmer-jni-" + inferWasmerJarAppendix() 203 | version project.version 204 | 205 | artifacts { 206 | archives jar 207 | } 208 | 209 | pom.withXml { 210 | def root = asNode() 211 | root.children().last() + pomConfig 212 | } 213 | } 214 | } 215 | } 216 | 217 | /// Second, set up Bintray. 218 | bintray { 219 | user = System.getenv("BINTRAY_USER") 220 | key = System.getenv("BINTRAY_API_KEY") 221 | publications = ["MyPublication"] 222 | pkg { 223 | repo = "wasmer-jni" 224 | name = "wasmer-jni" 225 | licenses = ["MIT"] 226 | vcsUrl = "https://github.com/wasmerio/wasmer-java.git" 227 | userOrg = "wasmer" 228 | desc = "Wasmer JNI is a library to execute WebAssembly binaries" 229 | } 230 | } 231 | } 232 | 233 | // Local Variables: 234 | // mode: java 235 | // End: 236 | // vim: set ft=java : 237 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*.class -------------------------------------------------------------------------------- /examples/GreetExample.java: -------------------------------------------------------------------------------- 1 | import org.wasmer.Instance; 2 | import org.wasmer.Memory; 3 | 4 | import java.io.IOException; 5 | import java.lang.StringBuilder; 6 | import java.nio.ByteBuffer; 7 | import java.nio.charset.StandardCharsets; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | 11 | class GreetExample { 12 | public static void main(String[] args) throws IOException { 13 | // Instantiates the module. 14 | byte[] bytes = Files.readAllBytes(Paths.get("greet.wasm")); 15 | Instance instance = new Instance(bytes); 16 | Memory memory = instance.exports.getMemory("memory"); 17 | 18 | // Set the subject to greet. 19 | byte[] subject = "Wasmer".getBytes(StandardCharsets.UTF_8); 20 | 21 | // Allocate memory for the subject, and get a pointer to it. 22 | Integer input_pointer = (Integer) instance.exports.getFunction("allocate").apply(subject.length)[0]; 23 | 24 | // Write the subject into the memory. 25 | { 26 | ByteBuffer memoryBuffer = memory.buffer(); 27 | memoryBuffer.position(input_pointer); 28 | memoryBuffer.put(subject); 29 | } 30 | 31 | // Run the `greet` function. Give the pointer to the subject. 32 | Integer output_pointer = (Integer) instance.exports.getFunction("greet").apply(input_pointer)[0]; 33 | 34 | // Read the result of the `greet` function. 35 | String result; 36 | 37 | { 38 | StringBuilder output = new StringBuilder(); 39 | ByteBuffer memoryBuffer = memory.buffer(); 40 | 41 | for (Integer i = output_pointer, max = memoryBuffer.limit(); i < max; ++i) { 42 | byte[] b = new byte[1]; 43 | memoryBuffer.position(i); 44 | memoryBuffer.get(b); 45 | 46 | if (b[0] == 0) { 47 | break; 48 | } 49 | 50 | output.appendCodePoint(b[0]); 51 | } 52 | 53 | result = output.toString(); 54 | } 55 | 56 | assert result.equals("Hello, Wasmer!"); 57 | 58 | instance.close(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/MemoryExample.java: -------------------------------------------------------------------------------- 1 | import org.wasmer.Instance; 2 | import org.wasmer.Memory; 3 | 4 | import java.io.IOException; 5 | import java.nio.ByteBuffer; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | 9 | class MemoryExample { 10 | public static void main(String[] args) throws IOException { 11 | byte[] bytes = Files.readAllBytes(Paths.get("memory.wasm")); 12 | Instance instance = new Instance(bytes); 13 | Integer pointer = (Integer) instance.exports.getFunction("return_hello").apply()[0]; 14 | 15 | Memory memory = instance.exports.getMemory("memory"); 16 | 17 | ByteBuffer memoryBuffer = memory.buffer(); 18 | 19 | byte[] data = new byte[13]; 20 | memoryBuffer.position(pointer); 21 | memoryBuffer.get(data); 22 | 23 | String result = new String(data); 24 | 25 | assert result.equals("Hello, World!"); 26 | 27 | instance.close(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/SimpleExample.java: -------------------------------------------------------------------------------- 1 | import org.wasmer.Instance; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Files; 5 | import java.nio.file.Paths; 6 | 7 | class SimpleExample { 8 | public static void main(String[] args) throws IOException { 9 | byte[] bytes = Files.readAllBytes(Paths.get("simple.wasm")); 10 | Instance instance = new Instance(bytes); 11 | 12 | Integer result = (Integer) instance.exports.getFunction("sum").apply(1, 2)[0]; 13 | 14 | assert result == 3; 15 | 16 | instance.close(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/greet.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{CStr, CString}; 2 | use std::mem; 3 | use std::os::raw::{c_char, c_void}; 4 | 5 | #[no_mangle] 6 | pub extern fn allocate(size: usize) -> *mut c_void { 7 | let mut buffer = Vec::with_capacity(size); 8 | let pointer = buffer.as_mut_ptr(); 9 | mem::forget(buffer); 10 | 11 | pointer as *mut c_void 12 | } 13 | 14 | #[no_mangle] 15 | pub extern fn deallocate(pointer: *mut c_void, capacity: usize) { 16 | unsafe { 17 | let _ = Vec::from_raw_parts(pointer, 0, capacity); 18 | } 19 | } 20 | 21 | #[no_mangle] 22 | pub extern fn greet(subject: *mut c_char) -> *mut c_char { 23 | let subject = unsafe { CStr::from_ptr(subject).to_bytes().to_vec() }; 24 | let mut output = b"Hello, ".to_vec(); 25 | output.extend(&subject); 26 | output.extend(&[b'!']); 27 | 28 | unsafe { CString::from_vec_unchecked(output) }.into_raw() 29 | } 30 | -------------------------------------------------------------------------------- /examples/greet.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/examples/greet.wasm -------------------------------------------------------------------------------- /examples/memory.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern fn return_hello() -> *const u8 { 3 | b"Hello, World!\0".as_ptr() 4 | } 5 | -------------------------------------------------------------------------------- /examples/memory.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/examples/memory.wasm -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern fn sum(x: i32, y: i32) -> i32 { 3 | x + y 4 | } 5 | -------------------------------------------------------------------------------- /examples/simple.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/examples/simple.wasm -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # This file has been automatically generated by Gradle. 4 | 5 | # 6 | # Copyright 2015 the original author or authors. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # https://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | ############################################################################## 22 | ## 23 | ## Gradle start up script for UN*X 24 | ## 25 | ############################################################################## 26 | 27 | # Attempt to set APP_HOME 28 | # Resolve links: $0 may be a link 29 | PRG="$0" 30 | # Need this for relative symlinks. 31 | while [ -h "$PRG" ] ; do 32 | ls=`ls -ld "$PRG"` 33 | link=`expr "$ls" : '.*-> \(.*\)$'` 34 | if expr "$link" : '/.*' > /dev/null; then 35 | PRG="$link" 36 | else 37 | PRG=`dirname "$PRG"`"/$link" 38 | fi 39 | done 40 | SAVED="`pwd`" 41 | cd "`dirname \"$PRG\"`/" >/dev/null 42 | APP_HOME="`pwd -P`" 43 | cd "$SAVED" >/dev/null 44 | 45 | APP_NAME="Gradle" 46 | APP_BASE_NAME=`basename "$0"` 47 | 48 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 49 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 50 | 51 | # Use the maximum available, or set MAX_FD != -1 to use that value. 52 | MAX_FD="maximum" 53 | 54 | warn () { 55 | echo "$*" 56 | } 57 | 58 | die () { 59 | echo 60 | echo "$*" 61 | echo 62 | exit 1 63 | } 64 | 65 | # OS specific support (must be 'true' or 'false'). 66 | cygwin=false 67 | msys=false 68 | darwin=false 69 | nonstop=false 70 | case "`uname`" in 71 | CYGWIN* ) 72 | cygwin=true 73 | ;; 74 | Darwin* ) 75 | darwin=true 76 | ;; 77 | MINGW* ) 78 | msys=true 79 | ;; 80 | NONSTOP* ) 81 | nonstop=true 82 | ;; 83 | esac 84 | 85 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 86 | 87 | # Determine the Java command to use to start the JVM. 88 | if [ -n "$JAVA_HOME" ] ; then 89 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 90 | # IBM's JDK on AIX uses strange locations for the executables 91 | JAVACMD="$JAVA_HOME/jre/sh/java" 92 | else 93 | JAVACMD="$JAVA_HOME/bin/java" 94 | fi 95 | if [ ! -x "$JAVACMD" ] ; then 96 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 97 | 98 | Please set the JAVA_HOME variable in your environment to match the 99 | location of your Java installation." 100 | fi 101 | else 102 | JAVACMD="java" 103 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 104 | 105 | Please set the JAVA_HOME variable in your environment to match the 106 | location of your Java installation." 107 | fi 108 | 109 | # Increase the maximum file descriptors if we can. 110 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 111 | MAX_FD_LIMIT=`ulimit -H -n` 112 | if [ $? -eq 0 ] ; then 113 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 114 | MAX_FD="$MAX_FD_LIMIT" 115 | fi 116 | ulimit -n $MAX_FD 117 | if [ $? -ne 0 ] ; then 118 | warn "Could not set maximum file descriptor limit: $MAX_FD" 119 | fi 120 | else 121 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 122 | fi 123 | fi 124 | 125 | # For Darwin, add options to specify how the application appears in the dock 126 | if $darwin; then 127 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 128 | fi 129 | 130 | # For Cygwin or MSYS, switch paths to Windows format before running java 131 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 132 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 133 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem This file has been automatically generated by Gradle. 2 | 3 | @rem 4 | @rem Copyright 2015 the original author or authors. 5 | @rem 6 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 7 | @rem you may not use this file except in compliance with the License. 8 | @rem You may obtain a copy of the License at 9 | @rem 10 | @rem https://www.apache.org/licenses/LICENSE-2.0 11 | @rem 12 | @rem Unless required by applicable law or agreed to in writing, software 13 | @rem distributed under the License is distributed on an "AS IS" BASIS, 14 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | @rem See the License for the specific language governing permissions and 16 | @rem limitations under the License. 17 | @rem 18 | 19 | @if "%DEBUG%" == "" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%" == "" set DIRNAME=. 31 | set APP_BASE_NAME=%~n0 32 | set APP_HOME=%DIRNAME% 33 | 34 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 35 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 36 | 37 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 38 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 39 | 40 | @rem Find java.exe 41 | if defined JAVA_HOME goto findJavaFromJavaHome 42 | 43 | set JAVA_EXE=java.exe 44 | %JAVA_EXE% -version >NUL 2>&1 45 | if "%ERRORLEVEL%" == "0" goto init 46 | 47 | echo. 48 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 49 | echo. 50 | echo Please set the JAVA_HOME variable in your environment to match the 51 | echo location of your Java installation. 52 | 53 | goto fail 54 | 55 | :findJavaFromJavaHome 56 | set JAVA_HOME=%JAVA_HOME:"=% 57 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 58 | 59 | if exist "%JAVA_EXE%" goto init 60 | 61 | echo. 62 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 63 | echo. 64 | echo Please set the JAVA_HOME variable in your environment to match the 65 | echo location of your Java installation. 66 | 67 | goto fail 68 | 69 | :init 70 | @rem Get command-line arguments, handling Windows variants 71 | 72 | if not "%OS%" == "Windows_NT" goto win9xME_args 73 | 74 | :win9xME_args 75 | @rem Slurp the command line arguments. 76 | set CMD_LINE_ARGS= 77 | set _SKIP=2 78 | 79 | :win9xME_args_slurp 80 | if "x%~1" == "x" goto execute 81 | 82 | set CMD_LINE_ARGS=%* 83 | 84 | :execute 85 | @rem Setup the command line 86 | 87 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 88 | 89 | @rem Execute Gradle 90 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 91 | 92 | :end 93 | @rem End local scope for the variables with windows NT shell 94 | if "%ERRORLEVEL%"=="0" goto mainEnd 95 | 96 | :fail 97 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 98 | rem the _cmd.exe /c_ return code! 99 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 100 | exit /b 1 101 | 102 | :mainEnd 103 | if "%OS%"=="Windows_NT" endlocal 104 | 105 | :omega 106 | -------------------------------------------------------------------------------- /include/org_wasmer_Instance.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class org_wasmer_Instance */ 4 | 5 | #ifndef _Included_org_wasmer_Instance 6 | #define _Included_org_wasmer_Instance 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: org_wasmer_Instance 12 | * Method: nativeInstantiate 13 | * Signature: (Lorg/wasmer/Instance;[B)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_org_wasmer_Instance_nativeInstantiate 16 | (JNIEnv *, jobject, jobject, jbyteArray); 17 | 18 | /* 19 | * Class: org_wasmer_Instance 20 | * Method: nativeDrop 21 | * Signature: (J)V 22 | */ 23 | JNIEXPORT void JNICALL Java_org_wasmer_Instance_nativeDrop 24 | (JNIEnv *, jobject, jlong); 25 | 26 | /* 27 | * Class: org_wasmer_Instance 28 | * Method: nativeCallExportedFunction 29 | * Signature: (JLjava/lang/String;[Ljava/lang/Object;)[Ljava/lang/Object; 30 | */ 31 | JNIEXPORT jobjectArray JNICALL Java_org_wasmer_Instance_nativeCallExportedFunction 32 | (JNIEnv *, jobject, jlong, jstring, jobjectArray); 33 | 34 | /* 35 | * Class: org_wasmer_Instance 36 | * Method: nativeInitializeExportedFunctions 37 | * Signature: (J)V 38 | */ 39 | JNIEXPORT void JNICALL Java_org_wasmer_Instance_nativeInitializeExportedFunctions 40 | (JNIEnv *, jclass, jlong); 41 | 42 | /* 43 | * Class: org_wasmer_Instance 44 | * Method: nativeInitializeExportedMemories 45 | * Signature: (J)V 46 | */ 47 | JNIEXPORT void JNICALL Java_org_wasmer_Instance_nativeInitializeExportedMemories 48 | (JNIEnv *, jclass, jlong); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | #endif 54 | -------------------------------------------------------------------------------- /include/org_wasmer_Memory.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class org_wasmer_Memory */ 4 | 5 | #ifndef _Included_org_wasmer_Memory 6 | #define _Included_org_wasmer_Memory 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: org_wasmer_Memory 12 | * Method: nativeMemoryView 13 | * Signature: (Lorg/wasmer/Memory;J)V 14 | */ 15 | JNIEXPORT void JNICALL Java_org_wasmer_Memory_nativeMemoryView 16 | (JNIEnv *, jobject, jobject, jlong); 17 | 18 | /* 19 | * Class: org_wasmer_Memory 20 | * Method: nativeMemoryGrow 21 | * Signature: (Lorg/wasmer/Memory;JI)I 22 | */ 23 | JNIEXPORT jint JNICALL Java_org_wasmer_Memory_nativeMemoryGrow 24 | (JNIEnv *, jobject, jobject, jlong, jint); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | #endif 30 | -------------------------------------------------------------------------------- /include/org_wasmer_Module.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class org_wasmer_Module */ 4 | 5 | #ifndef _Included_org_wasmer_Module 6 | #define _Included_org_wasmer_Module 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: org_wasmer_Module 12 | * Method: nativeModuleInstantiate 13 | * Signature: (Lorg/wasmer/Module;[B)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_org_wasmer_Module_nativeModuleInstantiate 16 | (JNIEnv *, jobject, jobject, jbyteArray); 17 | 18 | /* 19 | * Class: org_wasmer_Module 20 | * Method: nativeDrop 21 | * Signature: (J)V 22 | */ 23 | JNIEXPORT void JNICALL Java_org_wasmer_Module_nativeDrop 24 | (JNIEnv *, jobject, jlong); 25 | 26 | /* 27 | * Class: org_wasmer_Module 28 | * Method: nativeInstantiate 29 | * Signature: (JLorg/wasmer/Instance;)J 30 | */ 31 | JNIEXPORT jlong JNICALL Java_org_wasmer_Module_nativeInstantiate 32 | (JNIEnv *, jobject, jlong, jobject); 33 | 34 | /* 35 | * Class: org_wasmer_Module 36 | * Method: nativeValidate 37 | * Signature: ([B)Z 38 | */ 39 | JNIEXPORT jboolean JNICALL Java_org_wasmer_Module_nativeValidate 40 | (JNIEnv *, jclass, jbyteArray); 41 | 42 | /* 43 | * Class: org_wasmer_Module 44 | * Method: nativeSerialize 45 | * Signature: (J)[B 46 | */ 47 | JNIEXPORT jbyteArray JNICALL Java_org_wasmer_Module_nativeSerialize 48 | (JNIEnv *, jobject, jlong); 49 | 50 | /* 51 | * Class: org_wasmer_Module 52 | * Method: nativeDeserialize 53 | * Signature: (Lorg/wasmer/Module;[B)J 54 | */ 55 | JNIEXPORT jlong JNICALL Java_org_wasmer_Module_nativeDeserialize 56 | (JNIEnv *, jclass, jobject, jbyteArray); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | #endif 62 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'wasmer-jni' 2 | -------------------------------------------------------------------------------- /src/exception.rs: -------------------------------------------------------------------------------- 1 | pub use jni::errors::Error; 2 | use jni::{errors::ErrorKind, JNIEnv}; 3 | use std::thread; 4 | 5 | pub fn runtime_error(message: String) -> Error { 6 | Error::from_kind(ErrorKind::Msg(message)) 7 | } 8 | 9 | #[derive(Debug)] 10 | pub enum JOption { 11 | Some(T), 12 | None, 13 | } 14 | 15 | impl JOption { 16 | pub fn unwrap_or(self, default: T) -> T { 17 | match self { 18 | JOption::Some(result) => result, 19 | JOption::None => default, 20 | } 21 | } 22 | } 23 | 24 | pub fn joption_or_throw(env: &JNIEnv, result: thread::Result>) -> JOption { 25 | match result { 26 | Ok(result) => match result { 27 | Ok(result) => JOption::Some(result), 28 | Err(error) => { 29 | if !env.exception_check().unwrap() { 30 | env.throw_new("java/lang/RuntimeException", &error.to_string()) 31 | .expect("Cannot throw an `java/lang/RuntimeException` exception."); 32 | } 33 | 34 | JOption::None 35 | } 36 | }, 37 | Err(ref error) => { 38 | env.throw_new("java/lang/RuntimeException", format!("{:?}", error)) 39 | .expect("Cannot throw an `java/lang/RuntimeException` exception."); 40 | 41 | JOption::None 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/instance.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | exception::{joption_or_throw, runtime_error, Error}, 3 | memory, 4 | memory::Memory, 5 | types::{jptr, Pointer}, 6 | value::{Value, DOUBLE_CLASS, FLOAT_CLASS, INT_CLASS, LONG_CLASS}, 7 | }; 8 | use jni::{ 9 | objects::{GlobalRef, JClass, JObject, JString, JValue}, 10 | sys::{jbyteArray, jobjectArray}, 11 | JNIEnv, 12 | }; 13 | use std::{collections::HashMap, convert::TryFrom, panic, rc::Rc}; 14 | use wasmer_runtime::{imports, instantiate, DynFunc, Export, Value as WasmValue}; 15 | use wasmer_runtime as core; 16 | 17 | pub struct Instance { 18 | pub java_instance_object: GlobalRef, 19 | pub instance: Rc, 20 | pub memories: HashMap, 21 | } 22 | 23 | impl Instance { 24 | fn new(java_instance_object: GlobalRef, module_bytes: Vec) -> Result { 25 | let module_bytes = module_bytes.as_slice(); 26 | let imports = imports! {}; 27 | let instance = match instantiate(module_bytes, &imports) { 28 | Ok(instance) => Rc::new(instance), 29 | Err(e) => { 30 | return Err(runtime_error(format!( 31 | "Failed to instantiate the module: {}", 32 | e 33 | ))) 34 | } 35 | }; 36 | 37 | let memories: HashMap = instance 38 | .exports() 39 | .filter_map(|(export_name, export)| match export { 40 | Export::Memory(memory) => Some((export_name.to_string(), Memory::new(Rc::new(memory.clone())))), 41 | _ => None, 42 | }) 43 | .collect(); 44 | 45 | Ok(Self { 46 | java_instance_object, 47 | instance, 48 | memories, 49 | }) 50 | } 51 | 52 | fn call_exported_function( 53 | &self, 54 | export_name: String, 55 | arguments: Vec, 56 | ) -> Result, Error> { 57 | let function: DynFunc = self.instance.exports.get(&export_name).map_err(|_| { 58 | runtime_error(format!( 59 | "Exported function `{}` does not exist", 60 | export_name 61 | )) 62 | })?; 63 | 64 | function 65 | .call(arguments.as_slice()) 66 | .map_err(|e| runtime_error(format!("{}", e))) 67 | } 68 | } 69 | 70 | #[no_mangle] 71 | pub extern "system" fn Java_org_wasmer_Instance_nativeInstantiate( 72 | env: JNIEnv, 73 | _class: JClass, 74 | this: JObject, 75 | module_bytes: jbyteArray, 76 | ) -> jptr { 77 | let output = panic::catch_unwind(|| { 78 | let module_bytes = env.convert_byte_array(module_bytes)?; 79 | let java_instance = env.new_global_ref(this)?; 80 | 81 | let instance = Instance::new(java_instance, module_bytes)?; 82 | 83 | Ok(Pointer::new(instance).into()) 84 | }); 85 | 86 | joption_or_throw(&env, output).unwrap_or(0) 87 | } 88 | 89 | #[no_mangle] 90 | pub extern "system" fn Java_org_wasmer_Instance_nativeDrop( 91 | _env: JNIEnv, 92 | _class: JClass, 93 | instance_pointer: jptr, 94 | ) { 95 | let _: Pointer = instance_pointer.into(); 96 | } 97 | 98 | #[no_mangle] 99 | pub extern "system" fn Java_org_wasmer_Instance_nativeCallExportedFunction<'a>( 100 | env: JNIEnv<'a>, 101 | _class: JClass, 102 | instance_pointer: jptr, 103 | export_name: JString, 104 | arguments_pointer: jobjectArray, 105 | ) -> jobjectArray { 106 | let output = panic::catch_unwind(|| { 107 | let instance: &Instance = Into::>::into(instance_pointer).borrow(); 108 | let export_name: String = env.get_string(export_name)?.into(); 109 | 110 | let arguments_length = env.get_array_length(arguments_pointer)?; 111 | 112 | let arguments = (0..arguments_length) 113 | .map(|i| env.get_object_array_element(arguments_pointer, i)) 114 | .collect::, Error>>()?; 115 | 116 | let results = instance.call_exported_function( 117 | export_name.clone(), 118 | arguments 119 | .iter() 120 | .enumerate() 121 | .map(|(nth, argument)| { 122 | Ok( 123 | Value::try_from((&env, *argument)) 124 | .map_err(|_| { 125 | runtime_error(format!( 126 | "Failed to convert the argument {}nth of `{}` into a WebAssembly value.", 127 | nth, 128 | export_name, 129 | )) 130 | })? 131 | .inner()) 132 | }) 133 | .collect::, Error>>()?, 134 | )?; 135 | 136 | let obj_array = env.new_object_array( 137 | i32::try_from(results.len()).map_err(|e| runtime_error(e.to_string()))?, 138 | "java/lang/Object", 139 | JObject::null(), 140 | )?; 141 | 142 | if results.len() > 0 { 143 | for (nth, result) in results.iter().enumerate() { 144 | let obj = match result { 145 | WasmValue::I32(val) => env.new_object(INT_CLASS, "(I)V", &[JValue::from(*val)]), 146 | WasmValue::I64(val) => { 147 | env.new_object(LONG_CLASS, "(J)V", &[JValue::from(*val)]) 148 | } 149 | WasmValue::F32(val) => { 150 | env.new_object(FLOAT_CLASS, "(F)V", &[JValue::from(*val)]) 151 | } 152 | WasmValue::F64(val) => { 153 | env.new_object(DOUBLE_CLASS, "(D)V", &[JValue::from(*val)]) 154 | } 155 | _ => unreachable!(), 156 | }?; 157 | 158 | env.set_object_array_element(obj_array, nth as i32, obj)?; 159 | } 160 | 161 | Ok(obj_array) 162 | } else { 163 | Ok(JObject::null().into_inner()) 164 | } 165 | }); 166 | 167 | joption_or_throw(&env, output).unwrap_or(JObject::null().into_inner()) 168 | } 169 | 170 | #[no_mangle] 171 | pub extern "system" fn Java_org_wasmer_Instance_nativeInitializeExportedFunctions( 172 | env: JNIEnv, 173 | _class: JClass, 174 | instance_pointer: jptr, 175 | ) { 176 | let output = panic::catch_unwind(|| { 177 | let instance: &Instance = Into::>::into(instance_pointer).borrow(); 178 | 179 | let exports_object: JObject = env 180 | .get_field( 181 | instance.java_instance_object.as_obj(), 182 | "exports", 183 | "Lorg/wasmer/Exports;", 184 | )? 185 | .l()?; 186 | 187 | for (export_name, export) in instance.instance.exports() { 188 | if let Export::Function { .. } = export { 189 | let name = env.new_string(export_name)?; 190 | 191 | env.call_method( 192 | exports_object, 193 | "addFunction", 194 | "(Ljava/lang/String;)V", 195 | &[JObject::from(name).into()], 196 | )?; 197 | } 198 | } 199 | Ok(()) 200 | }); 201 | 202 | joption_or_throw(&env, output).unwrap_or(()) 203 | } 204 | 205 | #[no_mangle] 206 | pub extern "system" fn Java_org_wasmer_Instance_nativeInitializeExportedMemories( 207 | env: JNIEnv, 208 | _class: JClass, 209 | instance_pointer: jptr, 210 | ) { 211 | let output = panic::catch_unwind(|| { 212 | let instance: &Instance = Into::>::into(instance_pointer).borrow(); 213 | 214 | memory::java::initialize_memories(&env, instance)?; 215 | 216 | Ok(()) 217 | }); 218 | 219 | joption_or_throw(&env, output).unwrap_or(()) 220 | } 221 | -------------------------------------------------------------------------------- /src/java/org/wasmer/Exports.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | import org.wasmer.exports.Export; 4 | import org.wasmer.exports.Function; 5 | 6 | import java.lang.ClassCastException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * `Exports` is a Java class that represents the set of WebAssembly exports. 12 | * 13 | * Example: 14 | *
{@code
15 |  * Instance instance = new Instance(wasmBytes);
16 |  *
17 |  * // Get and run an exported function.
18 |  * Object[] result = instance.exports.getFunction("sum").apply(1, 2);
19 |  *
20 |  * // Get, manually downcast, and run an exported function.
21 |  * Export sum = instance.exports.get("sum");
22 |  * Object[] result = ((Function) sum).apply(1, 2);
23 |  * }
24 | */ 25 | public class Exports { 26 | private Map inner; 27 | private Instance instance; 28 | 29 | /** 30 | * The constructor instantiates new exported functions. 31 | * 32 | * @param instance Instance object which holds the exports object. 33 | */ 34 | protected Exports(Instance instance) { 35 | this.inner = new HashMap(); 36 | this.instance = instance; 37 | } 38 | 39 | /** 40 | * Return the export with the name `name`. 41 | * 42 | * @param name Name of the export to return. 43 | */ 44 | public Export get(String name) { 45 | return this.inner.get(name); 46 | } 47 | 48 | /** 49 | * Return the export with the name `name` as an exported function. 50 | * 51 | * @param name Name of the exported function. 52 | */ 53 | public Function getFunction(String name) throws ClassCastException { 54 | return (Function) this.inner.get(name); 55 | } 56 | 57 | /** 58 | * Return the export with the name `name` as an exported memory. 59 | * 60 | * @param name Name of the exported memory. 61 | */ 62 | public Memory getMemory(String name) throws ClassCastException { 63 | return (Memory) this.inner.get(name); 64 | } 65 | 66 | /** 67 | * Called by Rust to add a new exported function. 68 | */ 69 | private void addFunction(String name) { 70 | this.inner.put(name, this.generateFunctionWrapper(name)); 71 | } 72 | 73 | /** 74 | * Called by Rust to add a new exported memory. 75 | */ 76 | private void addMemory(String name, Memory memory) { 77 | this.inner.put(name, memory); 78 | } 79 | 80 | /** 81 | * Lambda expression for currying. 82 | * This takes a function name and returns the function to call WebAssembly function. 83 | */ 84 | private java.util.function.Function functionWrapperGenerator = 85 | functionName -> arguments -> this.instance.nativeCallExportedFunction(this.instance.instancePointer, functionName, arguments); 86 | 87 | /** 88 | * Generate the exported function wrapper. 89 | */ 90 | private Function generateFunctionWrapper(String functionName) { 91 | return this.functionWrapperGenerator.apply(functionName); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/java/org/wasmer/Instance.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | /** 4 | * `Instance` is a Java class that represents a WebAssembly instance. 5 | * 6 | * Example: 7 | *
{@code
 8 |  * Instance instance = new Instance(wasmBytes);
 9 |  * }
10 | */ 11 | public class Instance { 12 | /** 13 | * Native bindings. 14 | */ 15 | static { 16 | if (!Native.LOADED_EMBEDDED_LIBRARY) { 17 | System.loadLibrary("wasmer_jni"); 18 | } 19 | } 20 | private native long nativeInstantiate(Instance self, byte[] moduleBytes) throws RuntimeException; 21 | private native void nativeDrop(long instancePointer); 22 | protected native Object[] nativeCallExportedFunction(long instancePointer, String exportName, Object[] arguments) throws RuntimeException; 23 | protected static native void nativeInitializeExportedFunctions(long instancePointer); 24 | protected static native void nativeInitializeExportedMemories(long instancePointer); 25 | 26 | /** 27 | * All WebAssembly exports. 28 | */ 29 | public final Exports exports; 30 | 31 | /** 32 | The instance pointer. 33 | */ 34 | protected long instancePointer; 35 | 36 | /** 37 | * The constructor instantiates a new WebAssembly instance based on 38 | * WebAssembly bytes. 39 | * 40 | * @param moduleBytes WebAssembly bytes. 41 | */ 42 | public Instance(byte[] moduleBytes) throws RuntimeException { 43 | this.exports = new Exports(this); 44 | 45 | long instancePointer = this.nativeInstantiate(this, moduleBytes); 46 | this.instancePointer = instancePointer; 47 | 48 | this.nativeInitializeExportedFunctions(instancePointer); 49 | this.nativeInitializeExportedMemories(instancePointer); 50 | } 51 | 52 | protected Instance() { 53 | this.exports = new Exports(this); 54 | } 55 | 56 | /** 57 | * Delete an instance object pointer. 58 | */ 59 | public void close() { 60 | if (this.instancePointer != 0L) { 61 | this.nativeDrop(this.instancePointer); 62 | this.instancePointer = 0L; 63 | } 64 | } 65 | 66 | /** 67 | * Delete an instance object pointer, which is called by the garbage collector 68 | * before an object is removed from the memory. 69 | */ 70 | public void finalize() { 71 | this.close(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/java/org/wasmer/Memory.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | import org.wasmer.exports.Export; 4 | import java.lang.IllegalArgumentException; 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.nio.BufferUnderflowException; 8 | import java.nio.BufferOverflowException; 9 | import java.nio.ReadOnlyBufferException; 10 | 11 | /** 12 | * `Memory` is a Java class that represents a WebAssembly memory. 13 | * 14 | * Example: 15 | *
{@code
16 |  * Instance instance = new Instance(wasmBytes);
17 |  * Memory memory = instance.exports.getMemory("memory-name");
18 |  * ByteBuffer memoryBuffer = memory.buffer();
19 |  *
20 |  * // Write bytes.
21 |  * memoryBuffer.position(0);
22 |  * memoryBuffer.put(new byte[]{1, 2, 3, 4, 5});
23 |  *
24 |  * // Read bytes.
25 |  * byte[] bytes = new byte[5];
26 |  * memoryBuffer.position(0);
27 |  * memoryBuffer.get(bytes);
28 |  * }
29 | */ 30 | public class Memory implements Export { 31 | private native void nativeMemoryView(Memory memory, long memoryPointer); 32 | private native int nativeMemoryGrow(Memory memory, long memoryPointer, int page); 33 | 34 | /** 35 | * Represents the actual WebAssembly memory data, borrowed from the runtime (in Rust). 36 | * The `setBuffer` method must be used to set this attribute. 37 | */ 38 | private ByteBuffer buffer; 39 | private long memoryPointer; 40 | 41 | private Memory() { 42 | // This object is instantiated by Rust. 43 | } 44 | 45 | /** 46 | * Return a _new_ direct byte buffer borrowing the memory data. 47 | * 48 | * @return A new direct byte buffer. 49 | */ 50 | public ByteBuffer buffer() { 51 | this.nativeMemoryView(this, this.memoryPointer); 52 | 53 | return this.buffer; 54 | } 55 | 56 | /** 57 | * Set the `ByteBuffer` of this memory. See `Memory.buffer` to learn more. 58 | * 59 | * In addition, this method correctly sets the endianess of the `ByteBuffer`. 60 | */ 61 | private void setBuffer(ByteBuffer buffer) { 62 | this.buffer = buffer; 63 | 64 | // Ensure the endianess matches WebAssemly specification. 65 | if (this.buffer.order() != ByteOrder.LITTLE_ENDIAN) { 66 | this.buffer.order(ByteOrder.LITTLE_ENDIAN); 67 | } 68 | } 69 | 70 | /** 71 | * Grow this memory by the specified number of pages. 72 | * 73 | * @param page The number of pages to grow. 1 page size is 64KiB. 74 | * @return The previous number of pages. 75 | */ 76 | public int grow(int page) { 77 | return this.nativeMemoryGrow(this, this.memoryPointer, page); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/java/org/wasmer/Module.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | /** 4 | * `Module` is a Java class that represents a WebAssembly module. 5 | * 6 | * Example: 7 | *
{@code
  8 |  * boolean isValid = Module.validate(wasmBytes);
  9 |  *
 10 |  * Module module = new Module(wasmBytes);
 11 |  * Instance instance = module.instantiate();
 12 |  * }
13 | */ 14 | public class Module { 15 | /** 16 | * Native bindings. 17 | */ 18 | static { 19 | if (!Native.LOADED_EMBEDDED_LIBRARY) { 20 | System.loadLibrary("wasmer_jni"); 21 | } 22 | } 23 | private native long nativeModuleInstantiate(Module self, byte[] moduleBytes) throws RuntimeException; 24 | private native void nativeDrop(long modulePointer); 25 | private native long nativeInstantiate(long modulePointer, Instance instance); 26 | private static native boolean nativeValidate(byte[] moduleBytes); 27 | private native byte[] nativeSerialize(long modulePointer); 28 | private static native long nativeDeserialize(Module module, byte[] serializedBytes); 29 | 30 | private long modulePointer; 31 | 32 | 33 | /** 34 | * Check that given bytes represent a valid WebAssembly module. 35 | * 36 | * @param moduleBytes WebAssembly bytes. 37 | * @return true if, and only if, given bytes are valid as a WebAssembly module. 38 | */ 39 | public static boolean validate(byte[] moduleBytes) { 40 | return Module.nativeValidate(moduleBytes); 41 | } 42 | 43 | /** 44 | * The constructor instantiates a new WebAssembly module based on 45 | * WebAssembly bytes. 46 | * 47 | * @param moduleBytes WebAssembly bytes. 48 | */ 49 | public Module(byte[] moduleBytes) throws RuntimeException { 50 | long modulePointer = this.nativeModuleInstantiate(this, moduleBytes); 51 | this.modulePointer = modulePointer; 52 | } 53 | 54 | private Module() {} 55 | 56 | /** 57 | * Delete a module object pointer. 58 | */ 59 | public void close() { 60 | if (this.modulePointer != 0L) { 61 | this.nativeDrop(this.modulePointer); 62 | this.modulePointer = 0L; 63 | } 64 | } 65 | 66 | /** 67 | * Delete a module object pointer, which is called by the garbage collector 68 | * before an object is removed from the memory. 69 | */ 70 | public void finalize() { 71 | this.close(); 72 | } 73 | 74 | /** 75 | * Create an instance object based on a module object. 76 | * 77 | * @return Instance object. 78 | */ 79 | public Instance instantiate() { 80 | Instance instance = new Instance(); 81 | long instancePointer = this.nativeInstantiate(this.modulePointer, instance); 82 | instance.instancePointer = instancePointer; 83 | 84 | instance.nativeInitializeExportedFunctions(instancePointer); 85 | instance.nativeInitializeExportedMemories(instancePointer); 86 | return instance; 87 | } 88 | 89 | /** 90 | * Create a serialized byte array from a WebAssembly module. 91 | * 92 | * @return Serialized bytes. 93 | */ 94 | public byte[] serialize() { 95 | return this.nativeSerialize(this.modulePointer); 96 | } 97 | 98 | /** 99 | * Create an original Module object from a byte array. 100 | * 101 | * @return Module object. 102 | */ 103 | public static Module deserialize(byte[] serializedBytes) { 104 | Module module = new Module(); 105 | long modulePointer = Module.nativeDeserialize(module, serializedBytes); 106 | module.modulePointer = modulePointer; 107 | return module; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/java/org/wasmer/Native.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Code reduced and simplified from zmq integration in Java. See 3 | * https://github.com/zeromq/jzmq/blob/3384ea1c04876426215fe76b5d1aabc58c099ca0/jzmq-jni/src/main/java/org/zeromq/EmbeddedLibraryTools.java. 4 | */ 5 | 6 | package org.wasmer; 7 | 8 | import java.io.*; 9 | import java.net.URL; 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.Enumeration; 13 | import java.util.List; 14 | import java.util.jar.JarEntry; 15 | import java.util.jar.JarFile; 16 | 17 | public class Native { 18 | public static final boolean LOADED_EMBEDDED_LIBRARY; 19 | 20 | static { 21 | LOADED_EMBEDDED_LIBRARY = loadEmbeddedLibrary(); 22 | } 23 | 24 | private Native() {} 25 | 26 | public static String getCurrentPlatformIdentifier() { 27 | String osName = System.getProperty("os.name").toLowerCase(); 28 | 29 | if (osName.contains("windows")) { 30 | osName = "windows"; 31 | } else if (osName.contains("mac os x")) { 32 | osName = "darwin"; 33 | } else { 34 | osName = osName.replaceAll("\\s+", "_"); 35 | } 36 | 37 | return osName + "-" + System.getProperty("os.arch"); 38 | } 39 | 40 | private static boolean loadEmbeddedLibrary() { 41 | boolean usingEmbedded = false; 42 | 43 | // attempt to locate embedded native library within JAR at following location: 44 | // /NATIVE/${os.arch}/${os.name}/[libwasmer.so|libwasmer.dylib|wasmer.dll] 45 | String[] libs; 46 | final String libsFromProps = System.getProperty("wasmer-native"); 47 | 48 | if (libsFromProps == null) { 49 | libs = new String[]{"libwasmer_jni.so", "libwasmer_jni.dylib", "wasmer_jni.dll"}; 50 | } else { 51 | libs = libsFromProps.split(","); 52 | } 53 | 54 | StringBuilder url = new StringBuilder(); 55 | url.append("/org/wasmer/native/"); 56 | url.append(getCurrentPlatformIdentifier()).append("/"); 57 | 58 | URL nativeLibraryUrl = null; 59 | 60 | // loop through extensions, stopping after finding first one 61 | for (String lib: libs) { 62 | nativeLibraryUrl = Module.class.getResource(url.toString() + lib); 63 | 64 | if (nativeLibraryUrl != null) { 65 | break; 66 | } 67 | } 68 | 69 | if (nativeLibraryUrl != null) { 70 | // native library found within JAR, extract and load 71 | try { 72 | final File libfile = File.createTempFile("wasmer_jni", ".lib"); 73 | libfile.deleteOnExit(); // just in case 74 | 75 | final InputStream in = nativeLibraryUrl.openStream(); 76 | final OutputStream out = new BufferedOutputStream(new FileOutputStream(libfile)); 77 | 78 | int len = 0; 79 | byte[] buffer = new byte[8192]; 80 | 81 | while ((len = in.read(buffer)) > -1) { 82 | out.write(buffer, 0, len); 83 | } 84 | 85 | out.close(); 86 | in.close(); 87 | System.load(libfile.getAbsolutePath()); 88 | 89 | usingEmbedded = true; 90 | } catch (IOException x) { 91 | // mission failed, do nothing 92 | } 93 | 94 | } 95 | 96 | return usingEmbedded; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/java/org/wasmer/exports/Export.java: -------------------------------------------------------------------------------- 1 | package org.wasmer.exports; 2 | 3 | /** 4 | * Represent a WebAssembly instance export. It could be a function, a 5 | * memory etc. 6 | */ 7 | public interface Export {} 8 | -------------------------------------------------------------------------------- /src/java/org/wasmer/exports/Function.java: -------------------------------------------------------------------------------- 1 | package org.wasmer.exports; 2 | 3 | import org.wasmer.exports.Export; 4 | 5 | /** 6 | * Functional interface for WebAssembly exported functions, i.e. it 7 | * creates a new type for a closure that mimics a WebAssembly exported 8 | * function. 9 | * 10 | * The apply method takes an arbitrary number of arguments and returns 11 | * an output. 12 | */ 13 | @FunctionalInterface 14 | public interface Function extends Export { 15 | @SuppressWarnings("unchecked") 16 | public Object[] apply(Object... inputs); 17 | } 18 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod exception; 2 | mod instance; 3 | mod memory; 4 | mod module; 5 | mod types; 6 | mod value; 7 | -------------------------------------------------------------------------------- /src/memory.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | exception::{joption_or_throw, runtime_error, Error}, 3 | types::{jptr, Pointer}, 4 | }; 5 | use jni::{ 6 | objects::{JClass, JObject}, 7 | sys::jint, 8 | JNIEnv, 9 | }; 10 | use std::{cell::Cell, panic, rc::Rc, slice}; 11 | use wasmer_runtime::memory::MemoryView; 12 | use wasmer_runtime::units::Pages; 13 | use wasmer::Memory as WasmMemory; 14 | 15 | #[derive(Clone)] 16 | pub struct Memory { 17 | pub memory: Rc, 18 | } 19 | 20 | impl Memory { 21 | pub fn new(memory: Rc) -> Self { 22 | Self { memory } 23 | } 24 | 25 | pub fn grow(&self, number_of_pages: u32) -> Result { 26 | self.memory 27 | .grow(Pages(number_of_pages)) 28 | .map(|previous_pages| previous_pages.0) 29 | .map_err(|e| runtime_error(format!("Failed to grow the memory: {}", e))) 30 | } 31 | } 32 | 33 | #[no_mangle] 34 | pub extern "system" fn Java_org_wasmer_Memory_nativeMemoryView( 35 | env: JNIEnv, 36 | _class: JClass, 37 | memory_object: JObject, 38 | memory_pointer: jptr, 39 | ) { 40 | let output = panic::catch_unwind(|| { 41 | let memory: &Memory = Into::>::into(memory_pointer).borrow(); 42 | let view: MemoryView = memory.memory.view(); 43 | let data = unsafe { 44 | slice::from_raw_parts_mut(view[..].as_ptr() as *mut Cell as *mut u8, view.len()) 45 | }; 46 | 47 | // Create a new `JByteBuffer`, aka `java.nio.ByteBuffer`, 48 | // borrowing the data from the WebAssembly memory. 49 | let byte_buffer = env.new_direct_byte_buffer(data)?; 50 | 51 | // Try to rewrite the `org.wasmer.Memory.buffer` attribute by 52 | // calling the `org.wasmer.Memory.setBuffer` method. 53 | env.call_method( 54 | memory_object, 55 | "setBuffer", 56 | "(Ljava/nio/ByteBuffer;)V", 57 | &[JObject::from(byte_buffer).into()], 58 | )?; 59 | 60 | Ok(()) 61 | }); 62 | 63 | joption_or_throw(&env, output); 64 | } 65 | 66 | #[no_mangle] 67 | pub extern "system" fn Java_org_wasmer_Memory_nativeMemoryGrow( 68 | env: JNIEnv, 69 | _class: JClass, 70 | memory_object: JObject, 71 | memory_pointer: jptr, 72 | number_of_pages: jint, 73 | ) -> jint { 74 | let output = panic::catch_unwind(|| { 75 | let memory: &Memory = Into::>::into(memory_pointer).borrow(); 76 | let old_pages = memory.grow(number_of_pages as u32)?; 77 | 78 | let view: MemoryView = memory.memory.view(); 79 | let data = unsafe { 80 | std::slice::from_raw_parts_mut( 81 | view[..].as_ptr() as *mut Cell as *mut u8, 82 | view.len(), 83 | ) 84 | }; 85 | // Create a new `JByteBuffer`, aka `java.nio.ByteBuffer`, 86 | // borrowing the data from the WebAssembly memory. 87 | let byte_buffer = env.new_direct_byte_buffer(data)?; 88 | 89 | // Try to rewrite the `org.wasmer.Memory.buffer` attribute by 90 | // calling the `org.wasmer.Memory.setBuffer` method. 91 | env.call_method( 92 | memory_object, 93 | "setBuffer", 94 | "(Ljava/nio/ByteBuffer;)V", 95 | &[JObject::from(byte_buffer).into()], 96 | )?; 97 | 98 | Ok(old_pages as i32) 99 | }); 100 | 101 | joption_or_throw(&env, output).unwrap_or(0) 102 | } 103 | 104 | pub mod java { 105 | use crate::{ 106 | exception::Error, 107 | instance::Instance, 108 | types::{jptr, Pointer}, 109 | }; 110 | use jni::{objects::JObject, JNIEnv}; 111 | 112 | pub fn initialize_memories(env: &JNIEnv, instance: &Instance) -> Result<(), Error> { 113 | let exports_object: JObject = env 114 | .get_field( 115 | instance.java_instance_object.as_obj(), 116 | "exports", 117 | "Lorg/wasmer/Exports;", 118 | )? 119 | .l()?; 120 | 121 | // Get the `org.wasmer.Memory` class. 122 | let memory_class = env.find_class("org/wasmer/Memory")?; 123 | 124 | for (memory_name, memory) in &instance.memories { 125 | // Instantiate the `Memory` class. 126 | let memory_object = env.new_object(memory_class, "()V", &[])?; 127 | 128 | // Try to set the memory pointer to the field `org.wasmer.Memory.memoryPointer`. 129 | let memory_pointer: jptr = Pointer::new(memory.clone()).into(); 130 | env.set_field(memory_object, "memoryPointer", "J", memory_pointer.into())?; 131 | 132 | // Add the newly created `org.wasmer.Memory` in the 133 | // `org.wasmer.Exports` collection. 134 | env.call_method( 135 | exports_object, 136 | "addMemory", 137 | "(Ljava/lang/String;Lorg/wasmer/Memory;)V", 138 | &[ 139 | JObject::from(env.new_string(memory_name)?).into(), 140 | memory_object.into(), 141 | ], 142 | )?; 143 | } 144 | 145 | Ok(()) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | exception::{joption_or_throw, runtime_error, Error}, 3 | instance::Instance, 4 | memory::Memory, 5 | types::{jptr, Pointer}, 6 | }; 7 | use jni::{ 8 | objects::{GlobalRef, JClass, JObject}, 9 | sys::{jboolean, jbyteArray}, 10 | JNIEnv, 11 | }; 12 | use std::{collections::HashMap, panic, rc::Rc}; 13 | use wasmer_runtime::{self as runtime, validate, Export}; 14 | use wasmer_runtime::{cache::Artifact, imports, load_cache_with}; 15 | 16 | pub struct Module { 17 | #[allow(unused)] 18 | java_module_object: GlobalRef, 19 | module: runtime::Module, 20 | } 21 | 22 | impl Module { 23 | fn new(java_module_object: GlobalRef, module_bytes: Vec) -> Result { 24 | let module_bytes = module_bytes.as_slice(); 25 | let module = runtime::compile(module_bytes) 26 | .map_err(|e| runtime_error(format!("Failed to compile the module: {}", e)))?; 27 | 28 | Ok(Self { 29 | java_module_object, 30 | module, 31 | }) 32 | } 33 | 34 | fn serialize(&self) -> Result, Error> { 35 | match self.module.cache() { 36 | Ok(artifact) => match artifact.serialize() { 37 | Ok(serialized_artifact) => Ok(serialized_artifact), 38 | Err(_) => { 39 | return Err(runtime_error(format!( 40 | "Failed to serialize the module artifact." 41 | ))) 42 | } 43 | }, 44 | Err(_) => return Err(runtime_error(format!("Failed to get the module artifact."))), 45 | } 46 | } 47 | 48 | fn deserialize( 49 | java_module_object: GlobalRef, 50 | serialized_module: Vec, 51 | ) -> Result { 52 | let module = match unsafe { Artifact::deserialize(serialized_module.as_slice()) } { 53 | Ok(artifact) => { 54 | match load_cache_with(artifact) { 55 | Ok(module) => module, 56 | Err(_) => { 57 | return Err(runtime_error(format!( 58 | "Failed to compile the serialized module." 59 | ))) 60 | } 61 | } 62 | } 63 | Err(_) => return Err(runtime_error(format!("Failed to deserialize the module."))), 64 | }; 65 | 66 | Ok(Self { 67 | java_module_object, 68 | module, 69 | }) 70 | } 71 | } 72 | 73 | #[no_mangle] 74 | pub extern "system" fn Java_org_wasmer_Module_nativeModuleInstantiate( 75 | env: JNIEnv, 76 | _class: JClass, 77 | this: JObject, 78 | module_bytes: jbyteArray, 79 | ) -> jptr { 80 | let output = panic::catch_unwind(|| { 81 | let module_bytes = env.convert_byte_array(module_bytes)?; 82 | let java_module = env.new_global_ref(this)?; 83 | 84 | let module = Module::new(java_module, module_bytes)?; 85 | 86 | Ok(Pointer::new(module).into()) 87 | }); 88 | 89 | joption_or_throw(&env, output).unwrap_or(0) 90 | } 91 | 92 | #[no_mangle] 93 | pub extern "system" fn Java_org_wasmer_Module_nativeDrop( 94 | _env: JNIEnv, 95 | _class: JClass, 96 | module_pointer: jptr, 97 | ) { 98 | let _: Pointer = module_pointer.into(); 99 | } 100 | 101 | #[no_mangle] 102 | pub extern "system" fn Java_org_wasmer_Module_nativeInstantiate( 103 | env: JNIEnv, 104 | _class: JClass, 105 | module_pointer: jptr, 106 | instance_object: JObject, 107 | ) -> jptr { 108 | let output = panic::catch_unwind(|| { 109 | let java_instance_object = env.new_global_ref(instance_object)?; 110 | 111 | let module: &Module = Into::>::into(module_pointer).borrow(); 112 | let import_object = imports! {}; 113 | let instance = module.module.instantiate(&import_object).map_err(|e| { 114 | runtime_error(format!("Failed to instantiate a WebAssembly module: {}", e)) 115 | })?; 116 | 117 | let memories: HashMap = instance 118 | .exports() 119 | .filter_map(|(export_name, export)| match export { 120 | Export::Memory(memory) => Some((export_name.to_string(), Memory::new(Rc::new(memory.clone())))), 121 | _ => None, 122 | }) 123 | .collect(); 124 | 125 | Ok(Pointer::new(Instance { 126 | java_instance_object, 127 | instance: Rc::new(instance), 128 | memories, 129 | }) 130 | .into()) 131 | }); 132 | 133 | joption_or_throw(&env, output).unwrap_or(0) 134 | } 135 | 136 | #[no_mangle] 137 | pub extern "system" fn Java_org_wasmer_Module_nativeValidate( 138 | env: JNIEnv, 139 | _class: JClass, 140 | module_bytes: jbyteArray, 141 | ) -> jboolean { 142 | let output = panic::catch_unwind(|| { 143 | let module_bytes = env.convert_byte_array(module_bytes)?; 144 | match validate(module_bytes.as_slice()) { 145 | true => Ok(1), 146 | false => Ok(0), 147 | } 148 | }); 149 | 150 | joption_or_throw(&env, output).unwrap_or(0) 151 | } 152 | 153 | #[no_mangle] 154 | pub extern "system" fn Java_org_wasmer_Module_nativeSerialize( 155 | env: JNIEnv, 156 | _class: JClass, 157 | module_pointer: jptr, 158 | ) -> jbyteArray { 159 | let output = panic::catch_unwind(|| { 160 | let module: &Module = Into::>::into(module_pointer).borrow(); 161 | let serialized_module = module.serialize()?; 162 | let java_serialized_module = env.byte_array_from_slice(serialized_module.as_slice())?; 163 | Ok(java_serialized_module) 164 | }); 165 | 166 | joption_or_throw(&env, output).unwrap_or(JObject::null().into_inner()) 167 | } 168 | 169 | #[no_mangle] 170 | pub extern "system" fn Java_org_wasmer_Module_nativeDeserialize( 171 | env: JNIEnv, 172 | _class: JClass, 173 | java_module: JObject, 174 | java_serialized_module: jbyteArray, 175 | ) -> jptr { 176 | let output = panic::catch_unwind(|| { 177 | let java_module_object = env.new_global_ref(java_module)?; 178 | let serialized_module = env.convert_byte_array(java_serialized_module)?; 179 | let module = Module::deserialize(java_module_object, serialized_module)?; 180 | Ok(Pointer::new(module).into()) 181 | }); 182 | 183 | joption_or_throw(&env, output).unwrap_or(0) 184 | } 185 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use jni::sys::jlong; 2 | use std::ops::Deref; 3 | 4 | #[allow(non_camel_case_types)] 5 | pub type jptr = jlong; 6 | 7 | #[derive(Debug)] 8 | pub struct Pointer { 9 | value: Box, 10 | } 11 | 12 | impl Pointer { 13 | pub fn new(value: Kind) -> Self { 14 | Pointer { 15 | value: Box::new(value), 16 | } 17 | } 18 | 19 | pub fn borrow<'a>(self) -> &'a mut Kind { 20 | Box::leak(self.value) 21 | } 22 | } 23 | 24 | impl From> for jptr { 25 | fn from(pointer: Pointer) -> Self { 26 | Box::into_raw(pointer.value) as _ 27 | } 28 | } 29 | 30 | impl From for Pointer { 31 | fn from(pointer: jptr) -> Self { 32 | Self { 33 | value: unsafe { Box::from_raw(pointer as *mut Kind) }, 34 | } 35 | } 36 | } 37 | 38 | impl Deref for Pointer { 39 | type Target = Kind; 40 | 41 | fn deref(&self) -> &Self::Target { 42 | &self.value 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/value.rs: -------------------------------------------------------------------------------- 1 | use crate::exception::{runtime_error, Error}; 2 | use jni::{errors::ErrorKind, objects::JObject, JNIEnv}; 3 | use std::convert::TryFrom; 4 | use wasmer_runtime::Value as WasmValue; 5 | 6 | /// Value wrapping the real WebAssembly value. 7 | pub struct Value(WasmValue); 8 | 9 | impl Value { 10 | pub fn inner(self) -> WasmValue { 11 | self.0 12 | } 13 | } 14 | 15 | pub const INT_CLASS: &str = "java/lang/Integer"; 16 | pub const LONG_CLASS: &str = "java/lang/Long"; 17 | pub const FLOAT_CLASS: &str = "java/lang/Float"; 18 | pub const DOUBLE_CLASS: &str = "java/lang/Double"; 19 | 20 | impl TryFrom<(&JNIEnv<'_>, JObject<'_>)> for Value { 21 | type Error = Error; 22 | 23 | fn try_from((env, jobject): (&JNIEnv, JObject)) -> Result { 24 | if jobject.is_null() { 25 | return Err(ErrorKind::NullPtr("`try_from` receives a null object").into()); 26 | } 27 | 28 | Ok(Value( 29 | if env.is_instance_of(jobject, INT_CLASS).unwrap_or(false) { 30 | WasmValue::I32(env.call_method(jobject, "intValue", "()I", &[])?.i()?) 31 | } else if env.is_instance_of(jobject, LONG_CLASS).unwrap_or(false) { 32 | WasmValue::I64(env.call_method(jobject, "longValue", "()J", &[])?.j()?) 33 | } else if env.is_instance_of(jobject, FLOAT_CLASS).unwrap_or(false) { 34 | WasmValue::F32(env.call_method(jobject, "floatValue", "()F", &[])?.f()?) 35 | } else if env.is_instance_of(jobject, DOUBLE_CLASS).unwrap_or(false) { 36 | WasmValue::F64(env.call_method(jobject, "doubleValue", "()D", &[])?.d()?) 37 | } else { 38 | return Err(runtime_error(format!( 39 | "Could not convert argument {:?} to a WebAssembly value.", 40 | jobject 41 | ))); 42 | }, 43 | )) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/java/org/wasmer/InstanceTest.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | import org.wasmer.exports.Function; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertNull; 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | import java.io.IOException; 10 | import java.net.URL; 11 | import java.nio.ByteBuffer; 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.nio.file.Paths; 15 | import org.junit.jupiter.api.Test; 16 | 17 | class InstanceTest { 18 | private byte[] getBytes() throws IOException,Exception { 19 | URL url = getClass().getClassLoader().getResource("tests.wasm"); 20 | Path modulePath = Paths.get(url.toURI()); 21 | return Files.readAllBytes(modulePath); 22 | } 23 | 24 | @Test 25 | void sum() throws IOException,Exception { 26 | Instance instance = new Instance(getBytes()); 27 | Function sum = instance.exports.getFunction("sum"); 28 | 29 | assertEquals(3, sum.apply(1, 2)[0]); 30 | 31 | instance.close(); 32 | } 33 | 34 | @Test 35 | void arity_0() throws IOException,Exception { 36 | Instance instance = new Instance(getBytes()); 37 | 38 | assertEquals(42, (Integer) instance.exports.getFunction("arity_0").apply()[0]); 39 | 40 | instance.close(); 41 | } 42 | 43 | @Test 44 | void i32_i32() throws IOException,Exception { 45 | Instance instance = new Instance(getBytes()); 46 | 47 | assertEquals(42, (Integer) instance.exports.getFunction("i32_i32").apply(42)[0]); 48 | 49 | instance.close(); 50 | } 51 | 52 | @Test 53 | void i64_i64() throws IOException,Exception { 54 | Instance instance = new Instance(getBytes()); 55 | 56 | assertEquals(42l, (Long) instance.exports.getFunction("i64_i64").apply(42l)[0]); 57 | 58 | instance.close(); 59 | } 60 | 61 | @Test 62 | void f32_f32() throws IOException,Exception { 63 | Instance instance = new Instance(getBytes()); 64 | 65 | assertEquals(42.0f, (Float) instance.exports.getFunction("f32_f32").apply(42.0f)[0]); 66 | 67 | instance.close(); 68 | } 69 | 70 | @Test 71 | void f64_f64() throws IOException,Exception { 72 | Instance instance = new Instance(getBytes()); 73 | 74 | assertEquals(42.0d, (Double) instance.exports.getFunction("f64_f64").apply(42.0d)[0]); 75 | 76 | instance.close(); 77 | } 78 | 79 | @Test 80 | void i32_i64_f32_f64_f64() throws IOException,Exception { 81 | Instance instance = new Instance(getBytes()); 82 | 83 | assertEquals(10.0d, (Double) instance.exports.getFunction("i32_i64_f32_f64_f64").apply(1, 2l, 3.0f, 4.0d)[0]); 84 | 85 | instance.close(); 86 | } 87 | 88 | @Test 89 | void bool_casted_to_i32() throws IOException,Exception { 90 | Instance instance = new Instance(getBytes()); 91 | 92 | assertTrue((Integer) instance.exports.getFunction("bool_casted_to_i32").apply()[0] == 1); 93 | 94 | instance.close(); 95 | } 96 | 97 | @Test 98 | void string() throws IOException,Exception { 99 | Instance instance = new Instance(getBytes()); 100 | Memory memory = instance.exports.getMemory("memory"); 101 | ByteBuffer memoryBuffer = memory.buffer(); 102 | 103 | int pointer = (Integer) instance.exports.getFunction("string").apply()[0]; 104 | 105 | byte[] stringBytes = new byte[13]; 106 | memoryBuffer.position(pointer); 107 | memoryBuffer.get(stringBytes); 108 | 109 | String expected = "Hello, World!"; 110 | assertEquals(expected, new String(stringBytes)); 111 | 112 | instance.close(); 113 | } 114 | 115 | @Test 116 | void nothing() throws IOException,Exception { 117 | Instance instance = new Instance(getBytes()); 118 | 119 | assertNull(instance.exports.getFunction("void").apply()); 120 | 121 | instance.close(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /tests/java/org/wasmer/MemoryTest.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | import static org.junit.jupiter.api.Assertions.assertNull; 7 | 8 | import java.io.IOException; 9 | import java.lang.IllegalArgumentException; 10 | import java.nio.BufferOverflowException; 11 | import java.nio.BufferUnderflowException; 12 | import java.nio.ByteBuffer; 13 | import java.nio.ReadOnlyBufferException; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import org.junit.jupiter.api.Assertions; 18 | import org.junit.jupiter.api.Test; 19 | import org.junit.jupiter.api.Disabled; 20 | 21 | class MemoryTest { 22 | private byte[] getBytes(String filename) throws IOException,Exception { 23 | Path modulePath = Paths.get(getClass().getClassLoader().getResource(filename).toURI()); 24 | return Files.readAllBytes(modulePath); 25 | } 26 | 27 | @Test 28 | void size() throws IOException,Exception { 29 | Instance instance = new Instance(getBytes("tests.wasm")); 30 | Memory memory = instance.exports.getMemory("memory"); 31 | 32 | assertEquals(1114112, memory.buffer().limit()); 33 | 34 | instance.close(); 35 | } 36 | 37 | @Test 38 | void readStaticallyAllocatedDataInMemory() throws IOException, Exception { 39 | Instance instance = new Instance(getBytes("tests.wasm")); 40 | 41 | byte[] expectedData = "Hello, World!".getBytes(); 42 | 43 | int pointer = (Integer) instance.exports.getFunction("string").apply()[0]; 44 | Memory memory = instance.exports.getMemory("memory"); 45 | ByteBuffer memoryBuffer = memory.buffer(); 46 | 47 | byte[] readData = new byte[expectedData.length]; 48 | memoryBuffer.position(pointer); 49 | memoryBuffer.get(readData); 50 | 51 | assertArrayEquals(expectedData, readData); 52 | 53 | instance.close(); 54 | } 55 | 56 | @Test 57 | void readMemory() throws IOException,Exception { 58 | Instance instance = new Instance(getBytes("tests.wasm")); 59 | 60 | Memory memory = instance.exports.getMemory("memory"); 61 | ByteBuffer memoryBuffer = memory.buffer(); 62 | 63 | byte[] readData = new byte[5]; 64 | memoryBuffer.get(readData); 65 | 66 | assertArrayEquals(new byte[]{0, 0, 0, 0, 0}, readData); 67 | 68 | instance.close(); 69 | } 70 | 71 | @Test 72 | void writeMemory() throws IOException,Exception { 73 | Instance instance = new Instance(getBytes("tests.wasm")); 74 | 75 | Memory memory = instance.exports.getMemory("memory"); 76 | ByteBuffer memoryBuffer = memory.buffer(); 77 | 78 | byte[] writtenData = new byte[]{1, 2, 3, 4, 5}; 79 | memoryBuffer.put(writtenData); 80 | 81 | byte[] readData = new byte[5]; 82 | memoryBuffer.position(0); 83 | memoryBuffer.get(readData); 84 | 85 | assertArrayEquals(writtenData, readData); 86 | 87 | ByteBuffer memoryBuffer2 = memory.buffer(); 88 | byte[] readData2 = new byte[5]; 89 | memoryBuffer2.get(readData2); 90 | 91 | assertArrayEquals(writtenData, readData2); 92 | 93 | instance.close(); 94 | } 95 | 96 | @Test 97 | void noMemory() throws IOException,Exception { 98 | Instance instance = new Instance(getBytes("no_memory.wasm")); 99 | Memory memory = instance.exports.getMemory("memory"); 100 | 101 | assertNull(memory); 102 | 103 | instance.close(); 104 | } 105 | 106 | @Test 107 | void javaBorrowsRustMemory() throws IOException,Exception { 108 | Instance instance = new Instance(getBytes("tests.wasm")); 109 | 110 | { 111 | Memory memory = instance.exports.getMemory("memory"); 112 | ByteBuffer memoryBuffer = memory.buffer(); 113 | 114 | int pointer = (Integer) instance.exports.getFunction("string").apply()[0]; 115 | byte[] data = new byte[13]; 116 | memoryBuffer.position(pointer); 117 | memoryBuffer.get(data); 118 | 119 | assertEquals("Hello, World!", new String(data)); 120 | 121 | memoryBuffer.position(pointer); 122 | memoryBuffer.put(new byte[]{'A'}); 123 | } 124 | 125 | { 126 | Memory memory = instance.exports.getMemory("memory"); 127 | ByteBuffer memoryBuffer = memory.buffer(); 128 | 129 | int pointer = (Integer) instance.exports.getFunction("string").apply()[0]; 130 | byte[] data = new byte[13]; 131 | memoryBuffer.position(pointer); 132 | memoryBuffer.get(data); 133 | 134 | assertEquals("Aello, World!", new String(data)); 135 | } 136 | 137 | instance.close(); 138 | } 139 | 140 | @Test 141 | void memoryGrow() throws IOException,Exception { 142 | Instance instance = new Instance(getBytes("tests.wasm")); 143 | Memory memory = instance.exports.getMemory("memory"); 144 | 145 | int oldSize = memory.buffer().limit(); 146 | assertEquals(1114112, oldSize); 147 | 148 | memory.grow(1); 149 | 150 | int newSize = memory.buffer().limit(); 151 | assertEquals(1179648, newSize); 152 | assertEquals(65536, newSize - oldSize); 153 | 154 | instance.close(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/java/org/wasmer/ModuleTest.java: -------------------------------------------------------------------------------- 1 | package org.wasmer; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | 7 | import java.lang.RuntimeException; 8 | import java.io.IOException; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.Test; 14 | 15 | class ModuleTest { 16 | private byte[] getBytes(String filename) throws IOException,Exception { 17 | Path modulePath = Paths.get(getClass().getClassLoader().getResource(filename).toURI()); 18 | return Files.readAllBytes(modulePath); 19 | } 20 | 21 | @Test 22 | void validate() throws IOException,Exception { 23 | assertTrue(Module.validate(getBytes("tests.wasm"))); 24 | } 25 | 26 | @Test 27 | void invalidate() throws IOException,Exception { 28 | assertFalse(Module.validate(getBytes("invalid.wasm"))); 29 | } 30 | 31 | @Test 32 | void compile() throws IOException,Exception { 33 | assertTrue(new Module(getBytes("tests.wasm")) instanceof Module); 34 | } 35 | 36 | @Test 37 | void failedToCompile() throws IOException,Exception { 38 | Exception exception = Assertions.assertThrows(RuntimeException.class, () -> { 39 | Module module = new Module(getBytes("invalid.wasm")); 40 | }); 41 | 42 | String expected = "Failed to compile the module: Validation error: invalid leading byte in type definition"; 43 | assertTrue(exception.getMessage().startsWith(expected)); 44 | } 45 | 46 | @Test 47 | void instantiate() throws IOException,Exception { 48 | Module module = new Module(getBytes("tests.wasm")); 49 | 50 | Instance instance = module.instantiate(); 51 | assertEquals(3, (Integer) instance.exports.getFunction("sum").apply(1, 2)[0]); 52 | 53 | instance.close(); 54 | module.close(); 55 | } 56 | 57 | @Test 58 | void serialize() throws IOException,Exception { 59 | Module module = new Module(getBytes("tests.wasm")); 60 | assertTrue(module.serialize() instanceof byte[]); 61 | module.close(); 62 | } 63 | 64 | @Test 65 | void deserialize() throws IOException,Exception { 66 | Module module = new Module(getBytes("tests.wasm")); 67 | 68 | byte[] serialized = module.serialize(); 69 | module = null; 70 | 71 | Module deserializedModule = Module.deserialize(serialized); 72 | assertEquals(3, (Integer) deserializedModule.instantiate().exports.getFunction("sum").apply(1, 2)[0]); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/resources/invalid.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/tests/resources/invalid.wasm -------------------------------------------------------------------------------- /tests/resources/no_memory.wasm: -------------------------------------------------------------------------------- 1 | asm` hello 2 | A* -------------------------------------------------------------------------------- /tests/resources/no_memory.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $hello_wasm_type (func (result i32))) 3 | 4 | (func $hello (type $hello_wasm_type) (result i32) 5 | i32.const 42) 6 | 7 | (export "hello" (func $hello))) -------------------------------------------------------------------------------- /tests/resources/simple.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern fn sum(x: i32, y: i32) -> i32 { 3 | x + y 4 | } 5 | -------------------------------------------------------------------------------- /tests/resources/simple.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/tests/resources/simple.wasm -------------------------------------------------------------------------------- /tests/resources/tests.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern fn sum(x: i32, y: i32) -> i32 { 3 | x + y 4 | } 5 | 6 | #[no_mangle] 7 | pub extern fn arity_0() -> i32 { 8 | 42 9 | } 10 | 11 | #[no_mangle] 12 | pub extern fn i32_i32(x: i32) -> i32 { 13 | x 14 | } 15 | 16 | #[no_mangle] 17 | pub extern fn i64_i64(x: i64) -> i64 { 18 | x 19 | } 20 | 21 | #[no_mangle] 22 | pub extern fn f32_f32(x: f32) -> f32 { 23 | x 24 | } 25 | 26 | #[no_mangle] 27 | pub extern fn f64_f64(x: f64) -> f64 { 28 | x 29 | } 30 | 31 | #[no_mangle] 32 | pub extern fn i32_i64_f32_f64_f64(a: i32, b: i64, c: f32, d: f64) -> f64 { 33 | a as f64 + b as f64 + c as f64 + d 34 | } 35 | 36 | #[no_mangle] 37 | pub extern fn bool_casted_to_i32() -> bool { 38 | true 39 | } 40 | 41 | #[no_mangle] 42 | pub extern fn string() -> *const u8 { 43 | b"Hello, World!\0".as_ptr() 44 | } 45 | 46 | #[no_mangle] 47 | pub extern fn void() {} 48 | -------------------------------------------------------------------------------- /tests/resources/tests.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasmerio/wasmer-java/cbd3ac5b3de83b5abab12361614ea982f6a30d79/tests/resources/tests.wasm --------------------------------------------------------------------------------