272 Commits

Author SHA1 Message Date
dependabot[bot] 0b222d76fd Update wasmparser requirement from 0.205 to 0.206 (#103)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-30 16:29:41 +02:00
dependabot[bot] 2e29897786 Update wasmparser requirement from 0.204 to 0.205 (#101)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 15:34:49 +02:00
dependabot[bot] b974199ad5 Update wasmparser requirement from 0.203 to 0.204 (#98)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-17 00:49:23 +02:00
dependabot[bot] 5f293e47ff Update wasmparser requirement from 0.200 to 0.203 (#97)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-16 11:32:01 +02:00
dependabot[bot] 82f3638ba4 Update wasmparser requirement from 0.121 to 0.200 (#90)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/commits">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-18 09:30:04 +01:00
dependabot[bot] 74945dc206 Update wasmprinter requirement from 0.2 to 0.200 (#89)
Updates the requirements on
[wasmprinter](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/commits">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-18 09:20:40 +01:00
dependabot[bot] 1b7b54ca83 Update wasmparser requirement from 0.119 to 0.121 (#88)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/56d0d947f175af01eb91d2ff4b20c43858a2b849"><code>56d0d94</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1392">#1392</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/04ca1c576ebf1fe424b21f687eed6813c4231974"><code>04ca1c5</code></a>
Enable the component model feature by default (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1391">#1391</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/dcdfb0eea47a8e8d934f45147762b9aa66fbde5d"><code>dcdfb0e</code></a>
Use different limits for items in components (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1390">#1390</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/60ff8695a7b2b097cc18e5a3d1ccf66b0083723d"><code>60ff869</code></a>
<code>wast</code>: Fix pointer provenance bug reported by MIRI (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1386">#1386</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a6160b38674894612df19be6022af9e4e68a2eda"><code>a6160b3</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1385">#1385</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6470aa9df1782b4e7a21e5f065d0b991e0797862"><code>6470aa9</code></a>
<code>wasm-smith</code>: Implement support for generating GC
instructions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1382">#1382</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/5d42986f3c67816f75700b6df5db7e9c1b3bf2bb"><code>5d42986</code></a>
Break wasm-smith's default dependency on wasmparser (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1384">#1384</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/8b9ba68a18f1bac2f31c4889cc6c462cde3f13a0"><code>8b9ba68</code></a>
add composability for general import (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1380">#1380</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/2210c573bc5508689296e70a2fb9488dc874ad26"><code>2210c57</code></a>
dump: Better printing of rec groups and sub types (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1379">#1379</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/aaf941dbda39029b036f3a9390fe4d3525105774"><code>aaf941d</code></a>
[wast] make constructor of Id public (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1369">#1369</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.119.0...wasmparser-0.121.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-30 11:35:12 +01:00
dependabot[bot] 39fa497aee Update wasmparser requirement from 0.116 to 0.119 (#85)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/0168371fc8c7700c4aebbfabcd9947705eb09eb9"><code>0168371</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1366">#1366</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/eced912ee8a52b8818924da54a58ea85f0bbdddb"><code>eced912</code></a>
Add migration code for <code>f32</code>/<code>f64</code>. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1364">#1364</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/7dc8054d2dc5980587676d0c7fc97f117abd184f"><code>7dc8054</code></a>
Update the exception-handling validator implementation (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1333">#1333</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/0616ef196a183cf137ee06b4a5993b7d590088bf"><code>0616ef1</code></a>
Accept <code>f32</code>/<code>f64</code> as aliases for
<code>float32</code>/<code>float64</code>. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1356">#1356</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a3f8c60d98dcaab0e08d66ba22cede334fc1ded6"><code>a3f8c60</code></a>
Switch to <code>///</code> for printing documentation comments. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1357">#1357</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3c4f2f38211b42b8e5fcf1732c7f5f147e59854d"><code>3c4f2f3</code></a>
wasm-smith: Move Config's Default impl into macro (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1353">#1353</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4d1f5031027e46b322cc0c9ac8234ad42756c249"><code>4d1f503</code></a>
<code>wasm-smith</code>: Deduplicate and devirtualize configuration (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1351">#1351</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/9de484b8343b2ed1a78a31b5c2597ef4159150bb"><code>9de484b</code></a>
Use <code>bitflags</code> for symbol flags (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1350">#1350</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/928a946cab2cfc17f16d7f075e395a68456b24e3"><code>928a946</code></a>
Add parsing for <code>linking</code> custom section (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1348">#1348</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/810a98c7a5c462a5ae97366ffcf979883a9cc16c"><code>810a98c</code></a>
<code>wasmparser</code>: Get more GC spec tests passing (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1346">#1346</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.116.0...wasmparser-0.119.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-10 11:11:16 +00:00
dependabot[bot] 0c739d92c4 Update wasmparser requirement from 0.111 to 0.116 (#77)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/22402e3a057422ced35acd629cd3324bf4d983a3"><code>22402e3</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1266">#1266</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/34efe2b9b92e34f91c1415981e8cd81a6c08f703"><code>34efe2b</code></a>
Fix trivial typo in define_types.rs (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1265">#1265</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/112285c9a05c152dd2e007cd85c16784f52bc18a"><code>112285c</code></a>
Remove &quot;interface imports&quot; from binary syntax, expand accepted
strings (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1262">#1262</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/8f71316e421cabb5360d0320f7ca9ee20d692842"><code>8f71316</code></a>
<code>wasmparser</code>: Define core Wasm types in a macro (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1264">#1264</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e18b17f30166135d211a9645619d68370c90e693"><code>e18b17f</code></a>
wit-component: minor code simplification in linking.rs (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1259">#1259</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/dc5c0c5c820d31d44c48bb6c5b707a9d3de2a242"><code>dc5c0c5</code></a>
wit-component: use library order to determine duplicate symbol priority
(<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1258">#1258</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/537111b9a705168e3705177a82813f1d49c6a7c9"><code>537111b</code></a>
wasmparser: Use type-specific identifiers pervasively (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1257">#1257</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cc6a4bee4e3b04151046dbb7ddc635b422541a04"><code>cc6a4be</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1256">#1256</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4468adce8bfcca628718f2789633882f398db25f"><code>4468adc</code></a>
Enable omitting versions in world selection (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1255">#1255</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b57d64c9d5ceaa15d8036b29011093090de75529"><code>b57d64c</code></a>
Change the encoding of wit definitions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1252">#1252</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.111.0...wasmparser-0.116.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2023-11-07 10:13:57 +01:00
dependabot[bot] 060317f70d Update criterion requirement from 0.4 to 0.5 (#63)
Updates the requirements on
[criterion](https://github.com/bheisler/criterion.rs) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2>[0.5.0] - 2023-05-23</h2>
<h3>Changed</h3>
<ul>
<li>Replaced lazy_static dependency with once_cell</li>
<li>Improved documentation of the <code>html_reports</code> feature</li>
<li>Replaced atty dependency with is-terminal</li>
<li>MSRV bumped to 1.64</li>
<li>Upgraded clap dependency to v4</li>
<li>Upgraded tempfile dependency to v3.5.0</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Quick mode (<code>--quick</code>) no longer outputs 1ms for measured
times over 5 seconds</li>
<li>Documentation updates</li>
</ul>
<h2>[0.4.0] - 2022-09-10</h2>
<h3>Removed</h3>
<ul>
<li>The <code>Criterion::can_plot</code> function has been removed.</li>
<li>The <code>Criterion::bench_function_over_inputs</code> function has
been removed.</li>
<li>The <code>Criterion::bench_functions</code> function has been
removed.</li>
<li>The <code>Criterion::bench</code> function has been removed.</li>
</ul>
<h3>Changed</h3>
<ul>
<li>HTML report hidden behind non-default feature flag:
'html_reports'</li>
<li>Standalone support (ie without cargo-criterion) feature flag:
'cargo_bench_support'</li>
<li>MSRV bumped to 1.57</li>
<li><code>rayon</code> and <code>plotters</code> are optional (and
default) dependencies.</li>
<li>Status messages ('warming up', 'analyzing', etc) are printed to
stderr, benchmark results are printed to stdout.</li>
<li>Accept subsecond durations for <code>--warm-up-time</code>,
<code>--measurement-time</code> and <code>--profile-time</code>.</li>
<li>Replaced serde_cbor with ciborium because the former is no longer
maintained.</li>
<li>Upgrade clap to v3 and regex to v1.5.</li>
</ul>
<h3>Added</h3>
<ul>
<li>A <code>--discard-baseline</code> flag for discarding rather than
saving benchmark results.</li>
<li>Formal support for benchmarking code compiled to web-assembly.</li>
<li>A <code>--quiet</code> flag for printing just a single line per
benchmark.</li>
<li>A <code>Throughput::BytesDecimal</code> option for measuring
throughput in bytes but printing them using
decimal units like kilobytes instead of binary units like
kibibytes.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>When using <code>bench_with_input</code>, the input parameter will
now be passed through <code>black_box</code> before
passing it to the benchmark.</li>
</ul>
<h2>[0.3.6] - 2022-07-06</h2>
<h3>Changed</h3>
<ul>
<li>MSRV bumped to 1.49</li>
<li>Symbol for microseconds changed from ASCII 'us' to unicode 'µs'</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/4a560cb8d8b4cefc4819a6489f0ce0540663968d"><code>4a560cb</code></a>
release version 0.5 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/683">#683</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/3e2849ebf86e27507f783a20647a0fc81c6bfcc7"><code>3e2849e</code></a>
Post v0.4 CHANGELOG updates (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/680">#680</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/637010e50d3819839cd45d9f5b281c169573416a"><code>637010e</code></a>
Bump clap to version 4 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/679">#679</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/39d7e2f9546981d87ae195fe7c68f778afdb66a4"><code>39d7e2f</code></a>
Update to tempfile 3.5 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/675">#675</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/8ab2752ccfeece50347c81866a4185f29fd978a2"><code>8ab2752</code></a>
Fix typo in known_limitations.md (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/674">#674</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/a2112308ef8e3d8fe5a8da41ccb0fba3d5d460c4"><code>a211230</code></a>
chore: replace atty with is-terminal (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/628">#628</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/a844eb226bb814e6a4e8b35b3b91c74f22ad535b"><code>a844eb2</code></a>
Bump MSRV to 1.60 for csv dependency (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/665">#665</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/2f5360737807cbe90d149db6199783236f0ef634"><code>2f53607</code></a>
Use OR operator to specify multiple licenses (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/643">#643</a>)</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/86dcd7d323799043c100dbf358409e986a872a11"><code>86dcd7d</code></a>
Fix bug where time over the maximum would be reported as 1ms in quick
mode. (...</li>
<li><a
href="https://github.com/bheisler/criterion.rs/commit/2942aee124e433213f0e9b917bb730bcdc7df6f3"><code>2942aee</code></a>
Remove unnecessary <code>pub</code> from example code (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/657">#657</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bheisler/criterion.rs/compare/0.4.0...0.5.0">compare
view</a></li>
</ul>
</details>
<br />


You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2023-11-07 10:13:41 +01:00
dependabot[bot] 998bbb8bd5 Bump actions/checkout from 3 to 4 (#73)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to
4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update default runtime to node20 by <a
href="https://github.com/takost"><code>@​takost</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1436">actions/checkout#1436</a></li>
<li>Support fetching without the --progress option by <a
href="https://github.com/simonbaird"><code>@​simonbaird</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1067">actions/checkout#1067</a></li>
<li>Release 4.0.0 by <a
href="https://github.com/takost"><code>@​takost</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1447">actions/checkout#1447</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/takost"><code>@​takost</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1436">actions/checkout#1436</a></li>
<li><a
href="https://github.com/simonbaird"><code>@​simonbaird</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1067">actions/checkout#1067</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v3...v4.0.0">https://github.com/actions/checkout/compare/v3...v4.0.0</a></p>
<h2>v3.6.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Mark test scripts with Bash'isms to be run via Bash by <a
href="https://github.com/dscho"><code>@​dscho</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1377">actions/checkout#1377</a></li>
<li>Add option to fetch tags even if fetch-depth &gt; 0 by <a
href="https://github.com/RobertWieczoreck"><code>@​RobertWieczoreck</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/579">actions/checkout#579</a></li>
<li>Release 3.6.0 by <a
href="https://github.com/luketomlinson"><code>@​luketomlinson</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1437">actions/checkout#1437</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/RobertWieczoreck"><code>@​RobertWieczoreck</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/579">actions/checkout#579</a></li>
<li><a
href="https://github.com/luketomlinson"><code>@​luketomlinson</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1437">actions/checkout#1437</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v3.5.3...v3.6.0">https://github.com/actions/checkout/compare/v3.5.3...v3.6.0</a></p>
<h2>v3.5.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix: Checkout Issue in self hosted runner due to faulty submodule
check-ins by <a
href="https://github.com/megamanics"><code>@​megamanics</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1196">actions/checkout#1196</a></li>
<li>Fix typos found by codespell by <a
href="https://github.com/DimitriPapadopoulos"><code>@​DimitriPapadopoulos</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1287">actions/checkout#1287</a></li>
<li>Add support for sparse checkouts by <a
href="https://github.com/dscho"><code>@​dscho</code></a> and <a
href="https://github.com/dfdez"><code>@​dfdez</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1369">actions/checkout#1369</a></li>
<li>Release v3.5.3 by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1376">actions/checkout#1376</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/megamanics"><code>@​megamanics</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1196">actions/checkout#1196</a></li>
<li><a
href="https://github.com/DimitriPapadopoulos"><code>@​DimitriPapadopoulos</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1287">actions/checkout#1287</a></li>
<li><a href="https://github.com/dfdez"><code>@​dfdez</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1369">actions/checkout#1369</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v3...v3.5.3">https://github.com/actions/checkout/compare/v3...v3.5.3</a></p>
<h2>v3.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix: Use correct API url / endpoint in GHES by <a
href="https://github.com/fhammerl"><code>@​fhammerl</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1289">actions/checkout#1289</a>
based on <a
href="https://redirect.github.com/actions/checkout/issues/1286">#1286</a>
by <a href="https://github.com/1newsr"><code>@​1newsr</code></a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v3.5.1...v3.5.2">https://github.com/actions/checkout/compare/v3.5.1...v3.5.2</a></p>
<h2>v3.5.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Improve checkout performance on Windows runners by upgrading
<code>@​actions/github</code> dependency by <a
href="https://github.com/BrettDong"><code>@​BrettDong</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1246">actions/checkout#1246</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/BrettDong"><code>@​BrettDong</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1246">actions/checkout#1246</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v4.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1067">Support
fetching without the --progress option</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1436">Update to
node20</a></li>
</ul>
<h2>v3.6.0</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1377">Fix: Mark
test scripts with Bash'isms to be run via Bash</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/579">Add
option to fetch tags even if fetch-depth &gt; 0</a></li>
</ul>
<h2>v3.5.3</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1196">Fix:
Checkout fail in self-hosted runners when faulty submodule are
checked-in</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/1287">Fix
typos found by codespell</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/1369">Add
support for sparse checkouts</a></li>
</ul>
<h2>v3.5.2</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/1289">Fix
api endpoint for GHES</a></li>
</ul>
<h2>v3.5.1</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/1246">Fix
slow checkout on Windows</a></li>
</ul>
<h2>v3.5.0</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/1237">Add
new public key for known_hosts</a></li>
</ul>
<h2>v3.4.0</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1209">Upgrade
codeql actions to v2</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1210">Upgrade
dependencies</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1225">Upgrade
<code>@​actions/io</code></a></li>
</ul>
<h2>v3.3.0</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1045">Implement
branch list using callbacks from exec function</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/1050">Add
in explicit reference to private checkout options</a></li>
<li>[Fix comment typos (that got added in <a
href="https://redirect.github.com/actions/checkout/issues/770">#770</a>)](<a
href="https://redirect.github.com/actions/checkout/pull/1057">actions/checkout#1057</a>)</li>
</ul>
<h2>v3.2.0</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/942">Add
GitHub Action to perform release</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/967">Fix
status badge</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1002">Replace
datadog/squid with ubuntu/squid Docker image</a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/964">Wrap
pipeline commands for submoduleForeach in quotes</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1029">Update
<code>@​actions/io</code> to 1.1.2</a></li>
<li><a
href="https://redirect.github.com/actions/checkout/pull/1039">Upgrading
version to 3.2.0</a></li>
</ul>
<h2>v3.1.0</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/939">Use
<code>@​actions/core</code> <code>saveState</code> and
<code>getState</code></a></li>
<li><a href="https://redirect.github.com/actions/checkout/pull/922">Add
<code>github-server-url</code> input</a></li>
</ul>
<h2>v3.0.2</h2>
<ul>
<li><a href="https://redirect.github.com/actions/checkout/pull/770">Add
input <code>set-safe-directory</code></a></li>
</ul>
<h2>v3.0.1</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/3df4ab11eba7bda6032a0b82a6bb43b11571feac"><code>3df4ab1</code></a>
Release 4.0.0 (<a
href="https://redirect.github.com/actions/checkout/issues/1447">#1447</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/8b5e8b768746b50394015010d25e690bfab9dfbc"><code>8b5e8b7</code></a>
Support fetching without the --progress option (<a
href="https://redirect.github.com/actions/checkout/issues/1067">#1067</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/97a652b80035363df47baee5031ec8670b8878ac"><code>97a652b</code></a>
Update default runtime to node20 (<a
href="https://redirect.github.com/actions/checkout/issues/1436">#1436</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2023-11-07 10:13:22 +01:00
StackOverflowExcept1on fd3b1f856b chore: fix clippy warnings on latest nightly rust (#78)
btw `#[cfg(...)]` was used implicitly and expanded always lead to `use
alloc::collections::BTreeMap as Map;`
the second `cfg(std)` just doesn't work bcz `featureS`
2023-11-07 10:03:36 +01:00
StackOverflowExcept1on fdce5c64f1 chore: modernize WASM tests (#79)
I tried locally merge `fix-tests` and `fix-clippy` branches and CI
should work after my PRs
2023-11-07 09:14:09 +01:00
dependabot[bot] 6307588b3d Update wasmparser requirement from 0.110 to 0.111 (#71)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/2e63788ad535724e49a0da036281d9663b6d5294"><code>2e63788</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1173">#1173</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c17cf172b319a0f07f797a224a4152fa42ff581d"><code>c17cf17</code></a>
Disallow <code>(borrow $t)</code> in function result types (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1162">#1162</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/9fb2019dca043434837c996ec5105de350bccaea"><code>9fb2019</code></a>
wit-component: Add doc comment printing to WitPrinter (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1167">#1167</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a0c46a7a16fef5cc9143ad30c77f19303c27d907"><code>a0c46a7</code></a>
Probe for post-return instead of asserting existence (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1159">#1159</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4678a61ae428da21299aeae016bd56d5e248248f"><code>4678a61</code></a>
[wit-component] add shared-everything linking support (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1133">#1133</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/06aa46eda73d02b38c924c01806aac7eece5d58b"><code>06aa46e</code></a>
Extract <code>LocalParser</code> for parsing <code>local</code>. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1156">#1156</a>)
(<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1161">#1161</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3e1fb68b217b210c816a504fa7abe0907c9c9039"><code>3e1fb68</code></a>
Add text format and printing support for <code>dylink.0</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1135">#1135</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/9ed609db08183dc2b2fe239af5204bb9d6456a8a"><code>9ed609d</code></a>
Fix a panic decoding WIT from a component (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1157">#1157</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/2b4ade8c808f5c26a701d1c7a883ea1893d2553f"><code>2b4ade8</code></a>
Rename <code>Resolve::push_wasm</code> to <code>push_flat</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1158">#1158</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/559ede0a436240cb7dfe162c568f398655e9b18c"><code>559ede0</code></a>
Update wasm-compose example based on latest changes. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1154">#1154</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.110.0...wasmparser-0.111.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-20 11:45:30 +02:00
dependabot[bot] ca0a83ff91 Update wasmparser requirement from 0.109 to 0.110 (#69)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/94ad03bdb292549d6d699518343bad5639c05e8d"><code>94ad03b</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1145">#1145</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/dd6ddb31e9ffdc7cc04284a544a2738dc28e88c7"><code>dd6ddb3</code></a>
Fix encoding of type information in wasm-compose (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1141">#1141</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6f4508ab3b96515b44d842c6cac5879358e76fe4"><code>6f4508a</code></a>
Move the wasm-tools CLI to the <code>src/bin</code> directory (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1144">#1144</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c18d59fdfc906c0f9aae2f05318b6b890fc8d429"><code>c18d59f</code></a>
Fix wit-component not removing dead type imports (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1143">#1143</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/69b5213dda658510f8c14c484520bd3a2619a8a9"><code>69b5213</code></a>
Disallow empty types in the component model (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1142">#1142</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/23a2d6c56ec3698e809c7aad1806c5cd188dc658"><code>23a2d6c</code></a>
Convert more things to links in the rustdoc documentation. (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1137">#1137</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/ac8d61669ee1188b4bbd09168fcb62944bcc55d1"><code>ac8d616</code></a>
Fix the <code>Parser::parse</code> example to work with nested
components (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1136">#1136</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/188de0fd412dd01dd41bf91c897935934282c13d"><code>188de0f</code></a>
Fix a few typos in resolver (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1132">#1132</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cea2220ebb4e45041ef8c3ab13c0a87add632714"><code>cea2220</code></a>
Move component <code>value</code> support behind a feature flag (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1131">#1131</a>)</li>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.109.0...wasmparser-0.110.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-01 13:09:32 +02:00
dependabot[bot] 16469520a4 Update wasmi requirement from 0.29 to 0.31 (#70)
Updates the requirements on [wasmi](https://github.com/paritytech/wasmi)
to permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/releases">wasmi's
releases</a>.</em></p>
<blockquote>
<h2>v0.31.0 - 2023-07-31</h2>
<h3>Added</h3>
<ul>
<li>Added <code>ResourceLimiter</code> API known from Wasmtime. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/737">paritytech/wasmi#737</a>)
<ul>
<li>This API allows to limit growable Wasm resources such as Wasm tables
and linear memories.</li>
<li>Special thanks to <a href="https://github.com/graydon">Graydon
Hoare</a> for contributing this feature!</li>
</ul>
</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Fixed a bug were <code>Module::len_globals</code> internal API
returned length of linear memories instead. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/741">paritytech/wasmi#741</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Removed <code>intx</code> crate dependency. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/727">paritytech/wasmi#727</a>)
<ul>
<li>The dependence on the <code>intx</code> crate was accidental and not
really required at any time.</li>
</ul>
</li>
<li>Optimized <code>f64.const</code> instructions for <code>f64</code>
constant values that can losslessly be encoded as 32-bit
<code>f32</code> value. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/746">paritytech/wasmi#746</a>)</li>
</ul>
<h3>Dev. Note</h3>
<ul>
<li>We now publish and record graphs of benchmarks over time. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/740">paritytech/wasmi#740</a>)
<ul>
<li>This allows <code>wasmi</code> developers to better inspect
performance changes over longer periods of time.</li>
</ul>
</li>
<li>Updated dev. dependencies:
<ul>
<li><code>criterion 0.4.0</code> -&gt; <code>0.5.0</code></li>
<li><code>wast 0.52.0</code> -&gt; <code>0.62.0</code></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/blob/master/CHANGELOG.md">wasmi's
changelog</a>.</em></p>
<blockquote>
<h2>[<code>0.31.0</code>] - 2023-07-31</h2>
<h3>Added</h3>
<ul>
<li>Added <code>ResourceLimiter</code> API known from Wasmtime. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/737">paritytech/wasmi#737</a>)
<ul>
<li>This API allows to limit growable Wasm resources such as Wasm tables
and linear memories.</li>
<li>Special thanks to <a href="https://github.com/graydon">Graydon
Hoare</a> for contributing this feature!</li>
</ul>
</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Fixed a bug were <code>Module::len_globals</code> internal API
returned length of linear memories instead. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/741">paritytech/wasmi#741</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Removed <code>intx</code> crate dependency. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/727">paritytech/wasmi#727</a>)
<ul>
<li>The dependence on the <code>intx</code> crate was accidental and not
really required at any time.</li>
</ul>
</li>
<li>Optimized <code>f64.const</code> instructions for <code>f64</code>
constant values that can losslessly be encoded as 32-bit
<code>f32</code> value. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/746">paritytech/wasmi#746</a>)</li>
</ul>
<h3>Dev. Note</h3>
<ul>
<li>We now publish and record graphs of benchmarks over time. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/740">paritytech/wasmi#740</a>)
<ul>
<li>This allows <code>wasmi</code> developers to better inspect
performance changes over longer periods of time.</li>
</ul>
</li>
<li>Updated dev. dependencies:
<ul>
<li><code>criterion 0.4.0</code> -&gt; <code>0.5.0</code></li>
<li><code>wast 0.52.0</code> -&gt; <code>0.62.0</code></li>
</ul>
</li>
</ul>
<h2>[<code>0.30.0</code>] - 2023-05-28</h2>
<h3>Changed</h3>
<ul>
<li>Optimized <code>wasmi</code> bytecode memory consumption. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/718">paritytech/wasmi#718</a>)
<ul>
<li>This reduced the memory consumption of <code>wasmi</code> bytecode
by organizing the instructions
into so-called instruction words, effectively reducing the amount of
bytes required per
<code>wasmi</code> instruction 16 bytes to 8 bytes.
There was an experiment with 4 bytes but experiments confirmed that 8
bytes per instruction
word was the sweetspot for <code>wasmi</code> execution and translation
performance.</li>
<li>This did not affect execution performance too much but we saw
performance improvements
for translation from Wasm to <code>wasmi</code> bytecode by roughly
15-20%.</li>
</ul>
</li>
<li>Optimized <code>call</code> and <code>return_call</code> for Wasm
module internal calls. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/724">paritytech/wasmi#724</a>)
<ul>
<li><code>wasmi</code> bytecode now differentiates between calls to Wasm
module internal functions
and imported functions which allows the <code>wasmi</code> bytecode
executor to perform the common
internal calls more efficiently.</li>
<li>This led to an execution performance improvement across the board
but especially for
call intense workloads of up to 30% in some test cases.</li>
</ul>
</li>
</ul>
<h2>[<code>0.29.0</code>] - 2023-03-20</h2>
<h3>Added</h3>
<ul>
<li>Added support for <code>extended-const</code> Wasm proposal. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/707">paritytech/wasmi#707</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/paritytech/wasmi/commit/983ef37b3e2acf38a898e191c9bbbd2bc2c05da7"><code>983ef37</code></a>
Prepare <code>wasmi</code> release for version <code>0.31.0</code> (<a
href="https://redirect.github.com/paritytech/wasmi/issues/748">#748</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/af8c588c9059c5299da812958d7a71dc024d2938"><code>af8c588</code></a>
Publishing benchmarks for graphs (<a
href="https://redirect.github.com/paritytech/wasmi/issues/740">#740</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/ee577f268db3bc8b95c685205517c37b4800fa68"><code>ee577f2</code></a>
Refactor <code>reftype</code> <code>Transposer</code> conversion utility
(<a
href="https://redirect.github.com/paritytech/wasmi/issues/747">#747</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/ed12feb9f286d13bbdce50491c4d50487319f316"><code>ed12feb</code></a>
Add <code>F64Const32</code> instruction (<a
href="https://redirect.github.com/paritytech/wasmi/issues/746">#746</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/fbe1810a209f8884883333963b6d03c7421c5e5f"><code>fbe1810</code></a>
Fix <code>clippy</code> warning (<a
href="https://redirect.github.com/paritytech/wasmi/issues/745">#745</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/e5fdb7fe32b9151dff6a39c8a4d516817cc72dc2"><code>e5fdb7f</code></a>
fixes <a
href="https://redirect.github.com/paritytech/wasmi/issues/735">#735</a>:
copy paste typo (<a
href="https://redirect.github.com/paritytech/wasmi/issues/741">#741</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/4860ecc877a6e13a8c4924be6d8f287f126752ad"><code>4860ecc</code></a>
Support for <code>ResourceLimiter</code> API (<a
href="https://redirect.github.com/paritytech/wasmi/issues/737">#737</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/799995da7afb0ae02bb4fd1c9f242fe07c7ad824"><code>799995d</code></a>
make <code>ConstRef</code> based on <code>u32</code> instead of
<code>intx::U24</code> (<a
href="https://redirect.github.com/paritytech/wasmi/issues/727">#727</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/4fb164ce6b9a06af65923596711f5988384d6e13"><code>4fb164c</code></a>
Prepare release of <code>wasmi</code> version <code>0.30.0</code> (<a
href="https://redirect.github.com/paritytech/wasmi/issues/726">#726</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/a6165a6ff9ad07f525b3352b0ab4442da32e0f7f"><code>a6165a6</code></a>
smol clean-up (<a
href="https://redirect.github.com/paritytech/wasmi/issues/725">#725</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/paritytech/wasmi/compare/v0.29.0...v0.31.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-01 09:44:27 +02:00
dependabot[bot] 1d83a81c05 Update wasmparser requirement from 0.108 to 0.109 (#68)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b19ce5165cf2b0c20e01e0dc238712c4d44b42be"><code>b19ce51</code></a>
Bump versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1128">#1128</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/7cec276e1a3e600bd8036f672c9483d875f164e8"><code>7cec276</code></a>
Remove public deps from <code>wasm-metadata</code>'s API (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1130">#1130</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c91f611be4b8c4ea5d9d936594f68c0104dd80dd"><code>c91f611</code></a>
Update handling and parsing of element segments (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1126">#1126</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/07229fec475d38a56949a1ddab354e5813cc7ca7"><code>07229fe</code></a>
Update to new GC cast instruction encoding (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1127">#1127</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3948ae92972785b252f3c76af601ac83ee3ac3da"><code>3948ae9</code></a>
Update wit-component's <code>bitflags</code> dependency (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1123">#1123</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/8c7e3c5df72d075b66dd5d18ac4bee10041b1353"><code>8c7e3c5</code></a>
Update serde_yaml used by <code>wasm-compose</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1124">#1124</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6f59f98f7c4f94632df7c88627bbdc46db81ab02"><code>6f59f98</code></a>
Implement returning option/result of a handle in code generation (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1121">#1121</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/42f4bbf5e4218a83cca93b900ecd681b92a89b1a"><code>42f4bbf</code></a>
Fix parsing out-of-bounds <code>nan</code> constants (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1111">#1111</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/aa161581efeafe5e2be665925b365394b09473c9"><code>aa16158</code></a>
Fix &quot;duplicate identifier for field&quot; for subtype fields (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1117">#1117</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3186350fca1a749f933334270bd46582e2130ccb"><code>3186350</code></a>
Don't lex the entire input immediately (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1110">#1110</a>)</li>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.108.0...wasmparser-0.109.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 17:11:34 +02:00
dependabot[bot] 7fa2cd3cd2 Update wasmparser requirement from 0.104 to 0.108 (#67)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/620b4ab26820b67f93e70022e6cf656c5d7fb108"><code>620b4ab</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1118">#1118</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/46f9053e4100f6341ae704c0ee468b18a00ba1e3"><code>46f9053</code></a>
Update binary format for <code>resource.drop</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1116">#1116</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b3990e8b59e46b7acc76c8d7b2cf4470f08e2cd6"><code>b3990e8</code></a>
Reduce verbosity in wasmparser <code>Types</code> API (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1106">#1106</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/27f511cc60f7a83ae5149cc36105aa6233f13a9b"><code>27f511c</code></a>
Fix wit-smith syntax for static functions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1113">#1113</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/2413c71e542a371044c073006b3f83158344f327"><code>2413c71</code></a>
Test a wasm target in CI (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1112">#1112</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4a568a3eb3d82ac3fa92bd8f64ff69116fca307a"><code>4a568a3</code></a>
Don't panic in wasmprinter with non-function types (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1114">#1114</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6dae59e0b80c17ef7cee0ce67c886ad92a184049"><code>6dae59e</code></a>
fix: assertions for wasm target (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1109">#1109</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3379199d0d58da323740f7fdaa4618b459851b5d"><code>3379199</code></a>
feat(wasm-compose): --definitions configuration for components with
exports d...</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/195cc43bcf3b76f4cf19310dbcbd7825689f3b6a"><code>195cc43</code></a>
Fix exponential behavior elaborating WIT world exports (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1107">#1107</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/14b48186365c1340861f0c14485d6a0f4429de9e"><code>14b4818</code></a>
Shrink the size of wast text tokens (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1103">#1103</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.104.0...wasmparser-0.108.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-14 15:03:30 +09:00
dependabot[bot] 28e964d9d1 Update wasmparser requirement from 0.103 to 0.104 (#60)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/1e573fb1ae0ca457be1d06aa55a2fab06fa13b44"><code>1e573fb</code></a>
Bump crate versions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/1002">#1002</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/11cf92cf663cda0d68b5823e7d868d0ba7acdc84"><code>11cf92c</code></a>
Initial implementation of resource types (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/966">#966</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/207472c004b0e69a721529b08e4cd3ec24394b26"><code>207472c</code></a>
[wasm-encoder] Add encoding for coredumps (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/998">#998</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/016838279808be4d257f1b58b9942420f0a09855"><code>0168382</code></a>
Fix wasm-encoder's encoding of element segments (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/995">#995</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6e660de665ccb68a10b49d8fb726579d1874fd6f"><code>6e660de</code></a>
Support core wasm inputs to <code>wasm-tools component wit</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/994">#994</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/734accf3197ef82782e6f81ab8e53311df0a64bb"><code>734accf</code></a>
Require 'alias core export' when aliasing core item (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/997">#997</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/95c6bf7de19c26db41f5e40b9a3af61eecc7de57"><code>95c6bf7</code></a>
Add a new <code>wit-smith</code> subcommand (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/992">#992</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/f69b0860ba8afec33b38992c04e1c994b6bcfd76"><code>f69b086</code></a>
Fix some fuzz-discovered issues in WIT parsing and encoding (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/991">#991</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b00cc2c965de53a09fe67d3839083c1e32ada460"><code>b00cc2c</code></a>
Add a <code>--skeleton</code> option to <code>wasm-tools print</code>
(<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/990">#990</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/d1f35fcd1ad64c9baceae81b1b5cb98e25c7b7de"><code>d1f35fc</code></a>
wasm-mutate: Fix removing table 0 when an element references it (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/984">#984</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.103.0...wasmparser-0.104.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 12:11:43 +02:00
dependabot[bot] c07099b8d5 Update wasmparser requirement from 0.102 to 0.103 (#59)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/d808ad752f4e1e5e7aaecc226813162e2b0d0655"><code>d808ad7</code></a>
Bump crate verisons (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/982">#982</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b17fc48a23152735bafd8f7ee95e3b55683d9511"><code>b17fc48</code></a>
Optimize types in wasmparser slightly (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/979">#979</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/874e2fa79ff0c01b1594aed13f5e78b6f1e84416"><code>874e2fa</code></a>
Improve wit component errors when failing to decode function (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/978">#978</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/027507a75a705774c08b8b646ae9b9d70c3f702c"><code>027507a</code></a>
wit-component: Implement merging <code>Resolve</code>s together (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/974">#974</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a791205f4e0586bc3565460effbc22e01192b155"><code>a791205</code></a>
Update wasm-tools compose example with latest cargo component (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/976">#976</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/faf3c51fefa93c56215a3838a0f2ebd9932c93d8"><code>faf3c51</code></a>
wast: Update GC proposal instructions (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/972">#972</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/9c94ab1af1443f79b27b30218e29f1f0fc0260c0"><code>9c94ab1</code></a>
wasmparser: Pack <code>RefType</code> into a <code>[u8; 3]</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/971">#971</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/d550bd5491f9433bc42601f03a632ade53805b62"><code>d550bd5</code></a>
<code>wasmparser</code>: turn table index in the elements section into
an <code>Option</code> (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/957">#957</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/3af2562b91fbe5ea225f193b3dc2747142dce18e"><code>3af2562</code></a>
tests(wit-component): update <code>wasi-http</code> interface (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/969">#969</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/1e0052974277b3cce6c3703386e4e90291da2b24"><code>1e00529</code></a>
preserve <code>cabi_post_</code> exports when appropriate (<a
href="https://redirect.github.com/bytecodealliance/wasm-tools/issues/965">#965</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.102.0...wasmparser-0.103.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 10:39:34 +02:00
dependabot[bot] 6039337457 Update wasmi requirement from 0.28 to 0.29 (#58)
Updates the requirements on [wasmi](https://github.com/paritytech/wasmi)
to permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/releases">wasmi's
releases</a>.</em></p>
<blockquote>
<h2>v0.29.0 - 2023-03-20</h2>
<h3>Added</h3>
<ul>
<li>Added support for <code>extended-const</code> Wasm proposal. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/707">paritytech/wasmi#707</a>)</li>
<li>Added fuel consumption modes. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/706">paritytech/wasmi#706</a>)
<ul>
<li>This allows eager and lazy fuel consumption modes to be used which
mainly affects bulk operations such as <code>table.copy</code> and
<code>memory.grow</code>.
Eager fuel consumption always consumes fuel before a bulk operation for
the
total amount independent of success or failure of the operation whereras
lazy fuel consumption only consumes fuel for successful executions.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Normalize fuel costs of all instructions. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/705">paritytech/wasmi#705</a>)
<ul>
<li>With this change most instructions cost roughly 1 fuel upon
execution.
This is more similar to how Wasmtime deals with fuel metered instruction
costs.
Before this change <code>wasmi</code> tried to have fuel costs that more
closely mirror
the computation intensity of the respective instruction according to
benchmarks.</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/blob/master/CHANGELOG.md">wasmi's
changelog</a>.</em></p>
<blockquote>
<h2>[<code>0.29.0</code>] - 2023-03-20</h2>
<h3>Added</h3>
<ul>
<li>Added support for <code>extended-const</code> Wasm proposal. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/707">paritytech/wasmi#707</a>)</li>
<li>Added fuel consumption modes. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/706">paritytech/wasmi#706</a>)
<ul>
<li>This allows eager and lazy fuel consumption modes to be used which
mainly affects bulk operations such as <code>table.copy</code> and
<code>memory.grow</code>.
Eager fuel consumption always consumes fuel before a bulk operation for
the
total amount independent of success or failure of the operation whereras
lazy fuel consumption only consumes fuel for successful executions.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Normalize fuel costs of all instructions. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/705">paritytech/wasmi#705</a>)
<ul>
<li>With this change most instructions cost roughly 1 fuel upon
execution.
This is more similar to how Wasmtime deals with fuel metered instruction
costs.
Before this change <code>wasmi</code> tried to have fuel costs that more
closely mirror
the computation intensity of the respective instruction according to
benchmarks.</li>
</ul>
</li>
</ul>
<h2>[<code>0.28.0</code>] - 2023-03-01</h2>
<h3>Added</h3>
<ul>
<li>Added support for the <code>tail-call</code> Wasm proposal. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/683">paritytech/wasmi#683</a>)</li>
<li>Added support for <code>Linker</code> defined host functions. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/692">paritytech/wasmi#692</a>)
<ul>
<li>Apparently this PR introduced some performance wins for the Wasm
target according to our tests.
This information shall be taken with a grain of salt since we are not
sure why those performance
improvement occured since the PR's functionality is orthogonal to Wasm
engine performance.</li>
<li>Required precursor refactoring PR: <a
href="https://redirect.github.com/paritytech/wasmi/pull/681">paritytech/wasmi#681</a></li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>The <code>wasmi_wasi</code> crate now more closely mirrors the
<code>wasmtime_wasi</code> crate API. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/700">paritytech/wasmi#700</a>)</li>
</ul>
<h3>Internal</h3>
<ul>
<li>Refactor the <code>wasmi</code> Wasm engine to handle Wasm calls and
returns in its core. [(<a
href="https://redirect.github.com/paritytech/wasmi/issues/694">#694</a>)]
<ul>
<li>This improved performance of Wasm function calls significantly at
the cost of host function call performance.</li>
<li>Also this seemed to have impacts Wasm target performance quite
positively, too.</li>
</ul>
</li>
<li>The <code>Store</code> now handles Wasm functions and host functions
separately. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/686">paritytech/wasmi#686</a>)
<ul>
<li>This allows to store Wasm functions into the <code>StoreInner</code>
type which was an important
step towards the major refactoring in [(<a
href="https://redirect.github.com/paritytech/wasmi/issues/694">#694</a>)]</li>
<li>It was expected that host function call performance would degrade by
this PR but our tests
actually showed that the opposite was true and Wasm target performance
was improved overall.</li>
</ul>
</li>
<li>Introduce <code>ValueStackPtr</code> abstraction for the
<code>wasmi</code> engine core. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/688">paritytech/wasmi#688</a>)
<ul>
<li>This change significantly improved performance especially on the
Wasm target according to our tests.</li>
</ul>
</li>
<li>Optimize <code>memory.{load,store}</code> when reading or writing
single bytes. (<a
href="https://redirect.github.com/paritytech/wasmi/pull/689">paritytech/wasmi#689</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/paritytech/wasmi/commit/23d8d8c684255f2d63526baa348ab3eb3d249de0"><code>23d8d8c</code></a>
Prepare <code>wasmi</code> release of version <code>0.29.0</code> (<a
href="https://redirect.github.com/paritytech/wasmi/issues/708">#708</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/eb8d73fd3b2a7f9134bc46d391b6a6963439dbd6"><code>eb8d73f</code></a>
Add <code>extended-const</code> Wasm proposal support (<a
href="https://redirect.github.com/paritytech/wasmi/issues/707">#707</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/6dbbada8099511e538fb2a26e583012df0c90b5c"><code>6dbbada</code></a>
Add fuel consumption modes (<a
href="https://redirect.github.com/paritytech/wasmi/issues/706">#706</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/cf7736f57abb7dec469d5485f4a80fcf3aa2a392"><code>cf7736f</code></a>
Normalize fuel costs to roughly 1 fuel per executed instruction (<a
href="https://redirect.github.com/paritytech/wasmi/issues/705">#705</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/223f815d087fb918493b243182ae24bb960d8336"><code>223f815</code></a>
Update and refactor the <code>wasmi_wasi</code> crate (<a
href="https://redirect.github.com/paritytech/wasmi/issues/700">#700</a>)</li>
<li>See full diff in <a
href="https://github.com/paritytech/wasmi/compare/v0.28.0...v0.29.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-21 00:11:34 +01:00
dependabot[bot] 51daef9eba Update wasmparser requirement from 0.101 to 0.102 (#57)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/1d75a98fe32f9f4ea8cca2e51377116201e60e81"><code>1d75a98</code></a>
Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/950">#950</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cfc1d6052e4596ba6c577b1bb192fc6423b46154"><code>cfc1d60</code></a>
Fix size/align calculations for WIT variants (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/948">#948</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/ae010afe5a252b645fcfebf0b32d7a42384c57b8"><code>ae010af</code></a>
Increase limits on component/module/instance types (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/947">#947</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6da2f7490d12c36cc3652bb2c150b13262892af2"><code>6da2f74</code></a>
Restrict component import/export overlap (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/946">#946</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/efb9316b2fd462150c259a11a984a59d3e0cbfd8"><code>efb9316</code></a>
Update support for the relaxed-simd proposal (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/944">#944</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/56cdbdd3fc6b1aca1afb13268bc5f3494e9c5b6c"><code>56cdbdd</code></a>
Increase the maximum type size to 1M (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/945">#945</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c892013426b5143b3e6108d2fc42ef825e63fe88"><code>c892013</code></a>
Improve validation error when component model feature not enabled (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/939">#939</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cdbaae2272b12bc70ceb76587f0f9c8968b7ffe1"><code>cdbaae2</code></a>
bump versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/942">#942</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/07a55c628d20a9f5cb21c684da430d9453c3f6a5"><code>07a55c6</code></a>
wasm-compose: update the example for latest tooling. (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/941">#941</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4ee705fbb5600ae51ec3192b5a1cbf8f67bfda95"><code>4ee705f</code></a>
Remove outdated <code>is_char</code> check in ABI lowering (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/938">#938</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.101.0...wasmparser-0.102.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-07 03:19:53 +01:00
Alexander Theißen 3ba9c2cfa1 Add benchmarks for wasmi builtin metering (#56)
* Upgraded to newest wasmi
* Refactored benchmarks
* Two new benchmark strategies (`no_metering` and `wasmi_builtin`)

We can now benchmark the execution of modules using our two
instrumentation strategies in addition to no metering (as a baseline)
and wasmi's builtin metering.

We can learn from the following results (ran on my M1) that the builtin
metering decisively outperforms the instrumentation on every single
fixture.

cc @Robbepop 

```
coremark/no_metering                    [15.586 s 15.588 s 15.589 s]
coremark/wasmi_builtin                  [16.403 s 16.414 s 16.434 s]
coremark/host_function                  [18.245 s 18.248 s 18.252 s]
coremark/mutable_global                 [20.476 s 20.486 s 20.505 s]

recursive_ok/no_metering                [111.32 µs 111.33 µs 111.34 µs]
recursive_ok/wasmi_builtin              [138.64 µs 138.65 µs 138.66 µs]
recursive_ok/host_function              [495.55 µs 495.64 µs 495.78 µs]
recursive_ok/mutable_global             [514.07 µs 514.09 µs 514.11 µs]

fibonacci_recursive/no_metering         [3.9098 µs 3.9102 µs 3.9108 µs]
fibonacci_recursive/wasmi_builtin       [4.3242 µs 4.3246 µs 4.3250 µs]
fibonacci_recursive/host_function       [12.913 µs 12.914 µs 12.915 µs]
fibonacci_recursive/mutable_global      [13.202 µs 13.208 µs 13.212 µs]
              
factorial_recursive/no_metering         [530.72 ns 530.84 ns 530.91 ns]
factorial_recursive/wasmi_builtin       [619.17 ns 619.30 ns 619.44 ns]
factorial_recursive/host_function       [1.7656 µs 1.7657 µs 1.7659 µs]
factorial_recursive/mutable_global      [1.8783 µs 1.8786 µs 1.8788 µs]

count_until/no_metering                 [1.2422 ms 1.2423 ms 1.2424 ms]
count_until/wasmi_builtin               [1.3976 ms 1.3978 ms 1.3981 ms]
count_until/host_function               [4.8074 ms 4.8106 ms 4.8125 ms]
count_until/mutable_global              [5.9161 ms 5.9169 ms 5.9182 ms]

memory_vec_add/no_metering              [4.1630 ms 4.1638 ms 4.1648 ms]
memory_vec_add/wasmi_builtin            [4.3913 ms 4.3925 ms 4.3930 ms]
memory_vec_add/host_function            [8.2925 ms 8.2949 ms 8.2967 ms]
memory_vec_add/mutable_global           [9.1124 ms 9.1152 ms 9.1163 ms]

wasm_kernel::tiny_keccak/no_metering    [613.21 µs 613.42 µs 613.58 µs]
wasm_kernel::tiny_keccak/wasmi_builtin  [617.04 µs 617.46 µs 617.81 µs]
wasm_kernel::tiny_keccak/host_function  [817.24 µs 817.44 µs 817.89 µs]
wasm_kernel::tiny_keccak/mutable_global [873.42 µs 873.90 µs 874.65 µs]

global_bump/no_metering                 [1.4597 ms 1.4598 ms 1.4600 ms]
global_bump/wasmi_builtin               [1.6151 ms 1.6152 ms 1.6153 ms]
global_bump/host_function               [5.5393 ms 5.5418 ms 5.5435 ms]
global_bump/mutable_global              [6.9446 ms 6.9454 ms 6.9461 ms]
```
2023-03-06 22:06:45 +01:00
dependabot[bot] 16297ab942 Update wasmparser requirement from 0.100 to 0.101 (#53)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/ca2e77094dc1896d6d8c85d638981c6bfb4f9ae6"><code>ca2e770</code></a>
Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/931">#931</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/de36f6c60166bcbc7681f6b97dd5990441cb43a6"><code>de36f6c</code></a>
Support wit bindgens adding producer information via component-type
metadata ...</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/902e2898c8965c1b75051bb64ef6d774f46447d2"><code>902e289</code></a>
Add a function to extract a world from a document (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/928">#928</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c242e9a7e79d989792d1824915ac192a2afb57d9"><code>c242e9a</code></a>
Fix validation of <code>ref.func</code> without function-references (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/925">#925</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e713d1e8e71b170c880c2ddad8bfb9f992c57b47"><code>e713d1e</code></a>
Fix validation panic with unreachable code (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/926">#926</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cda63d228ab58ebaccff1d5f544ae3c65a8d506a"><code>cda63d2</code></a>
Run more function-references tests (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/922">#922</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/dd5ad96a52b5095fc4dcb9b305ebe8c8b5041a98"><code>dd5ad96</code></a>
Fix a copy/paste mistake in add-function mutator (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/927">#927</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e5293d587f463e67d42ca26b151cd7afdc0a5e17"><code>e5293d5</code></a>
Function references (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/701">#701</a>)</li>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.100.0...wasmparser-0.101.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-04 22:25:57 +01:00
dependabot[bot] 325cdb8969 Update wasmparser requirement from 0.99 to 0.100 (#51)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/0932bc10082c6457a33164beb1b07d64cbdc093e"><code>0932bc1</code></a>
Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/921">#921</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/c7e5beb2849d8fef26988758de171ac860fe5848"><code>c7e5beb</code></a>
Encode exported instances with nested components (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/918">#918</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/37f63ebefb90b41c1c5757098fe93b192ec04139"><code>37f63eb</code></a>
wit-component: lazily allocate adapter stack when appropriate (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/919">#919</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/fc5ab6cd9165c50afdbb58bb1a65c0bc2cc3fd8c"><code>fc5ab6c</code></a>
Reduce the code size of some wasm-mutate functions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/917">#917</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/49d3adc05022aee0faa77eeca3bc3872c29fa7fd"><code>49d3adc</code></a>
Implement export type ascription (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/913">#913</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/02291c7a4ba43d3371072fb39908f1cca88e99a3"><code>02291c7</code></a>
Model types-in-worlds as imports (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/916">#916</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e34c72f8d95220ec1f4a8e189e3af615e9baccb7"><code>e34c72f</code></a>
Add a test suite for the <code>wasm-tools</code> CLI (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/915">#915</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/22c9e0f26240344aadcab7dcb5093f8f7d73780d"><code>22c9e0f</code></a>
Remove function-based subtyping (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/914">#914</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/098ad8230d10bb5e131b9c01a1883045ccbd083d"><code>098ad82</code></a>
Disable float types with <code>floats = false</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/912">#912</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/90e4d87beded25f7285aa9ec06e9d594e071d048"><code>90e4d87</code></a>
Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/907">#907</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.99.0...wasmparser-0.100.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-12 21:38:31 +01:00
dependabot[bot] 53f640af63 Update wasmparser requirement from 0.98 to 0.99 (#48)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/278c3ee93f0ebbcb7221b1410a402b62ae56c4ae"><code>278c3ee</code></a>
Bump versions of crates (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/891">#891</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a7c8b09391b70235bb539ec750aa90798ac1e1ec"><code>a7c8b09</code></a>
Fix a slew of fuzz bugs in wit-{parser,component} (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/886">#886</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/b7eb6aae41dfd7c76dec6f53923b8de4785f1af5"><code>b7eb6aa</code></a>
wasm-mutate: Add an &quot;AddCustomSection&quot; mutator (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/890">#890</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cacda73ccb6f9f8cc42e8391c77480187c99b48d"><code>cacda73</code></a>
Fix resolving memory names of <code>memory.discard</code> in text format
(<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/888">#888</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/8173865e15f7b259b92093cb283a40655565bbd4"><code>8173865</code></a>
<code>wasm-smith</code>: Add support for the Wasm tail calls proposal
(<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/887">#887</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/507c0541586ca4e4c88cf43c66210140e018b435"><code>507c054</code></a>
Fix references to imported types in the text format (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/885">#885</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e60c726ee5fafe0a62e18aa4f0924d1298140524"><code>e60c726</code></a>
Manually bump patch versions to move over yanks</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/ed2558cd7764061af02925f111fe762580cc9920"><code>ed2558c</code></a>
Bump versions for real</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/7d5843d19067625c79e8af6561dfe4609b0c6ac8"><code>7d5843d</code></a>
Revert &quot;Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/884">#884</a>)&quot;</li>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.98.0...wasmparser-0.99.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-25 19:00:34 -03:00
dependabot[bot] a667e38b5a Update wasmparser requirement from 0.97 to 0.98 (#47)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e60c726ee5fafe0a62e18aa4f0924d1298140524"><code>e60c726</code></a>
Manually bump patch versions to move over yanks</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/ed2558cd7764061af02925f111fe762580cc9920"><code>ed2558c</code></a>
Bump versions for real</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/7d5843d19067625c79e8af6561dfe4609b0c6ac8"><code>7d5843d</code></a>
Revert &quot;Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/884">#884</a>)&quot;</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/d23f487448e1f2f3545a36328d70021693d4400c"><code>d23f487</code></a>
Bump crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/884">#884</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/398b367f79a086a0b2f8fa0f71657d523c29d079"><code>398b367</code></a>
Add experimental memory.discard instruction (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/882">#882</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/9a51f6de46d29cbafd8cc3b3e50bd2447f7e7fb3"><code>9a51f6d</code></a>
VisitOperator: implement delegates for Box&lt;VisitOperator&gt; (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/883">#883</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/208b2e79fbc0ba0c9e63a9ea15e60fcec437b383"><code>208b2e7</code></a>
Fix some minor issues in <code>wit-component</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/881">#881</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/a1fdde03f81aa14709d73fb6ddde21b55d22177c"><code>a1fdde0</code></a>
VisitOperator: implement delegate from &amp;mut VisitOperator (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/880">#880</a>)</li>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.97.0...wasmparser-0.98.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 21:54:51 -03:00
dependabot[bot] b67ac31310 Update wasmparser requirement from 0.96 to 0.97 (#45)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/bytecodealliance/wasm-tools/commits">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-17 23:34:52 -03:00
dependabot[bot] bee3aebeef Update wasmi requirement from 0.21 to 0.22 (#44)
Updates the requirements on [wasmi](https://github.com/paritytech/wasmi)
to permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/releases">wasmi's
releases</a>.</em></p>
<blockquote>
<h2>v0.22.0 - 2023-01-16</h2>
<h3>Added</h3>
<ul>
<li>Add missing <code>TypedFunc::call_resumable</code> API. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/605">paritytech/wasmi#605</a>)
<ul>
<li>So far resumable calls were only available for the <code>Func</code>
type.
However, there was no technical reason why it was not implemented
for <code>TypedFunc</code> so this mirrored API now exists.</li>
<li>This also cleans up rough edges with the
<code>Func::call_resumable</code> API.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Clean up the <code>wasmi_core</code> crate API. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/607">paritytech/wasmi#607</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/608">paritytech/wasmi#608</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/609">paritytech/wasmi#609</a>)
<ul>
<li>This removes plenty of traits from the public interface of the crate
which greatly simplifies the API surface for users.</li>
<li>The <code>UntypedValue</code> type gained some new methods to
replace functionality
that was provided in parts by the removed traits.</li>
</ul>
</li>
<li>The <code>wasmi</code> crate now follows the Wasmtime API a bit more
closely. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/613">paritytech/wasmi#613</a>)</li>
</ul>
<h3>Internal</h3>
<ul>
<li>The <code>Store</code> and <code>Engine</code> types are better
decoupled from their generic parts. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/610">paritytech/wasmi#610</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/611">paritytech/wasmi#611</a>)
<ul>
<li>This might reduce binary bloat and may have positive effects on the
performance.
In fact we measured significant performance improvements on the Wasm
target.</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/blob/master/CHANGELOG.md">wasmi's
changelog</a>.</em></p>
<blockquote>
<h2>[<code>0.22.0</code>] - 2023-01-16</h2>
<h3>Added</h3>
<ul>
<li>Add missing <code>TypedFunc::call_resumable</code> API. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/605">paritytech/wasmi#605</a>)
<ul>
<li>So far resumable calls were only available for the <code>Func</code>
type.
However, there was no technical reason why it was not implemented
for <code>TypedFunc</code> so this mirrored API now exists.</li>
<li>This also cleans up rough edges with the
<code>Func::call_resumable</code> API.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Clean up the <code>wasmi_core</code> crate API. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/607">paritytech/wasmi#607</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/608">paritytech/wasmi#608</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/609">paritytech/wasmi#609</a>)
<ul>
<li>This removes plenty of traits from the public interface of the crate
which greatly simplifies the API surface for users.</li>
<li>The <code>UntypedValue</code> type gained some new methods to
replace functionality
that was provided in parts by the removed traits.</li>
</ul>
</li>
<li>The <code>wasmi</code> crate now follows the Wasmtime API a bit more
closely. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/613">paritytech/wasmi#613</a>)</li>
</ul>
<h3>Internal</h3>
<ul>
<li>The <code>Store</code> and <code>Engine</code> types are better
decoupled from their generic parts. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/610">paritytech/wasmi#610</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/611">paritytech/wasmi#611</a>)
<ul>
<li>This might reduce binary bloat and may have positive effects on the
performance.
In fact we measured significant performance improvements on the Wasm
target.</li>
</ul>
</li>
</ul>
<h2>[<code>0.21.0</code>] - 2023-01-04</h2>
<h3>Added</h3>
<ul>
<li>Add support for resumable function calls. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/598">paritytech/wasmi#598</a>)
<ul>
<li>This feature allows to resume a function call upon encountering a
host trap.</li>
</ul>
</li>
<li>Add support for concurrently running function executions using a
single <code>wasmi</code> engine.
<ul>
<li>This feature also allows to call Wasm functions from host functions.
(<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/590">paritytech/wasmi#590</a>)</li>
</ul>
</li>
<li>Add initial naive WASI support for <code>wasmi</code> using the new
<code>wasmi_wasi</code> crate. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/557">paritytech/wasmi#557</a>)
<ul>
<li>Special thanks to <a href="https://github.com/OLUWAMUYIWA">Onigbinde
Oluwamuyiwa Elijah</a> for carrying the WASI support efforts!</li>
<li>Also thanks to <a href="https://github.com/Berrysoft">Yuyi Wang</a>
for testing and improving initial WASI support. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/592">paritytech/wasmi#592</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/571">paritytech/wasmi#571</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/568">paritytech/wasmi#568</a>)</li>
<li><strong>Note:</strong> There is ongoing work to integrate WASI
support in <code>wasmi_cli</code> so that the <code>wasmi</code> CLI
will then
be able to execute arbitrary <code>wasm-wasi</code> files out of the box
in the future.</li>
</ul>
</li>
<li>Add <code>Module::imports</code> that allows to query Wasm module
imports. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/573">paritytech/wasmi#573</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/583">paritytech/wasmi#583</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix a bug that imported linear memories and tables were initialized
twice upon instantiation. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/593">paritytech/wasmi#593</a>)</li>
<li>The <code>wasmi</code> CLI now properly hints for file path
arguments. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/596">paritytech/wasmi#596</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>The <code>wasmi::Trap</code> type is now more similar to Wasmtime's
<code>Trap</code> type. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/559">paritytech/wasmi#559</a>)</li>
<li>The <code>wasmi::Store</code> type is now <code>Send</code> and
<code>Sync</code> as intended. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/566">paritytech/wasmi#566</a>)</li>
<li>The <code>wasmi</code> CLI now prints exported functions names if
the function name CLI argument is missing. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/579">paritytech/wasmi#579</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/paritytech/wasmi/commit/0bbb80cc8063ba7cb5a25f2047b21990564e87fe"><code>0bbb80c</code></a>
Prepare for release of <code>wasmi</code> <code>v0.22.0</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/614">#614</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/7c16e7793553a132b7d7b4f53fb20209eafeffa2"><code>7c16e77</code></a>
Mirror Wasmtime APIs more closely (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/613">#613</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/1a5891aa8716c4ffea01a98ca204267ae95d79c2"><code>1a5891a</code></a>
Add tests for <code>ComponentVec</code> data structure (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/612">#612</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/2d139d76ce48a01ef0cb69330dae97468ff6fda5"><code>2d139d7</code></a>
Make <code>Engine</code>'s executor use <code>&amp;mut StoreInner</code>
(making it non-generic) (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/611">#611</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/702cc6872aa19cd0067a18e5620ec05ca1dfdf73"><code>702cc68</code></a>
Create a non-generic <code>StoreInner</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/610">#610</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/cc05d72465cff368b2b09f76c84fe23bfa186b68"><code>cc05d72</code></a>
No longer re-export unused traits from <code>wasmi_core</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/609">#609</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/f4aabf3e10ffa72659b663e791f77fe39aa0c9ba"><code>f4aabf3</code></a>
Add Wasm load and store API to <code>UntypedValue</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/608">#608</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/d2069ce5378b931847b591fd1430dc8a0657eda7"><code>d2069ce</code></a>
Cleanup <code>wasmi_core</code> crate (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/607">#607</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/0d12bffda0bc22affc26d499f3bfbbd7be1f17f7"><code>0d12bff</code></a>
Refactor resumable function call tests (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/606">#606</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/7753fab3484678fed7ad72dd0005440987f610fa"><code>7753fab</code></a>
Implement resumable calls for <code>TypedFunc</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/605">#605</a>)</li>
<li>See full diff in <a
href="https://github.com/paritytech/wasmi/compare/v0.21.0...v0.22.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-17 06:43:26 -03:00
Alexander Theißen 74716698f5 Speedup CI (#43)
* No need to build on nightly: This crate works on stable
* Use larger runners where applicable (linux)
* Only run the tests on macOS and Windows: The rest is OS independent
2023-01-10 16:01:52 -03:00
dependabot[bot] 54213f77f6 Update wasmi requirement from 0.20 to 0.21 (#42)
Updates the requirements on [wasmi](https://github.com/paritytech/wasmi)
to permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/releases">wasmi's
releases</a>.</em></p>
<blockquote>
<h2>v0.21.0 - 2023-01-04</h2>
<h3>Added</h3>
<ul>
<li>Add support for resumable function calls. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/598">paritytech/wasmi#598</a>)
<ul>
<li>This feature allows to resume a function call upon encountering a
host trap.</li>
</ul>
</li>
<li>Add support for concurrently running function executions using a
single <code>wasmi</code> engine.
<ul>
<li>This feature also allows to call Wasm functions from host functions.
(<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/590">paritytech/wasmi#590</a>)</li>
</ul>
</li>
<li>Add initial naive WASI support for <code>wasmi</code> using the new
<code>wasmi_wasi</code> crate. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/557">paritytech/wasmi#557</a>)
<ul>
<li>Special thanks to <a href="https://github.com/OLUWAMUYIWA">Onigbinde
Oluwamuyiwa Elijah</a> for carrying the WASI support efforts!</li>
<li>Also thanks to <a href="https://github.com/Berrysoft">Yuyi Wang</a>
for testing and improving initial WASI support. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/592">paritytech/wasmi#592</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/571">paritytech/wasmi#571</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/568">paritytech/wasmi#568</a>)</li>
<li><strong>Note:</strong> There is ongoing work to integrate WASI
support in <code>wasmi_cli</code> so that the <code>wasmi</code> CLI
will then
be able to execute arbitrary <code>wasm-wasi</code> files out of the box
in the future.</li>
</ul>
</li>
<li>Add <code>Module::imports</code> that allows to query Wasm module
imports. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/573">paritytech/wasmi#573</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/583">paritytech/wasmi#583</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix a bug that imported linear memories and tables were initialized
twice upon instantiation. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/593">paritytech/wasmi#593</a>)</li>
<li>The <code>wasmi</code> CLI now properly hints for file path
arguments. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/596">paritytech/wasmi#596</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>The <code>wasmi::Trap</code> type is now more similar to Wasmtime's
<code>Trap</code> type. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/559">paritytech/wasmi#559</a>)</li>
<li>The <code>wasmi::Store</code> type is now <code>Send</code> and
<code>Sync</code> as intended. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/566">paritytech/wasmi#566</a>)</li>
<li>The <code>wasmi</code> CLI now prints exported functions names if
the function name CLI argument is missing. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/579">paritytech/wasmi#579</a>)</li>
<li>Improve feedback when running a Wasm module without exported
function using <code>wasmi</code> CLI. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/584">paritytech/wasmi#584</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/paritytech/wasmi/blob/master/CHANGELOG.md">wasmi's
changelog</a>.</em></p>
<blockquote>
<h2>[0.21.0] - 2023-01-04</h2>
<h3>Added</h3>
<ul>
<li>Add support for resumable function calls. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/598">paritytech/wasmi#598</a>)
<ul>
<li>This feature allows to resume a function call upon encountering a
host trap.</li>
</ul>
</li>
<li>Add support for concurrently running function executions using a
single <code>wasmi</code> engine.
<ul>
<li>This feature also allows to call Wasm functions from host functions.
(<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/590">paritytech/wasmi#590</a>)</li>
</ul>
</li>
<li>Add initial naive WASI support for <code>wasmi</code> using the new
<code>wasmi_wasi</code> crate. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/557">paritytech/wasmi#557</a>)
<ul>
<li>Special thanks to <a href="https://github.com/OLUWAMUYIWA">Onigbinde
Oluwamuyiwa Elijah</a> for carrying the WASI support efforts!</li>
<li>Also thanks to <a href="https://github.com/Berrysoft">Yuyi Wang</a>
for testing and improving initial WASI support. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/592">paritytech/wasmi#592</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/571">paritytech/wasmi#571</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/568">paritytech/wasmi#568</a>)</li>
<li><strong>Note:</strong> There is ongoing work to integrate WASI
support in <code>wasmi_cli</code> so that the <code>wasmi</code> CLI
will then
be able to execute arbitrary <code>wasm-wasi</code> files out of the box
in the future.</li>
</ul>
</li>
<li>Add <code>Module::imports</code> that allows to query Wasm module
imports. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/573">paritytech/wasmi#573</a>,
<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/583">paritytech/wasmi#583</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix a bug that imported linear memories and tables were initialized
twice upon instantiation. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/593">paritytech/wasmi#593</a>)</li>
<li>The <code>wasmi</code> CLI now properly hints for file path
arguments. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/596">paritytech/wasmi#596</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>The <code>wasmi::Trap</code> type is now more similar to Wasmtime's
<code>Trap</code> type. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/559">paritytech/wasmi#559</a>)</li>
<li>The <code>wasmi::Store</code> type is now <code>Send</code> and
<code>Sync</code> as intended. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/566">paritytech/wasmi#566</a>)</li>
<li>The <code>wasmi</code> CLI now prints exported functions names if
the function name CLI argument is missing. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/579">paritytech/wasmi#579</a>)</li>
<li>Improve feedback when running a Wasm module without exported
function using <code>wasmi</code> CLI. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/584">paritytech/wasmi#584</a>)</li>
</ul>
<h2>[0.20.0] - 2022-11-04</h2>
<h3>Added</h3>
<ul>
<li>Contribution documentation about fuzz testing. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/529">paritytech/wasmi#529</a>)</li>
</ul>
<h3>Removed</h3>
<ul>
<li>Removed some deprecated functions in the <code>wasmi_core</code>
crate. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/545">paritytech/wasmi#545</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed a critical performance regression introduced in Rust 1.65. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/518">paritytech/wasmi#518</a>)
<ul>
<li>While the PR's main job was to clean up some code it was found out
that it
also fixes a critical performance regression introduced in Rust
1.65.</li>
<li>You can read more about this performance regression <a
href="https://github-redirect.dependabot.com/rust-lang/rust/issues/102952">in
this thread</a>.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Fixed handling of edge cases with respect to Wasm linear memory. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/449">paritytech/wasmi#449</a>)
<ul>
<li>This allows for <code>wasmi</code> to properly setup and use linear
memory instances of up to 4GB.</li>
</ul>
</li>
<li>Optimize and improve Wasm instantiation. (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/531">paritytech/wasmi#531</a>)</li>
<li>Optimize <code>global.get</code> of immutable non-imported globals.
(<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/pull/533">paritytech/wasmi#533</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/paritytech/wasmi/commit/9e228e8a253074bf25cfcfeff11b07ff2033170e"><code>9e228e8</code></a>
Bump <code>wasmi</code> version to <code>0.21.0</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/604">#604</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/8fb3a58de76a10b0072d0c71fd1677a96f33009f"><code>8fb3a58</code></a>
Prepare for <code>wasmi</code> version <code>0.21.0</code> release (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/603">#603</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/829ae5b115e8d8f484c93798309ac9e1eb7351eb"><code>829ae5b</code></a>
Resumable Function Calls (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/598">#598</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/3c62031d096a73c59edb05ea5cc508e5bc65b0f6"><code>3c62031</code></a>
Add <code>res: EngineResources</code> field to
<code>EngineExecutor</code> (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/602">#602</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/bbcfc21deea430f82aac6c268ffea61587173060"><code>bbcfc21</code></a>
Refactor <code>Engine</code> internals (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/601">#601</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/3186c023210a537d0fd70517942a1ebd0c5ad3f7"><code>3186c02</code></a>
Return <code>()</code> from <code>CallResults</code> for slices (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/600">#600</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/8965c9af96beb189919c0a2aa306a8ae111141ad"><code>8965c9a</code></a>
Refactor FuncType verification (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/599">#599</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/2b5a48618fa9acb1d36e91ba9325623d6858e0e6"><code>2b5a486</code></a>
CLI: Improve CLI parsing (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/596">#596</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/da8e4a694054ea218b316c31f28aae5494a42119"><code>da8e4a6</code></a>
Allow host functions to call Wasm functions (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/590">#590</a>)</li>
<li><a
href="https://github.com/paritytech/wasmi/commit/f82ed77000b520046918b4e75cd733a2a7650d5b"><code>f82ed77</code></a>
Fix duplicated imported linear memories and tables (<a
href="https://github-redirect.dependabot.com/paritytech/wasmi/issues/593">#593</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/paritytech/wasmi/compare/v0.20.0...v0.21.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2023-01-10 15:04:05 -03:00
dependabot[bot] 23a2347f1f Update wasmparser requirement from 0.95 to 0.96 (#41)
Updates the requirements on
[wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit
the latest version.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/bd3208f0f30dff710e1c28e13a20cded24a38db5"><code>bd3208f</code></a>
Bump some crate versions (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/865">#865</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/6b965ce03b9fc8d3b94eb967eb50285f914ffd0b"><code>6b965ce</code></a>
Fix fuzzing errors (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/862">#862</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/cd44f7326316e652fc90778455a466bcb8272640"><code>cd44f73</code></a>
Consolidate list-reading functions into <code>read_iter</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/860">#860</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e59094c01101732edd757cedf39e7390013669de"><code>e59094c</code></a>
Implement infrastructure fro a <code>use</code> keyword in
<code>*.wit</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/858">#858</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/24d48083cea015bd62887f9b141caf7a18e5505e"><code>24d4808</code></a>
[wasmparser] Reduce the size of TypeId for better validation performance
(<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/844">#844</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/2de95fe4b749b175f4038006a32c2ecf33a66c5a"><code>2de95fe</code></a>
Cleanup skipping methods in <code>BinaryReader</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/861">#861</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/f234d0c9b531213f35e10177c8f2582c5f3ab58f"><code>f234d0c</code></a>
Remove a large amount of boilerplate parsing from
<code>wasmparser</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/857">#857</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/8e3f8d83fc6a67494374eda8925ed57811d786eb"><code>8e3f8d8</code></a>
Remove <code>deterministic</code> crate feature from `wasmparser (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/854">#854</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/4ac65e93fa1890c0749c2579e0dcbc2bffd7e4d1"><code>4ac65e9</code></a>
Add debug names to shim module in <code>wit-component</code> (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/853">#853</a>)</li>
<li><a
href="https://github.com/bytecodealliance/wasm-tools/commit/e5ffae8f4d30ba7e25922209268d31dc18bcedfd"><code>e5ffae8</code></a>
wasmparser: split parsers for different elems (<a
href="https://github-redirect.dependabot.com/bytecodealliance/wasm-tools/issues/849">#849</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.95.0...wasmparser-0.96.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-15 15:12:07 +01:00
Sasha Gryaznov 54c4f8f878 Patch: use checked sum for locals counter (#40)
follow-up patch to #38

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2022-12-08 11:58:02 +01:00
Sasha Gryaznov 6a79d1d4b8 Charge gas for local variables on the callee side (#38)
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2022-11-26 16:37:31 +01:00
dependabot[bot] b51701088e Update wasmparser requirement from 0.94 to 0.95 (#37)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.94.0...wasmparser-0.95.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-23 00:35:05 +01:00
Sasha Gryaznov a4dde28607 Add new gas metering method: mutable global + local gas function (#34)
* fix misprints in doc comments

* added global gas tracker variable and local gas fn

* all exported functions of the module to accept a new param and to set the gas_left global to its value at their very start

* make module support both gas metering methods

* tests fixed for the old metering method

* better naming

* MutableGlobal metering method implemented, tests for the old method pass

* gas_metering::tests updated and pass

* all tests udpdated and pass

* emacs backup files to .gitignore

* docs updated

* clippy fix

* iff = if and only if

* more clippy

* docs misprints fixes

* refactored to have Backend trait and two implementations in separate sub-modules

* docs updated

* fixed old benches (updating them is coming next)

* added bench for an instrumented wasm-coremark

* updated benches: added them for both gas_metering instrumentations

* benches contest first ver

* added debug prints to the bench

* refactored to better fit frontend-backend pattern

* docs update

* updated benches

* design updated on feedback

* re-structured sub-modules

re-structured sub-modules & updated docs

* docs improved

* addressed latest feedback comments

* re-writed the local gas function

* coremark benches show ~20% performance improvement

* fix ci: test + clippy

* save before re-factoring prepare_in_wasm()

* bare_call_16 shows 16% worse perf

* + fibonacci recursive bench

* refactored benchmarks

* + factorial recursive bench

* benches on wasmi fixtures show no perf improvement, coremark runs ~20% faster being instrumented with mutable_global gas metering

* charge gas for local gas func isntructions execution

* replaced benchmark which requires multi_value feature

* save: optimized gas func a bit (benches work, fixture tests fail)

* 1033% overhead on many_blocks.wasm when mut_global gas_metering together with stack_height

* size overhead test for both gas metering methods + stack limiter

* added more benches

* improved print_size_overhead test

* test for comparing size overheads of two gas_metering injectors

* before optimization: benches + size overhead

* optimization try-1: inline part of gas func instructions: +benches +size overheads

* optimization try-2: inline hot path of gas fn:  +benches +size overheads

* opt try-3: count for gas fn cost on the caller side: +benches +size overhead

* revert to initial version but with static gas fn cost on the caller side: +benches +sizes

* tests fixed

* use newest wasmi 0.20: +benches +docs updated

* use if-else block instead of Return: +benches

* fix tests

* clippy fix

* addressed review comments

* Update changelog

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2022-11-20 15:00:10 +01:00
dependabot[bot] 90cb67d5d7 Update wasmparser requirement from 0.92 to 0.94 (#36)
* Update wasmparser requirement from 0.92 to 0.94

Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.92.0...wasmparser-0.94.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix whitespace differences in tests

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2022-11-10 09:35:58 +01:00
dependabot[bot] 4c1d47a618 Update wasmparser requirement from 0.90 to 0.92 (#33)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.90.0...wasmparser-0.92.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-10 11:22:57 +02:00
dependabot[bot] 840af19d4b Update criterion requirement from 0.3 to 0.4 (#31)
Updates the requirements on [criterion](https://github.com/bheisler/criterion.rs) to permit the latest version.
- [Release notes](https://github.com/bheisler/criterion.rs/releases)
- [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bheisler/criterion.rs/compare/0.3.0...0.4.0)

---
updated-dependencies:
- dependency-name: criterion
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-14 12:00:09 +02:00
Alexander Theißen 0229f865b6 Use u64 for gas counter (#30)
* Use `u64` for gas counter

* Update doc
2022-09-11 14:36:06 +02:00
dependabot[bot] c2db4b8365 Update wasmparser requirement from 0.89 to 0.90 (#28)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.89.0...wasmparser-0.90.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-24 08:59:46 +02:00
dependabot[bot] 1ade161da4 Update wasmparser requirement from 0.88 to 0.89 (#27)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.88.0...wasmparser-0.89.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-17 14:08:30 +02:00
dependabot[bot] 25ff883bbd Update wasmparser requirement from 0.87 to 0.88 (#26)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.87.0...wasmparser-0.88.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-30 17:39:07 +02:00
dependabot[bot] 3b932b11ad Update wasmparser requirement from 0.86 to 0.87 (#24)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.86.0...wasmparser-0.87.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-06 11:21:44 +02:00
Alexander Theißen d10bbdf554 Fix CODEOWNERS 2022-06-21 14:21:59 +02:00
dependabot[bot] 28ef7f550c Update wasmparser requirement from 0.84 to 0.86 (#23)
Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.84.0...wasmparser-0.86.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-12 20:24:01 +01:00
Filipe Azevedo 4a394c5f88 bump version (#22) 2022-06-08 10:29:51 +02:00
Alexander Theißen d1648be274 Fix publish 2022-06-06 16:16:30 +01:00
Filipe Azevedo 4a51f16874 handle debug info (#16) 2022-06-06 15:42:52 +01:00
dependabot[bot] 8380823e62 Bump actions/checkout from 2 to 3 (#19)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-06 11:53:30 +03:00
Sergejs Kostjucenko 88d652e69a add gha to dependabot (#18) 2022-06-02 19:23:10 +03:00
dependabot[bot] 4713aa760f Update wasmparser requirement from 0.82 to 0.84 (#10)
* Update wasmparser requirement from 0.82 to 0.84

Updates the requirements on [wasmparser](https://github.com/bytecodealliance/wasm-tools) to permit the latest version.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/wasmparser-0.82.0...wasmparser-0.84.0)

---
updated-dependencies:
- dependency-name: wasmparser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Adapt tests to new wasmparser

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2022-04-07 15:50:15 +02:00
Alexander Theißen 4548a86329 Add test to measure size overhead (#8)
* Don't use parity-wasm directly

* Add test that output size over head of metering
2022-01-31 14:50:32 +01:00
Alexander Theißen ff68bee449 We should use bench_with_input so that a blackbox is used 2022-01-31 13:14:12 +01:00
Alexander Theißen 7c843842a7 Run CI on windows, too (#7)
* Run CI on windows, too

* Build path without `concat!` macro

* Fix ci on windows
2022-01-31 11:03:18 +01:00
Alexander Theißen 374afe5700 Replace wabt with rust tools (#5) 2022-01-30 13:05:07 +01:00
Alexander Theißen 8291876394 Add benchmarks and add tiny performance improvements (#6)
* Add some benchmarks

* Replace extend -> extend_from_slice (1-2% performance improvement)

* Add many_blocks benchmarks
2022-01-24 21:20:47 +01:00
Alexander Theißen 184b3f8b3a Prepare for releasing v0.1.1 2022-01-18 18:28:07 +01:00
Alexander Theißen 57da96fb50 Consider activation frame for stack height metering (#2)
* Charge a base cost for calling a function

* Added regression test for empty functions

* Satisfy clippy
2022-01-18 18:04:17 +01:00
Alexander Theißen 4e3e6b598a Added documentation link 2022-01-11 21:46:18 +02:00
Alexander Theißen c5eaffd229 Fix README typo 2022-01-11 21:37:12 +02:00
Alexander Theißen e882111f92 Remove everything not needed by substrate
Also rename to wasm-instrument
2022-01-11 17:50:24 +02:00
Leonardo Yvens b22696aaa5 sign_ext feature flag (#174)
* sign_ext feature flag

* Derive default to fix clippy warning
2021-12-21 15:23:16 +01:00
Dan Shields 5259f1c922 Merge pull request #173 from paritytech/NukeManDan-patch-1
version 0.19.0
rust 2021
MSRV 1.56.1
2021-11-21 16:01:06 -07:00
Dan Shields da2f0a0f23 version 0.19.0
edition = "2021"
rust-version = "1.56.1"
2021-11-20 23:46:06 -07:00
Keith Yeung 1d62dc1270 cargo fmt 2021-11-13 19:05:45 -08:00
Dan Shields abd5d4f6df move to rust 2021 2021-11-13 19:59:13 -07:00
Sergei Shulepov c9b837c80a Merge pull request #171 from paritytech/at-bump-version
Bump version and only include essential files in crate
2021-09-08 14:17:45 +02:00
Alexander Theißen 2bf8068571 Bump version and only include essential files in crate 2021-09-07 17:55:50 +02:00
Alexander Theißen 2293760964 Use linear time algorithm to inject stack height metering (#170) 2021-09-07 17:42:03 +02:00
Alexander Theißen 2f88f49ef6 Add test for empty loops (#169) 2021-09-06 16:25:50 +02:00
Alexander Theißen 6ff274f0b8 Add CODEOWNERS (#167) 2021-08-02 12:54:10 +03:00
Chevdor 3d3e3010b3 Add justfile (#166) 2021-07-28 16:29:33 +02:00
Chevdor ef4e09fff9 Typo and minor fixes (#165) 2021-07-28 16:28:25 +02:00
Chevdor b8b18be419 Fix linting related issues (#164) 2021-07-27 16:14:14 +02:00
Alexander Theißen 72626a566a Add a clippy job to the CI (#163)
* Add clippy CI check

* Fix remaining clippy lints

* Cargo fmt
2021-07-27 15:50:50 +02:00
dependabot[bot] b8e6b9e319 Update env_logger requirement from 0.8 to 0.9 (#159)
Updates the requirements on [env_logger](https://github.com/env-logger-rs/env_logger) to permit the latest version.
- [Release notes](https://github.com/env-logger-rs/env_logger/releases)
- [Changelog](https://github.com/env-logger-rs/env_logger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/env-logger-rs/env_logger/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: env_logger
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-27 15:38:59 +02:00
Chevdor cb023973e8 Cleanup (#162)
* Remove unnecessary references

* Shorten expressions

* Remove unnecessary reference

* Simplify expression

* Fix formatting
2021-07-27 15:14:55 +02:00
Alexander Theißen a0b548b37d Add rustfmt.toml from substrate repo (#161)
* Add rustfmt.toml from substrate repo

* Apply rustfmt to code base

* Fix formatting

* Move rustfmt job to the top
2021-07-27 14:46:28 +02:00
Alexander Theißen 77ad07e347 Add github actions (#160)
* Add github actions

* s/toolchains/toolchain

* s/test/build

* Remove no longer need travis
2021-07-27 13:59:16 +02:00
Alexander Theißen c5043a47ac Add dependabot (#158) 2021-07-27 12:06:17 +02:00
NikVolf 9f15b8cd21 bump to 0.18.1 2021-06-10 14:31:47 +03:00
Nikolay Volf 1ef05d71ed Strip custom sections in wasm-prune (#150)
* strip custom sections

* line width
2021-06-10 14:29:59 +03:00
Sergei Shulepov 0cead7ba6d Merge pull request #151 from paritytech/ser-bless
Add BLESS env option
2021-06-10 11:13:04 +02:00
Sergei Shulepov e1c8ce90a1 Merge pull request #152 from paritytech/ser-fix-locals
Fix counting of the local variables
2021-06-10 10:49:36 +02:00
Sergei Shulepov 9e98400de0 Update tests/diff.rs
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2021-06-10 10:49:16 +02:00
Sergey Shulepov 19760b5835 Fix counting of the local variables
The code assumed that the number of `Local` and number of locals is the
same thing. In reality though it is not. `Local` actually represents a
group of locals with the same type. The group can declare more than one
variable and the number of them is returned by `Local::count`.

In this PR we acknowledge this fact. Along the way we add a checked
arithmetic for locals_count and max_stack_height summation.
2021-06-09 19:22:40 +02:00
Sergey Shulepov 717aa8f0cb Add BLESS env option
Right now if there is a diff between the actual and expected results,
the expected file will be overwritten. This may be annoying. To make it
controlled we introduce BLESS option.

This means that the expected files won't be regenerated unless this
environment variable is set.

Therefore to regenerate the tests use:

    BLESS=1 cargo test
2021-06-09 19:17:54 +02:00
Sergei Shulepov d891cddcb3 Merge pull request #149 from paritytech/at-export-parity-wasm
Export the complete `parity-wasm` crate
2021-05-27 12:18:15 +02:00
Alexander Theißen 95a711bc33 Re-export the whole parity_wasm crate 2021-05-26 15:10:15 +02:00
Alexander Theißen 1b0ed1b383 Transition to Rust 2018 style imports 2021-05-26 14:59:04 +02:00
Sergei Shulepov ca45220af5 Merge pull request #148 from paritytech/at-update-deps
Update dependencies
2021-04-22 12:42:51 +03:00
Alexander Theißen 2d1f4daed7 Update dependencies 2021-04-22 09:08:41 +02:00
Alexander Theißen ad01d9b41c Bump to 0.17.1 2021-04-21 14:12:12 +02:00
Alexander Theißen b2272f39bc stack_height: if instruction should pop one value from the stack (#147)
* stack_height: 'if' instruction should pop one value from the stack

* Fix indentation
2021-04-21 14:08:50 +02:00
Alexander Theißen d9432bafa9 Bump to 0.17 2020-12-12 18:45:19 +01:00
Alexander Theißen 1131240d39 Export parity_wasm::Instruction
We should export it because it is used in a public interface.
Otherwise every crate that depends on this needs to also
directly depend on parity_wasm.
2020-12-12 17:59:47 +01:00
Alexander Theißen 988ac32095 De-Bumo to 0.16.1
Last PR did not contain any change to an interface.
2020-12-10 10:53:30 +01:00
Sergei Shulepov 712c696c2d Merge pull request #145 from paritytech/cmichi-upgrade-to-parity-wasm-0.42.1
Upgrade to `parity-wasm` 0.42.1
2020-12-09 12:23:11 +01:00
Michael Mueller 9a0f992cb3 Use results length as arity 2020-12-08 17:24:59 +01:00
Michael Mueller d6127afd1d Upgrade to parity-wasm v0.42.1 2020-12-08 16:51:55 +01:00
Alexander Theißen 7da376062a bump to 0.16 2020-10-22 16:12:22 +02:00
Sergei Shulepov 3ab49836be Merge pull request #144 from paritytech/at-unify-packet
Merge pwasm-utils-cli into the main package
2020-10-22 14:34:09 +02:00
Alexander Theißen 2430b18633 Make feature "std" a requirement for the "cli" feature 2020-10-22 12:27:31 +02:00
Alexander Theißen aebfc0fbd7 Fixes necessary for having no_std imports work with edition2018 2020-10-22 12:26:24 +02:00
Alexander Theißen a2653cff5a Update CI script 2020-10-22 10:26:26 +02:00
Alexander Theißen 3142a74de2 Update README.md to reflect the new package unification 2020-10-21 20:49:34 +02:00
Alexander Theißen f556bde4a4 Ignore .vscode directory 2020-10-21 20:26:22 +02:00
Alexander Theißen f05f43b883 Unify pwasm-utils and pwasm-utils-cli packet 2020-10-21 20:24:49 +02:00
Alexander Theißen af761da031 Add repository metadata to Cargo.toml files 2020-10-21 11:37:30 +02:00
Alexander Theißen fbaae277fc bump to 0.15 2020-10-21 11:17:15 +02:00
Sergei Shulepov e0a05c6329 Merge pull request #143 from paritytech/at-instruction-costs
Make the rules passed to gas metering injection generic
2020-10-14 14:55:58 +02:00
Alexander Theißen e0dbaef676 Wrapped overlong line 2020-10-14 14:17:12 +02:00
Alexander Theißen 880d273861 Make the rules passed to gas metering injection generic 2020-10-14 13:26:48 +02:00
Sergei Shulepov 3568667ecb Merge pull request #142 from paritytech/at-cleanup
Address all clippy lints
2020-10-13 16:24:53 +02:00
Alexander Theißen c09a924a81 Address all clippy lints
These changes do not change the behaviour of the
code and should be non-controversial.
2020-10-13 15:42:01 +02:00
Sergei Shulepov f59eb121e5 Merge pull request #141 from paritytech/at-fixes
Fix issues with the stack height metering
2020-10-13 13:51:51 +02:00
Alexander Theißen 1f8e6dd5b2 Don't generate duplicate thunks
Previously, functions that appear in multiple places
(exported, start function, table) would generate a thunk
for each place they appear in. Those additional thunks are
identical and only only one of them would be referenced.
Main offender are tables with redundant entries.

This commit eliminates those duplicate thunks without adding
any additional overhead.
2020-10-13 11:43:59 +02:00
Alexander Theißen 5e3b06de05 Fix Instruction::CallIndirect stack height metering
The stack height metering for functions containing
CallIndirect was wrong. The code did not take into
consideration that is pops one value from the stack.

The effect was that the stack height of functions
using this instruction was higher than its real height.
2020-10-13 11:43:59 +02:00
Alexander Theißen 2306999c9c Fix using Write::write without checking the return value
Use write_all instead which garantues that the whole buffer
was written.
2020-10-13 11:43:40 +02:00
NikVolf 016425a25b bump to 0.14 2020-08-04 13:54:57 +03:00
Alexander Theißen 409ced002a Allow specifying the module of the imported 'gas' function (#140)
* No need for mem::replace when doing a simple assignment

* Allow specifying the module of the imported 'gas' function

This allows users to place the imported function inside a custom
module instead of the generic 'env' module.
2020-08-04 13:53:53 +03:00
NikVolf b61f6dd52f bump to 0.13 2020-08-03 14:59:57 +03:00
Nikolay Volf e026abe166 Export internal globals instrumentation (#138)
* export internal globals

* add test

* Update src/export_globals.rs

Co-authored-by: Sergei Shulepov <sergei@parity.io>

* address review

Co-authored-by: Sergei Shulepov <sergei@parity.io>
2020-08-03 14:58:24 +03:00
Nikolay Volf 8c6dec11a4 Merge pull request #139 from paritytech/update-wabt
Update wabt to 0.10
2020-08-03 14:20:20 +03:00
NikVolf 3f2935df9c update wabt 2020-08-03 14:00:07 +03:00
Nikolay Volf dcf189b822 Merge pull request #135 from osolmaz/correct-spelling
Corrected spelling error
2020-07-29 16:05:53 +03:00
Sergei Shulepov 19b5fb50cb Merge pull request #137 from osolmaz/correct-instruction-type
Corrected InstructionType's for GetGlobal and SetGlobal
2020-07-27 22:26:16 +02:00
Onur Solmaz 1e8953a9cb Corrected InstructionType's for GetGlobal and SetGlobal 2020-07-27 13:56:53 +02:00
Onur Solmaz 377684f9c7 Corrected spelling error 2020-07-23 20:08:03 +02:00
Nikolay Volf e89abb0c17 Merge pull request #134 from bddap/bddap-nostd-on-stable
Bump 'parity-wasm' version to enable no_std builds on stable.
2019-11-01 16:36:11 +03:00
Andrew Dirksen e6336a4a90 Travis-ci was configured to build with no_std only when using rust nightly.
This commit tells travis to attempt no_std builds for both nightly and stable.
2019-10-31 16:56:11 -07:00
Andrew Dirksen a881cf12bb Bump 'parity-wasm' version to enable no_std builds on stable.
Bump own version in preparation for cargo publish.
Bump cli verion to match.
2019-10-31 15:52:09 -07:00
NikVolf 2fe761f8c4 bump cli to 0.11 as well 2019-09-09 16:58:21 +03:00
Sergey Pepyakin 87761dad61 Bump pwasm-utils 2019-09-05 22:58:03 +02:00
Sergei Pepyakin a768692bbe Merge pull request #133 from paritytech/bump-parity-wasm
Bump parity-wasm to latest version
2019-09-05 22:50:02 +02:00
Demi M. Obenour ea4cde0e7d Bump parity-wasm to latest version
to allow Substrate to do the same
2019-09-04 18:14:10 -04:00
NikVolf f9d8b722b5 bump to 0.10 2019-08-29 18:57:46 +03:00
Nikolay Volf 39f234e441 Merge pull request #129 from oscoin/fix-pwasm
Preserve "deploy" when optimizing pwasm ctor module
2019-08-29 18:57:00 +03:00
Thomas Scholtes b4f9be733d Preserve "deploy" when optimizing pwasm ctor module
When optimizing the constructor module for a PWasm contract the "deploy" symbol is preserved instead of the "call"
symbol. Before this change `build` would error for PWasm contracts because `pack_instance` would not find the "deploy"
symbol in the optimized contract.

Fixes #128
2019-08-29 16:27:48 +02:00
NikVolf 155c7253c3 bump to 0.9 2019-08-02 15:21:44 +03:00
Nikolay Volf c9cdef4c51 Merge pull request #126 from paritytech/ser-update-pwasm
Update parity-wasm to 0.39
2019-08-02 15:20:32 +03:00
Sergey Pepyakin 2b5026a6c5 Add notice about parity-wasm features 2019-07-30 16:48:58 +02:00
Sergey Pepyakin a774a2cb29 Update parity-wasm to 0.39 2019-07-30 16:44:05 +02:00
Sergei Pepyakin 6fd636a41d Merge pull request #125 from jimpo/gas-fuzzing
Validate the gas metering algorithm using fuzzer.
2019-07-30 13:04:51 +02:00
Jim Posen 5792da28d5 Fix typo
Co-Authored-By: Sergei Pepyakin <s.pepyakin@gmail.com>
2019-07-25 12:37:57 +02:00
Jim Posen f8673d5b87 Fix dev dependency crate imports. 2019-07-25 11:05:25 +02:00
Jim Posen 5180d694ce Validate the gas metering algorithm using fuzzer. 2019-07-19 11:25:54 +02:00
NikVolf a150df8703 bump to 0.8.1 2019-07-17 18:40:00 +03:00
Sergei Pepyakin ae412c45f1 Merge pull request #124 from paritytech/fix-warnings
Fix warnings
2019-07-17 17:22:31 +03:00
Nikolay Volf 6f46ef5211 Update README.md 2019-07-17 17:02:55 +03:00
NikVolf 026b0502bb fix warnings 2019-07-17 17:01:15 +03:00
NikVolf 2c173fee26 bump to 0.8.0 due to change in gas counting 2019-07-17 16:57:28 +03:00
Sergei Pepyakin 0870ce6646 Merge pull request #122 from jimpo/basic-block
Rewrite gas metering algorithm to handle branches
2019-07-17 16:19:52 +03:00
Jim Posen 82bd972333 !fixup lowest_forward_br rename and field docs. 2019-07-12 10:45:01 +02:00
Jim Posen 93abbcfe56 Add gas injection unit test for correct else behavior. 2019-07-12 10:30:11 +02:00
Jim Posen ed7f31ec20 Use macro + WAT to make gas injection unit tests more readable. 2019-07-12 10:15:37 +02:00
Jim Posen b5472bcd8f !fixup Address review comments. 2019-07-11 16:45:46 +02:00
Jim Posen b3f8f62105 Update gas expectations. 2019-07-04 17:57:40 +02:00
Jim Posen 0cf7daa9e5 Update high level inject_gas_counter function documentation. 2019-07-04 17:57:40 +02:00
Jim Posen 24924f59ec Change gas metering injection code to handle branches properly. 2019-07-04 17:57:40 +02:00
Jim Posen de60f491b4 Fix ordering of actual and expected arguments in assert_eq!. 2019-07-04 17:57:40 +02:00
Jim Posen 4c0f42c6fc Perform gas metering injection step in linear time.
Previously the code was quadratic in the worst case as inserting into
the middle of a vector is a linear-time operation.
2019-07-04 17:57:40 +02:00
Jim Posen c3d10a2619 Merge pull request #121 from jimpo/gas-docs
Documentation of gas metering instrumentation process & cleanup.
2019-07-01 17:25:45 +02:00
Jim Posen 863744b1fc Add gas test confirming that br instructions do not end blocks. 2019-07-01 17:02:21 +02:00
Jim Posen 89e13ee901 Cleanup stack height Context.
Removes unnecessary Options and fixes typos.
2019-06-26 12:48:51 +02:00
Jim Posen 929e0ec2c0 Documentation of gas metering instrumentation process. 2019-06-26 12:47:30 +02:00
Nikolay Volf f6a1a6a066 Merge pull request #118 from paritytech/idents
Fix identation
2019-04-10 07:59:26 +03:00
NikVolf 0d40703c6e fix identation 2019-04-09 19:02:07 +03:00
NikVolf 124de6c2db update dependency 2019-04-09 18:57:16 +03:00
NikVolf 5a617c3aae bump cli to 0.7 2019-04-09 18:56:54 +03:00
NikVolf 80ea6ec7ad bump to 0.7.0 2019-04-09 18:56:32 +03:00
Sergei Pepyakin bbcc495ccc Merge pull request #116 from paritytech/small-tests
A couple of small tests.
2019-04-03 14:43:29 +02:00
Sergey Pepyakin 1b7a5d26ea A couple of small tests. 2019-04-03 14:24:01 +02:00
Nikolay Volf b1fbd2921e Merge pull request #115 from holygits/add-clap-version
Fix '-V/--version' output [EOM]
2019-02-27 10:33:52 +08:00
holygits 1e68a862f8 Fix '-V/--version' output 2019-02-26 16:43:33 +13:00
Nikolay Volf 466f5cceba Merge pull request #107 from paritytech/graph
Higher level wasm representation
2019-01-29 17:14:54 +03:00
NikVolf 38e0f254b0 use indoc! 2019-01-27 12:15:38 +03:00
NikVolf 5b2cd9c4c6 add example 2019-01-24 16:21:52 +03:00
NikVolf ad83ad17ee avoid panic when generating format 2019-01-24 16:10:39 +03:00
NikVolf 91036c0aff avoid panics when creating representation 2019-01-24 16:04:00 +03:00
NikVolf 728c935367 alter some tests to show correspondence 2019-01-24 15:36:09 +03:00
NikVolf 33785674dc simplify code 2019-01-24 15:32:14 +03:00
NikVolf 3e635514e4 some reformatting 2019-01-24 15:26:17 +03:00
NikVolf d8428327d5 simpler imports 2019-01-24 15:18:16 +03:00
NikVolf d695703146 more complicated opt and delete tests 2019-01-24 15:07:57 +03:00
NikVolf cda99e70da add much more complicated assertion 2019-01-24 14:42:53 +03:00
NikVolf 0a78a1ab8d complicate test 2019-01-24 14:35:05 +03:00
NikVolf 33c84edd78 Merge remote-tracking branch 'origin/master' into graph
# Conflicts:
#	src/lib.rs
2019-01-24 12:38:35 +03:00
NikVolf 8413e562cd more insert api and graph module logic upon 2019-01-24 12:37:03 +03:00
NikVolf 1bc4973e6e insert api in ref_list 2019-01-24 12:05:20 +03:00
Sergei Pepyakin 8ecbc8ddcc Merge pull request #114 from paritytech/ret
"return_ "-> "ret" in public api
2019-01-24 09:54:46 +01:00
NikVolf 56464c102f return_ -> ret 2019-01-24 11:20:31 +03:00
Nikolay Volf 6046e94b40 Merge pull request #113 from holygits/fix/preserve-optimize
Preserve deploy symbol on optimize for substrate target
2019-01-24 11:15:30 +03:00
holygits ec206fca64 Preserve deploy symbol on optimize for substrate target 2019-01-24 15:46:01 +13:00
Sergei Pepyakin 59384e09d0 Merge pull request #109 from holygits/fix/108
Preserve 'deploy' export for Substrate binaries
2019-01-23 22:21:17 +01:00
holygits 4f81bbc506 Don't pack Substrate ctor module 2019-01-24 10:18:18 +13:00
NikVolf f5890c2c7b more complex test 2019-01-23 15:01:08 +03:00
NikVolf 7504381419 fix linking for elements 2019-01-23 14:44:32 +03:00
NikVolf bb9832dba1 more docs and warnings 2019-01-23 13:57:26 +03:00
NikVolf 62ea903c3a add some docs 2019-01-23 13:47:44 +03:00
holygits c47adc1bd4 Refactor TargetRuntime as enum
Don't rename create symbol for substrate binaries
2019-01-23 17:03:53 +13:00
NikVolf c3833efca7 fix for nightly 2019-01-22 20:39:51 +03:00
NikVolf 4e871c65e2 generate instructions on module generation 2019-01-22 20:37:36 +03:00
NikVolf 48c1c6e72a code mapping 2019-01-22 20:30:50 +03:00
NikVolf d60340762b public api exposure and fix warnings 2019-01-22 18:28:15 +03:00
NikVolf da5b2ca5f6 rest of sections generation 2019-01-22 18:21:30 +03:00
NikVolf c520d334cd ordering and filtering 2019-01-22 17:14:37 +03:00
NikVolf 76b6743c64 generation of more sections 2019-01-22 16:40:28 +03:00
NikVolf d6c6cefcf1 generation - import 2019-01-22 16:11:04 +03:00
NikVolf 86da6439d1 data and elements 2019-01-22 15:15:17 +03:00
NikVolf ed1c7b1b51 better exports 2019-01-22 14:42:57 +03:00
NikVolf cf10b7d5d9 exports and fix for no-std 2019-01-22 14:31:21 +03:00
NikVolf dd9169e30f table and memory 2019-01-22 13:03:11 +03:00
NikVolf be40285a67 func and tests 2019-01-22 12:58:29 +03:00
NikVolf ba45e15567 remove unused 2019-01-22 12:39:09 +03:00
NikVolf 33ff0cbe1d refactor to reflist 2019-01-22 12:19:29 +03:00
NikVolf db4070b96c ref list impl 2019-01-22 12:08:25 +03:00
NikVolf 80d80a37d9 import rewiring 2019-01-21 17:56:30 +03:00
NikVolf 06277915da some graph structure definition 2019-01-21 17:04:31 +03:00
NikVolf 7c7a0713fc bump to 0.6.2 2019-01-15 14:18:45 +03:00
Nikolay Volf 31e3324015 Merge pull request #104 from laizy/master
rewire corresponding indices in name section
2019-01-15 14:17:13 +03:00
laizy dc993bdb1b rewire corresponding indices in name section 2019-01-13 09:53:59 +08:00
Sergey Pepyakin b58e01ec67 Bump version to 0.6.1 2019-01-04 14:38:08 +01:00
Sergey Pepyakin 8db40174ae Add gas tests. 2018-12-24 20:43:23 +01:00
Sergey Pepyakin 471a9b3fcc Account start function in gas func patching. 2018-12-24 19:28:53 +01:00
Sergey Pepyakin 3db0d60e70 Teach stack limiter to handle start fn 2018-12-24 19:20:33 +01:00
NikVolf fe25beca2b bump all to 0.6 2018-09-30 19:02:14 +01:00
Nikolay Volf 24b97b517a Merge pull request #102 from paritytech/ser-introduce-substrate-contracts
Introduce substrate contracts support.
2018-09-30 19:00:44 +01:00
Sergey Pepyakin 836ec93008 Introduce substrate contracts support. 2018-09-30 18:24:36 +01:00
NikVolf 5238b41af2 bump cli to 0.4.1 2018-08-06 16:51:35 +03:00
Nikolay Volf 19ce379f64 Merge pull request #101 from paritytech/fix-output
Fix not saving raw module when no constructor specified
2018-08-06 16:50:57 +03:00
NikVolf a9f5058b4f fix not saving raw module when no constructor specified 2018-08-06 16:09:11 +03:00
NikVolf 4b8b07a0b5 bump versions 2018-08-06 15:43:46 +03:00
Nikolay Volf 67d67f3fba Merge pull request #100 from paritytech/no-constructor
The constructor arg removed from
2018-08-06 15:40:04 +03:00
fro 3a7f8836dd the constructor arg removed from 2018-08-06 15:19:01 +03:00
NikVolf abb5ae6f22 bump cli to 0.3.0 2018-08-03 14:11:29 +03:00
NikVolf 9d0ad5b309 bump to 0.4.0 2018-08-03 14:10:51 +03:00
NikVolf 6c510a7f35 bump to 0.3.2 2018-08-01 17:29:42 +03:00
Alexey e491789127 Move build logic to lib (#97)
* refactored out build to lib

* save_raw returns

* fix indentations and other small fixes

* fix build API

* rename Target to SourceTarget

* fix formatting

* make join runtime_type into runtime_type and runtime_version
2018-08-01 17:26:22 +03:00
Alexey 3e7946ab1c fix call_indirect test (#98)
Merged
2018-08-01 13:48:38 +03:00
Nikolay Volf 41839664bb wasm-check utility (#94)
* wasm-check utility

* more runtime externs

* couple more imports
2018-07-12 18:49:09 +03:00
NikVolf 735110e8d5 bump to 0.3.1 2018-07-09 18:31:58 +03:00
Nikolay Volf 0fe96ee497 Merge pull request #93 from paritytech/fix-nightly
Fix nightly compilation
2018-07-09 18:31:20 +03:00
NikVolf 0837464ec4 change imports 2018-07-09 17:44:04 +03:00
NikVolf 7366384861 bump to lib to 0.3 and cli to 0.2 2018-07-04 12:17:42 +03:00
Sergey Pepyakin db80363d56 Merge pull request #91 from paritytech/bump-version-0.2.2
Bump version up to 0.2.2
2018-07-02 16:39:06 +03:00
Sergey Pepyakin bbb6c6078a Bump version up to 0.2.2. 2018-07-02 15:21:37 +03:00
Nikolay Volf f7e71718a4 Merge pull request #90 from paritytech/parity-wasm-bump
Update parity-wasm dependency to 0.31
2018-06-29 17:23:11 +03:00
Wei Tang af2d61b9f8 Fix tests and cli 2018-06-29 19:06:33 +08:00
Wei Tang d6f82000ee Update parity-wasm dependency to 0.31 2018-06-29 19:01:06 +08:00
Sergey Pepyakin f4b75bd840 Merge pull request #88 from sphinxc0re/patch-1
Fixed typo
2018-06-11 16:55:26 +03:00
Julian Laubstein 187844f79d Fixed typo 2018-06-06 16:27:20 +02:00
NikVolf a4ff19d358 bump to 0.2.1 2018-05-31 15:40:23 +02:00
Nikolay Volf e31f1040e1 Merge pull request #87 from HCastano/use-if-let-statements
Update matches with single arm to be if-let statements
2018-05-31 16:37:47 +03:00
Hernando Castano e6e340fa0a Update matches with single arm to be if-let statements 2018-05-29 22:46:11 -04:00
Nikolay Volf de23bfac0a Merge pull request #84 from paritytech/public-api
Add public api switch to wasm-build
2018-05-21 22:57:27 +03:00
Nikolay Volf 261c823b63 Merge pull request #82 from paritytech/pack-cli
Standalone wasm-pack binary
2018-05-20 22:51:40 +04:00
NikVolf ce865c1e8a add public api switch 2018-05-18 17:51:37 +04:00
Nikolay Volf 2d60c0bb0e Merge pull request #81 from paritytech/small-fixes
Small fixes in comments
2018-05-18 17:10:55 +04:00
NikVolf 5609a08e99 change to expect 2018-05-18 16:47:06 +04:00
NikVolf edabee0649 more fixes to fixes 2018-05-18 16:45:04 +04:00
NikVolf 367514ae07 actual implementation of packer 2018-05-18 16:37:49 +04:00
NikVolf 816f14eac7 also call/deploy update 2018-05-18 16:29:35 +04:00
NikVolf f9540c5423 some fixes 2018-05-18 16:22:41 +04:00
NikVolf 04ac17c3d5 additional binary 2018-05-18 16:21:25 +04:00
NikVolf f7e6631c83 add contribution section 2018-05-16 20:52:54 +04:00
Alexey 20ff66c649 Merge pull request #79 from elopio/patch-1
Fix typo
2018-05-16 19:04:26 +03:00
Leo Arias 5ef171209b Fix typo 2018-05-16 10:01:51 -06:00
Nikolay Volf 947f0b8bbb Update README.md 2018-05-16 17:39:34 +04:00
NikVolf 7f8811cb2c readme for cli 2018-05-15 18:18:49 +04:00
NikVolf 4112b4b961 bump/set versions 2018-05-15 18:14:23 +04:00
89 changed files with 4888 additions and 3924 deletions
+17 -1
View File
@@ -6,6 +6,22 @@ tab_width=4
end_of_line=lf
charset=utf-8
trim_trailing_whitespace=true
max_line_length=120
max_line_length=100
insert_final_newline=true
[*.md]
max_line_length=80
indent_style=space
indent_size=2
[*.yml]
indent_style=space
indent_size=2
tab_width=8
end_of_line=lf
[*.sh]
indent_style=space
indent_size=2
tab_width=8
end_of_line=lf
+4
View File
@@ -0,0 +1,4 @@
# For details about syntax, see:
# https://help.github.com/en/articles/about-code-owners
* @athei @pepyakin
+11
View File
@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
labels: []
schedule:
interval: "daily"
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: daily
+112
View File
@@ -0,0 +1,112 @@
name: Check
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
rustfmt:
runs-on: "ubuntu_20_64_core"
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: rustfmt
- uses: actions/checkout@v4
- name: Fmt
uses: actions-rs/cargo@v1
with:
toolchain: nightly
command: fmt
args: --all -- --check
clippy:
runs-on: "ubuntu_20_64_core"
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
components: clippy
default: true
- uses: actions/checkout@v4
- name: Clippy
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-targets --all-features -- -D warnings
build:
runs-on: "ubuntu_20_64_core"
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
target: wasm32-unknown-unknown
toolchain: stable
default: true
- uses: actions/checkout@v4
- name: Cargo build
uses: actions-rs/cargo@v1
with:
command: build
- name: Cargo build (std)
uses: actions-rs/cargo@v1
with:
command: build
args: --all-features
- name: Cargo build (no_std)
uses: actions-rs/cargo@v1
with:
command: build
args: --no-default-features
- name: Cargo build (wasm)
uses: actions-rs/cargo@v1
with:
command: build
args: --no-default-features --target wasm32-unknown-unknown
test:
strategy:
matrix:
os: ["ubuntu_20_64_core", "macos-latest", "windows-latest"]
runs-on: ${{ matrix.os }}
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
default: true
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v4
- name: Cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
+2
View File
@@ -3,3 +3,5 @@ target
.cargo
.DS_Store
.idea
.vscode
*~
-9
View File
@@ -1,9 +0,0 @@
language: rust
rust:
- nightly
- stable
script:
- cargo build --all --release --verbose
- cargo test --all --verbose
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo build --no-default-features; fi
+91
View File
@@ -0,0 +1,91 @@
# Benchmarks
## Table of Contents
- [Benchmark Results](#benchmark-results)
- [coremark, instrumented](#coremark,-instrumented)
- [recursive_ok, instrumented](#recursive_ok,-instrumented)
- [fibonacci_recursive, instrumented](#fibonacci_recursive,-instrumented)
- [factorial_recursive, instrumented](#factorial_recursive,-instrumented)
- [count_until, instrumented](#count_until,-instrumented)
- [memory_vec_add, instrumented](#memory_vec_add,-instrumented)
- [wasm_kernel::tiny_keccak, instrumented](#wasm_kernel::tiny_keccak,-instrumented)
- [global_bump, instrumented](#global_bump,-instrumented)
## Instrumented Modules sizes
| fixture | original size | gas metered/host fn | gas metered/mut global | size diff |
|------------------------------|------------------|---------------------|------------------------|-----------|
| recursive_ok.wat | 0 kb | 0 kb (137%) | 0 kb (177%) | +29% |
| count_until.wat | 0 kb | 0 kb (125%) | 0 kb (153%) | +21% |
| global_bump.wat | 0 kb | 0 kb (123%) | 0 kb (145%) | +18% |
| memory-vec-add.wat | 0 kb | 0 kb (116%) | 0 kb (134%) | +15% |
| factorial.wat | 0 kb | 0 kb (125%) | 0 kb (145%) | +15% |
| fibonacci.wat | 0 kb | 0 kb (121%) | 0 kb (134%) | +10% |
| contract_terminate.wasm | 1 kb | 1 kb (110%) | 1 kb (112%) | +2% |
| coremark_minimal.wasm | 7 kb | 8 kb (114%) | 8 kb (115%) | +0% |
| trait_erc20.wasm | 10 kb | 11 kb (108%) | 11 kb (108%) | +0% |
| rand_extension.wasm | 4 kb | 5 kb (109%) | 5 kb (109%) | +0% |
| multisig.wasm | 27 kb | 30 kb (110%) | 30 kb (110%) | +0% |
| wasm_kernel.wasm | 779 kb | 787 kb (100%) | 795 kb (101%) | +0% |
| many_blocks.wasm | 1023 kb | 2389 kb (233%) | 2389 kb (233%) | +0% |
| contract_transfer.wasm | 7 kb | 8 kb (113%) | 8 kb (113%) | +0% |
| erc1155.wasm | 26 kb | 29 kb (111%) | 29 kb (111%) | +0% |
| erc20.wasm | 9 kb | 10 kb (108%) | 10 kb (109%) | +0% |
| dns.wasm | 10 kb | 11 kb (108%) | 11 kb (108%) | +0% |
| proxy.wasm | 3 kb | 4 kb (108%) | 4 kb (109%) | +0% |
| erc721.wasm | 13 kb | 14 kb (108%) | 14 kb (108%) | +0% |
## Benchmark Results
### coremark, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `20.81 s` (✅ **1.00x**) | `20.20 s` (✅ **1.03x faster**) |
### recursive_ok, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `367.11 us` (✅ **1.00x**) | `585.39 us` (❌ *1.59x slower*) |
### fibonacci_recursive, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `9.15 us` (✅ **1.00x**) | `13.56 us` (❌ *1.48x slower*) |
### factorial_recursive, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `1.50 us` (✅ **1.00x**) | `1.98 us` (❌ *1.32x slower*) |
### count_until, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `5.03 ms` (✅ **1.00x**) | `8.13 ms` (❌ *1.62x slower*) |
### memory_vec_add, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `6.21 ms` (✅ **1.00x**) | `8.45 ms` (❌ *1.36x slower*) |
### wasm_kernel::tiny_keccak, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `925.22 us` (✅ **1.00x**) | `1.08 ms` (❌ *1.17x slower*) |
### global_bump, instrumented
| | `with host_function::Injector` | `with mutable_global::Injector` |
|:-------|:----------------------------------------|:----------------------------------------- |
| | `3.79 ms` (✅ **1.00x**) | `7.03 ms` (❌ *1.86x slower*) |
---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+53
View File
@@ -0,0 +1,53 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The semantic versioning guarantees cover the interface to the substrate runtime which
includes this pallet as a dependency. This module will also add storage migrations whenever
changes require it. Stability with regard to offchain tooling is explicitly excluded from
this guarantee: For example adding a new field to an in-storage data structure will require
changes to frontends to properly display it. However, those changes will still be regarded
as a minor version bump.
The interface provided to smart contracts will adhere to semver with one exception: Even
major version bumps will be backwards compatible with regard to already deployed contracts.
In other words: Upgrading this pallet will not break pre-existing contracts.
## [Unreleased]
### New
- Add new gas metering method: mutable global + local gas function
[#34](https://github.com/paritytech/wasm-instrument/pull/34)
- Account for locals initialization costs
[#38](https://github.com/paritytech/wasm-instrument/pull/38)
## [v0.3.0]
### Changed
- Use 64bit arithmetic for per-block gas counter
[#30](https://github.com/paritytech/wasm-instrument/pull/30)
## [v0.2.0] 2022-06-06
### Changed
- Adjust debug information (if already parsed) when injecting gas metering
[#16](https://github.com/paritytech/wasm-instrument/pull/16)
## [v0.1.1] 2022-01-18
### Fixed
- Stack metering disregarded the activiation frame.
[#2](https://github.com/paritytech/wasm-instrument/pull/2)
## [v0.1.0] 2022-01-11
### Changed
- Created from [pwasm-utils](https://github.com/paritytech/wasm-utils) by removing unused code and cleaning up docs.
+39 -18
View File
@@ -1,27 +1,48 @@
[package]
name = "pwasm-utils"
version = "0.1.5"
authors = ["Nikolay Volf <nikvolf@gmail.com>", "Sergey Pepyakin <s.pepyakin@gmail.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
description = "Collection of command-line utilities and corresponding Rust api for producing pwasm-compatible executables"
keywords = ["wasm", "webassembly", "pwasm"]
name = "wasm-instrument"
version = "0.4.0"
edition = "2021"
rust-version = "1.56.1"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT OR Apache-2.0"
description = "Instrument and transform wasm modules."
keywords = ["wasm", "webassembly", "blockchain", "gas-metering", "parity"]
categories = ["wasm", "no-std"]
repository = "https://github.com/paritytech/wasm-instrument"
include = ["src/**/*", "LICENSE-*", "README.md"]
[[bench]]
name = "instrumentation"
harness = false
path = "benches/instrumentation.rs"
[[bench]]
name = "execution"
harness = false
path = "benches/execution.rs"
[profile.bench]
lto = "fat"
codegen-units = 1
[dependencies]
parity-wasm = { version = "0.30", default-features = false }
log = { version = "0.4", default-features = false }
byteorder = { version = "1", default-features = false }
parity-wasm = { version = "0.45", default-features = false }
[dev-dependencies]
tempdir = "0.3"
wabt = "0.2"
diff = "0.1.11"
binaryen = "0.12"
criterion = "0.5"
diff = "0.1"
pretty_assertions = "1"
rand = "0.8"
wat = "1"
wasmparser = "0.206"
wasmprinter = "0.200"
wasmi = "0.31"
[features]
default = ["std"]
std = ["parity-wasm/std", "log/std", "byteorder/std"]
std = ["parity-wasm/std"]
sign_ext = ["parity-wasm/sign_ext"]
[workspace]
members = [
"./cli",
]
[lib]
bench = false
-2
View File
@@ -1,5 +1,3 @@
Copyright (c) 2017 Nikolay Volf
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
+20 -45
View File
@@ -1,58 +1,33 @@
# wasm-utils
# wasm-instrument
[![Build Status](https://travis-ci.org/paritytech/wasm-utils.svg?branch=master)](https://travis-ci.org/paritytech/wasm-utils)
A Rust library containing a collection of wasm module instrumentations and transformations
mainly useful for wasm based block chains and smart contracts.
Collection of WASM utilities used in Parity and WASM contract devepment
## Provided functionality
## Build tools for cargo
This is a non exhaustive list of provided functionality. Please check out the [documentation](https://docs.rs/wasm-instrument/latest/wasm_instrument/) for details.
Easiest way to use is to install via `cargo install`:
### Gas Metering
```
cargo install pwasm-utils --bin wasm-build
```
Add gas metering to your platform by injecting the necessary code directly into the wasm module. This allows having a uniform gas metering implementation across different execution engines (interpreters, JIT compilers).
## Symbols pruning (wasm-prune)
### Stack Height Limiter
```
cargo install pwasm-utils
wasm-prune <input_wasm_binary.wasm> <output_wasm_binary.wasm>
```
Neither the wasm standard nor any sufficiently complex execution engine specifies how many items on the wasm stack are supported before the execution aborts or malfunctions. Even the same execution engine on different operating systems or host architectures could support a different number of stack items and be well within its rights.
This will optimize WASM symbols tree to leave only those elements that are used by contract `_call` function entry.
This is the kind of indeterminism that can lead to consensus failures when used in a blockchain context.
## Gas counter (wasm-gas)
To address this issue we can inject some code that meters the stack height at runtime and aborts the execution when it reaches a predefined limit. Choosing this limit suffciently small so that it is smaller than what any reasonably parameterized execution engine would support solves the issue: All execution engines would reach the injected limit before hitting any implementation specific limitation.
For development puposes, raw WASM contract can be injected with gas counters (the same way as it done by Parity runtime when running contracts)
## License
```
cargo install pwasm-utils
wasm-gas <input_wasm_binary.wasm> <output_wasm_binary.wasm>
```
## Externalization (wasm-ext)
Parity WASM runtime provides some library functions that can be commonly found in libc. WASM binary size can be reduced and performance may be improved if these functions are used. This utility scans for invocations of the following functions inside the WASM binary:
- `_malloc`,
- `_free`,
- `_memcpy`,
- `_memset`,
- `_memmove`
And then substitutes them with invocations of the imported ones. Should be run before `wasm-opt` for better results.
```
cargo install pwasm-utils
wasm-ext <input_wasm_binary.wasm> <output_wasm_binary.wasm>
```
## API
All executables use corresponding api methods of the root crate and can be combined in other build tools.
# License
`wasm-utils` is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0), at your choice.
`wasm-instrument` is distributed under the terms of both the MIT license and the
Apache License (Version 2.0), at your choice.
See LICENSE-APACHE, and LICENSE-MIT for details.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in `wasm-instrument` by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
+437
View File
@@ -0,0 +1,437 @@
use criterion::{
criterion_group, criterion_main, measurement::Measurement, Bencher, BenchmarkGroup, Criterion,
};
use std::{
fs::read,
path::PathBuf,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use wasm_instrument::{
gas_metering::{self, host_function, mutable_global, ConstantCostRules},
parity_wasm::{deserialize_buffer, elements::Module, serialize},
};
use wasmi::{
core::{Pages, TrapCode, F32},
Caller, Config, Engine, Instance, Linker, Memory, StackLimits, Store, TypedFunc, Value,
};
/// Describes a gas metering strategy we want to benchmark.
///
/// Most strategies just need a subset of these functions. Hence we added default
/// implementations for all of them.
trait MeteringStrategy {
/// The wasmi config we should be using for this strategy.
fn config() -> Config {
Config::default()
}
/// The strategy may or may not want to instrument the module.
fn instrument_module(module: Module) -> Module {
module
}
/// The strategy might need to define additional host functions.
fn define_host_funcs(_linker: &mut Linker<u64>) {}
/// The strategy might need to do some initialization of the wasm instance.
fn init_instance(_module: &mut BenchInstance) {}
}
/// Don't do any metering at all. This is helpful as a baseline.
struct NoMetering;
/// Use wasmi's builtin fuel metering.
struct WasmiMetering;
/// Instrument the module using [`host_function::Injector`].
struct HostFunctionMetering;
/// Instrument the module using [`mutable_global::Injector`].
struct MutableGlobalMetering;
impl MeteringStrategy for NoMetering {}
impl MeteringStrategy for WasmiMetering {
fn config() -> Config {
let mut config = Config::default();
config.consume_fuel(true);
config
}
fn init_instance(module: &mut BenchInstance) {
module.store.add_fuel(u64::MAX).unwrap();
}
}
impl MeteringStrategy for HostFunctionMetering {
fn instrument_module(module: Module) -> Module {
let backend = host_function::Injector::new("env", "gas");
gas_metering::inject(module, backend, &ConstantCostRules::default()).unwrap()
}
fn define_host_funcs(linker: &mut Linker<u64>) {
// the instrumentation relies on the existing of this function
linker
.func_wrap("env", "gas", |mut caller: Caller<'_, u64>, amount_consumed: u64| {
let gas_remaining = caller.data_mut();
*gas_remaining =
gas_remaining.checked_sub(amount_consumed).ok_or(TrapCode::OutOfFuel)?;
Ok(())
})
.unwrap();
}
}
impl MeteringStrategy for MutableGlobalMetering {
fn instrument_module(module: Module) -> Module {
let backend = mutable_global::Injector::new("gas_left");
gas_metering::inject(module, backend, &ConstantCostRules::default()).unwrap()
}
fn init_instance(module: &mut BenchInstance) {
// the instrumentation relies on the host to initialize the global with the gas limit
// we just init to the maximum so it will never run out
module
.instance
.get_global(&mut module.store, "gas_left")
.unwrap()
.set(&mut module.store, Value::I64(-1i64)) // the same as u64::MAX
.unwrap();
}
}
/// A wasm instance ready to be benchmarked.
struct BenchInstance {
store: Store<u64>,
instance: Instance,
}
impl BenchInstance {
/// Create a new instance for the supplied metering strategy.
///
/// `wasm`: The raw wasm module for the benchmark.
/// `define_host_func`: In here the caller can define additional host function.
fn new<S, H>(wasm: &[u8], define_host_funcs: &H) -> Self
where
S: MeteringStrategy,
H: Fn(&mut Linker<u64>),
{
let module = deserialize_buffer(wasm).unwrap();
let instrumented_module = S::instrument_module(module);
let input = serialize(instrumented_module).unwrap();
let mut config = S::config();
config.set_stack_limits(StackLimits::new(1024, 1024 * 1024, 64 * 1024).unwrap());
let engine = Engine::new(&config);
let module = wasmi::Module::new(&engine, &mut &input[..]).unwrap();
let mut linker = Linker::new(&engine);
S::define_host_funcs(&mut linker);
define_host_funcs(&mut linker);
// init host state with maximum gas_left (only used by host_function instrumentation)
let mut store = Store::new(&engine, u64::MAX);
let instance = linker.instantiate(&mut store, &module).unwrap().start(&mut store).unwrap();
let mut bench_module = Self { store, instance };
S::init_instance(&mut bench_module);
bench_module
}
}
/// Runs a benchmark for every strategy.
///
/// We require the closures to implement `Fn` as they are executed for every strategy and we
/// don't want them to change in between.
///
/// `group`: The benchmark group within the benchmarks will be executed.
/// `wasm`: The raw wasm module for the benchmark.
/// `define_host_func`: In here the caller can define additional host function.
/// `f`: In here the user should perform the benchmark. Will be executed for every strategy.
fn for_strategies<M, H, F>(group: &mut BenchmarkGroup<M>, wasm: &[u8], define_host_funcs: H, f: F)
where
M: Measurement,
H: Fn(&mut Linker<u64>),
F: Fn(&mut Bencher<M>, &mut BenchInstance),
{
let mut module = BenchInstance::new::<NoMetering, _>(wasm, &define_host_funcs);
group.bench_function("no_metering", |bench| f(bench, &mut module));
let mut module = BenchInstance::new::<WasmiMetering, _>(wasm, &define_host_funcs);
group.bench_function("wasmi_builtin", |bench| f(bench, &mut module));
let mut module = BenchInstance::new::<HostFunctionMetering, _>(wasm, &define_host_funcs);
group.bench_function("host_function", |bench| f(bench, &mut module));
let mut module = BenchInstance::new::<MutableGlobalMetering, _>(wasm, &define_host_funcs);
group.bench_function("mutable_global", |bench| f(bench, &mut module));
}
/// Converts the `.wat` encoded `bytes` into `.wasm` encoded bytes.
fn wat2wasm(bytes: &[u8]) -> Vec<u8> {
wat::parse_bytes(bytes).unwrap().into_owned()
}
fn fixture_dir() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("benches");
path.push("fixtures");
path.push("wasm");
path
}
fn gas_metered_coremark(c: &mut Criterion) {
let mut group = c.benchmark_group("coremark");
// Benchmark host_function::Injector
let wasm_filename = "coremark_minimal.wasm";
let bytes = read(fixture_dir().join(wasm_filename)).unwrap();
let define_host_funcs = |linker: &mut Linker<u64>| {
linker
.func_wrap("env", "clock_ms", || {
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64
})
.unwrap();
};
for_strategies(&mut group, &bytes, define_host_funcs, |bench, module| {
bench.iter(|| {
let run = module.instance.get_typed_func::<(), F32>(&mut module.store, "run").unwrap();
// Call the wasm!
run.call(&mut module.store, ()).unwrap();
})
});
}
fn gas_metered_recursive_ok(c: &mut Criterion) {
let mut group = c.benchmark_group("recursive_ok");
const RECURSIVE_DEPTH: i32 = 8000;
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/recursive_ok.wat"));
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let bench_call =
module.instance.get_typed_func::<i32, i32>(&module.store, "call").unwrap();
bench.iter(|| {
let result = bench_call.call(&mut module.store, RECURSIVE_DEPTH).unwrap();
assert_eq!(result, 0);
})
},
);
}
fn gas_metered_fibonacci_recursive(c: &mut Criterion) {
let mut group = c.benchmark_group("fibonacci_recursive");
const FIBONACCI_REC_N: i64 = 10;
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/fibonacci.wat"));
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let bench_call = module
.instance
.get_typed_func::<i64, i64>(&module.store, "fib_recursive")
.unwrap();
bench.iter(|| {
bench_call.call(&mut module.store, FIBONACCI_REC_N).unwrap();
});
},
);
}
fn gas_metered_fac_recursive(c: &mut Criterion) {
let mut group = c.benchmark_group("factorial_recursive");
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/factorial.wat"));
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let fac = module
.instance
.get_typed_func::<i64, i64>(&module.store, "recursive_factorial")
.unwrap();
bench.iter(|| {
let result = fac.call(&mut module.store, 25).unwrap();
assert_eq!(result, 7034535277573963776);
})
},
);
}
fn gas_metered_count_until(c: &mut Criterion) {
const COUNT_UNTIL: i32 = 100_000;
let mut group = c.benchmark_group("count_until");
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/count_until.wat"));
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let count_until = module
.instance
.get_typed_func::<i32, i32>(&module.store, "count_until")
.unwrap();
bench.iter(|| {
let result = count_until.call(&mut module.store, COUNT_UNTIL).unwrap();
assert_eq!(result, COUNT_UNTIL);
})
},
);
}
fn gas_metered_vec_add(c: &mut Criterion) {
fn test_for<A, B>(
b: &mut Bencher,
vec_add: TypedFunc<(i32, i32, i32, i32), ()>,
mut store: &mut Store<u64>,
mem: Memory,
len: usize,
vec_a: A,
vec_b: B,
) where
A: IntoIterator<Item = i32>,
B: IntoIterator<Item = i32>,
{
use core::mem::size_of;
let ptr_result = 10;
let len_result = len * size_of::<i64>();
let ptr_a = ptr_result + len_result;
let len_a = len * size_of::<i32>();
let ptr_b = ptr_a + len_a;
// Reset `result` buffer to zeros:
mem.data_mut(&mut store)[ptr_result..ptr_result + (len * size_of::<i32>())].fill(0);
// Initialize `a` buffer:
for (n, a) in vec_a.into_iter().take(len).enumerate() {
mem.write(&mut store, ptr_a + (n * size_of::<i32>()), &a.to_le_bytes()).unwrap();
}
// Initialize `b` buffer:
for (n, b) in vec_b.into_iter().take(len).enumerate() {
mem.write(&mut store, ptr_b + (n * size_of::<i32>()), &b.to_le_bytes()).unwrap();
}
// Prepare parameters and all Wasm `vec_add`:
let params = (ptr_result as i32, ptr_a as i32, ptr_b as i32, len as i32);
b.iter(|| {
vec_add.call(&mut store, params).unwrap();
});
// Validate the result buffer:
for n in 0..len {
let mut buffer4 = [0x00; 4];
let mut buffer8 = [0x00; 8];
let a = {
mem.read(&store, ptr_a + (n * size_of::<i32>()), &mut buffer4).unwrap();
i32::from_le_bytes(buffer4)
};
let b = {
mem.read(&store, ptr_b + (n * size_of::<i32>()), &mut buffer4).unwrap();
i32::from_le_bytes(buffer4)
};
let actual_result = {
mem.read(&store, ptr_result + (n * size_of::<i64>()), &mut buffer8).unwrap();
i64::from_le_bytes(buffer8)
};
let expected_result = (a as i64) + (b as i64);
assert_eq!(
expected_result, actual_result,
"given a = {a} and b = {b}, results diverge at index {n}"
);
}
}
let mut group = c.benchmark_group("memory_vec_add");
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/memory-vec-add.wat"));
const LEN: usize = 100_000;
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let vec_add = module
.instance
.get_typed_func::<(i32, i32, i32, i32), ()>(&module.store, "vec_add")
.unwrap();
let mem = module.instance.get_memory(&module.store, "mem").unwrap();
mem.grow(&mut module.store, Pages::new(25).unwrap()).unwrap();
test_for(
bench,
vec_add,
&mut module.store,
mem,
LEN,
(0..LEN).map(|i| (i * i) as i32),
(0..LEN).map(|i| (i * 10) as i32),
)
},
);
}
fn gas_metered_tiny_keccak(c: &mut Criterion) {
let mut group = c.benchmark_group("wasm_kernel::tiny_keccak");
let wasm_filename = "wasm_kernel.wasm";
let wasm_bytes = read(fixture_dir().join(wasm_filename)).unwrap();
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let prepare = module
.instance
.get_typed_func::<(), i32>(&module.store, "prepare_tiny_keccak")
.unwrap();
let keccak = module
.instance
.get_typed_func::<i32, ()>(&module.store, "bench_tiny_keccak")
.unwrap();
let test_data_ptr = prepare.call(&mut module.store, ()).unwrap();
bench.iter(|| {
keccak.call(&mut module.store, test_data_ptr).unwrap();
})
},
);
}
fn gas_metered_global_bump(c: &mut Criterion) {
const BUMP_AMOUNT: i32 = 100_000;
let mut group = c.benchmark_group("global_bump");
let wasm_bytes = wat2wasm(include_bytes!("fixtures/wat/global_bump.wat"));
for_strategies(
&mut group,
&wasm_bytes,
|_| {},
|bench, module| {
let bump = module.instance.get_typed_func::<i32, i32>(&module.store, "bump").unwrap();
bench.iter(|| {
let result = bump.call(&mut module.store, BUMP_AMOUNT).unwrap();
assert_eq!(result, BUMP_AMOUNT);
})
},
);
}
criterion_group!(
name = coremark;
config = Criterion::default()
.sample_size(10)
.measurement_time(Duration::from_millis(275000))
.warm_up_time(Duration::from_millis(1000));
targets =
gas_metered_coremark,
);
criterion_group!(
name = wasmi_fixtures;
config = Criterion::default()
.sample_size(10)
.measurement_time(Duration::from_millis(250000))
.warm_up_time(Duration::from_millis(1000));
targets =
gas_metered_recursive_ok,
gas_metered_fibonacci_recursive,
gas_metered_fac_recursive,
gas_metered_count_until,
gas_metered_vec_add,
gas_metered_tiny_keccak,
gas_metered_global_bump,
);
criterion_main!(coremark, wasmi_fixtures);
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+25
View File
@@ -0,0 +1,25 @@
;; Exports a function `count_until` that takes an input `n`.
;; The exported function counts an integer `n` times and then returns `n`.
(module
(func $count_until (export "count_until") (param $limit i32) (result i32)
(local $counter i32)
(block
(loop
(br_if
1
(i32.eq
(local.tee $counter
(i32.add
(local.get $counter)
(i32.const 1)
)
)
(local.get $limit)
)
)
(br 0)
)
)
(return (local.get $counter))
)
)
+35
View File
@@ -0,0 +1,35 @@
(module
;; Iterative factorial function, does not use recursion.
(func (export "iterative_factorial") (param i64) (result i64)
(local i64)
(local.set 1 (i64.const 1))
(block
(br_if 0 (i64.lt_s (local.get 0) (i64.const 2)))
(loop
(local.set 1 (i64.mul (local.get 1) (local.get 0)))
(local.set 0 (i64.add (local.get 0) (i64.const -1)))
(br_if 0 (i64.gt_s (local.get 0) (i64.const 1)))
)
)
(local.get 1)
)
;; Recursive trivial factorial function.
(func $rec_fac (export "recursive_factorial") (param i64) (result i64)
(if (result i64)
(i64.eq (local.get 0) (i64.const 0))
(then (i64.const 1))
(else
(i64.mul
(local.get 0)
(call $rec_fac
(i64.sub
(local.get 0)
(i64.const 1)
)
)
)
)
)
)
)
+47
View File
@@ -0,0 +1,47 @@
(module
(func $fib_recursive (export "fib_recursive") (param $N i64) (result i64)
(if
(i64.le_s (local.get $N) (i64.const 1))
(then (return (local.get $N)))
)
(return
(i64.add
(call $fib_recursive
(i64.sub (local.get $N) (i64.const 1))
)
(call $fib_recursive
(i64.sub (local.get $N) (i64.const 2))
)
)
)
)
(func $fib_iterative (export "fib_iterative") (param $N i64) (result i64)
(local $n1 i64)
(local $n2 i64)
(local $tmp i64)
(local $i i64)
;; return $N for N <= 1
(if
(i64.le_s (local.get $N) (i64.const 1))
(then (return (local.get $N)))
)
(local.set $n1 (i64.const 1))
(local.set $n2 (i64.const 1))
(local.set $i (i64.const 2))
;;since we normally return n2, handle n=1 case specially
(loop $again
(if
(i64.lt_s (local.get $i) (local.get $N))
(then
(local.set $tmp (i64.add (local.get $n1) (local.get $n2)))
(local.set $n1 (local.get $n2))
(local.set $n2 (local.get $tmp))
(local.set $i (i64.add (local.get $i) (i64.const 1)))
(br $again)
)
)
)
(local.get $n2)
)
)
+27
View File
@@ -0,0 +1,27 @@
;; Exports a function `bump` that takes an input `n`.
;; The exported function bumps a global variable `n` times and then returns it.
(module
(global $g (mut i32) (i32.const 0))
(func $bump (export "bump") (param $n i32) (result i32)
(global.set $g (i32.const 0))
(block $break
(loop $continue
(br_if ;; if $g == $n then break
$break
(i32.eq
(global.get $g)
(local.get $n)
)
)
(global.set $g ;; $g += 1
(i32.add
(global.get $g)
(i32.const 1)
)
)
(br $continue)
)
)
(return (global.get $g))
)
)
+58
View File
@@ -0,0 +1,58 @@
;; Exports a function `vec_add` that computes the addition of 2 vectors
;; of length `len` starting at `ptr_a` and `ptr_b` and stores the result
;; into a buffer of the same length starting at `ptr_result`.
(module
(memory (export "mem") 1)
(func (export "vec_add")
(param $ptr_result i32)
(param $ptr_a i32)
(param $ptr_b i32)
(param $len i32)
(local $n i32)
(block $exit
(loop $loop
(br_if ;; exit loop if $n == $len
$exit
(i32.eq
(local.get $n)
(local.get $len)
)
)
(i64.store offset=0 ;; ptr_result[n] = ptr_a[n] + ptr_b[n]
(i32.add
(local.get $ptr_result)
(i32.mul
(local.get $n)
(i32.const 8)
)
)
(i64.add
(i64.load32_s offset=0 ;; load ptr_a[n]
(i32.add
(local.get $ptr_a)
(i32.mul
(local.get $n)
(i32.const 4)
)
)
)
(i64.load32_s offset=0 ;; load ptr_b[n]
(i32.add
(local.get $ptr_b)
(i32.mul
(local.get $n)
(i32.const 4)
)
)
)
)
)
(local.set $n ;; increment n
(i32.add (local.get $n) (i32.const 1))
)
(br $loop) ;; continue loop
)
)
(return)
)
)
+22
View File
@@ -0,0 +1,22 @@
;; Exports a function `call` that takes an input `n`.
;; The exported function calls itself `n` times.
(module
(func $call (export "call") (param $n i32) (result i32)
(if (result i32)
(local.get $n)
(then
(return
(call $call
(i32.sub
(local.get $n)
(i32.const 1)
)
)
)
)
(else
(return (local.get $n))
)
)
)
)
+58
View File
@@ -0,0 +1,58 @@
use criterion::{
criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, Criterion,
Throughput,
};
use std::{
fs::{read, read_dir},
path::PathBuf,
};
use wasm_instrument::{
gas_metering::{self, host_function, ConstantCostRules},
inject_stack_limiter,
parity_wasm::{deserialize_buffer, elements::Module},
};
fn fixture_dir() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("benches");
path.push("fixtures");
path.push("wasm");
path
}
fn for_fixtures<F, M>(group: &mut BenchmarkGroup<M>, f: F)
where
F: Fn(Module),
M: Measurement,
{
for entry in read_dir(fixture_dir()).unwrap() {
let entry = entry.unwrap();
let bytes = read(entry.path()).unwrap();
group.throughput(Throughput::Bytes(bytes.len().try_into().unwrap()));
group.bench_with_input(entry.file_name().to_str().unwrap(), &bytes, |bench, input| {
bench.iter(|| f(deserialize_buffer(input).unwrap()))
});
}
}
fn gas_metering(c: &mut Criterion) {
let mut group = c.benchmark_group("Gas Metering");
for_fixtures(&mut group, |module| {
gas_metering::inject(
module,
host_function::Injector::new("env", "gas"),
&ConstantCostRules::default(),
)
.unwrap();
});
}
fn stack_height_limiter(c: &mut Criterion) {
let mut group = c.benchmark_group("Stack Height Limiter");
for_fixtures(&mut group, |module| {
inject_stack_limiter(module, 128).unwrap();
});
}
criterion_group!(benches, gas_metering, stack_height_limiter);
criterion_main!(benches);
-42
View File
@@ -1,42 +0,0 @@
[package]
name = "pwasm-utils-cli"
version = "0.1.5"
authors = ["Nikolay Volf <nikvolf@gmail.com>", "Sergey Pepyakin <s.pepyakin@gmail.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
description = "Collection of command-line utilities and corresponding Rust api for producing pwasm-compatible executables"
keywords = ["wasm", "webassembly", "pwasm"]
[lib]
[[bin]]
name = "wasm-prune"
path = "prune/main.rs"
[[bin]]
name = "wasm-ext"
path = "ext/main.rs"
[[bin]]
name = "wasm-gas"
path = "gas/main.rs"
[[bin]]
name = "wasm-build"
path = "build/main.rs"
[[bin]]
name = "wasm-stack-height"
path = "stack_height/main.rs"
[dependencies]
parity-wasm = "0.30"
pwasm-utils = { path = ".." }
glob = "0.2"
clap = "2.24"
log = "0.4"
env_logger = "0.5"
lazy_static = "1.0"
[dev-dependencies]
tempdir = "0.3"
-269
View File
@@ -1,269 +0,0 @@
//! Experimental build tool for cargo
extern crate glob;
extern crate pwasm_utils as utils;
extern crate clap;
extern crate parity_wasm;
extern crate pwasm_utils_cli as logger;
mod source;
use std::{fs, io};
use std::io::Write;
use std::path::PathBuf;
use clap::{App, Arg};
use parity_wasm::elements;
use utils::{CREATE_SYMBOL, CALL_SYMBOL, ununderscore_funcs, externalize_mem, shrink_unknown_stack};
#[derive(Debug)]
pub enum Error {
Io(io::Error),
FailedToCopy(String),
Decoding(elements::Error, String),
Encoding(elements::Error),
Packing(utils::PackingError),
Optimizer,
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::Io(err)
}
}
impl From<utils::OptimizerError> for Error {
fn from(_err: utils::OptimizerError) -> Self {
Error::Optimizer
}
}
impl From<utils::PackingError> for Error {
fn from(err: utils::PackingError) -> Self {
Error::Packing(err)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
use Error::*;
match *self {
Io(ref io) => write!(f, "Generic i/o error: {}", io),
FailedToCopy(ref msg) => write!(f, "{}. Have you tried to run \"cargo build\"?", msg),
Decoding(ref err, ref file) => write!(f, "Decoding error ({}). Must be a valid wasm file {}. Pointed wrong file?", err, file),
Encoding(ref err) => write!(f, "Encoding error ({}). Almost impossible to happen, no free disk space?", err),
Optimizer => write!(f, "Optimization error due to missing export section. Pointed wrong file?"),
Packing(ref e) => write!(f, "Packing failed due to module structure error: {}. Sure used correct libraries for building contracts?", e),
}
}
}
pub fn wasm_path(input: &source::SourceInput) -> String {
let mut path = PathBuf::from(input.target_dir());
path.push(format!("{}.wasm", input.final_name()));
path.to_string_lossy().to_string()
}
pub fn process_output(input: &source::SourceInput) -> Result<(), Error> {
let mut cargo_path = PathBuf::from(input.target_dir());
let wasm_name = input.bin_name().to_string().replace("-", "_");
cargo_path.push(
match input.target() {
source::SourceTarget::Emscripten => source::EMSCRIPTEN_TRIPLET,
source::SourceTarget::Unknown => source::UNKNOWN_TRIPLET,
}
);
cargo_path.push("release");
cargo_path.push(format!("{}.wasm", wasm_name));
let mut target_path = PathBuf::from(input.target_dir());
target_path.push(format!("{}.wasm", input.final_name()));
fs::copy(cargo_path.as_path(), target_path.as_path())
.map_err(|io| Error::FailedToCopy(
format!("Failed to copy '{}' to '{}': {}", cargo_path.display(), target_path.display(), io)
))?;
Ok(())
}
fn has_ctor(module: &elements::Module) -> bool {
if let Some(ref section) = module.export_section() {
section.entries().iter().any(|e| CREATE_SYMBOL == e.field())
} else {
false
}
}
fn do_main() -> Result<(), Error> {
logger::init_log();
let matches = App::new("wasm-build")
.arg(Arg::with_name("target")
.index(1)
.required(true)
.help("Cargo target directory"))
.arg(Arg::with_name("wasm")
.index(2)
.required(true)
.help("Wasm binary name"))
.arg(Arg::with_name("skip_optimization")
.help("Skip symbol optimization step producing final wasm")
.long("skip-optimization"))
.arg(Arg::with_name("enforce_stack_adjustment")
.help("Enforce stack size adjustment (used for old wasm32-unknown-unknown)")
.long("enforce-stack-adjustment"))
.arg(Arg::with_name("runtime_type")
.help("Injects RUNTIME_TYPE global export")
.takes_value(true)
.long("runtime-type"))
.arg(Arg::with_name("runtime_version")
.help("Injects RUNTIME_VERSION global export")
.takes_value(true)
.long("runtime-version"))
.arg(Arg::with_name("source_target")
.help("Cargo target type kind ('wasm32-unknown-unknown' or 'wasm32-unknown-emscripten'")
.takes_value(true)
.long("target"))
.arg(Arg::with_name("final_name")
.help("Final wasm binary name")
.takes_value(true)
.long("final"))
.arg(Arg::with_name("save_raw")
.help("Save intermediate raw bytecode to path")
.takes_value(true)
.long("save-raw"))
.arg(Arg::with_name("shrink_stack")
.help("Shrinks the new stack size for wasm32-unknown-unknown")
.takes_value(true)
.long("shrink-stack"))
.get_matches();
let target_dir = matches.value_of("target").expect("is required; qed");
let wasm_binary = matches.value_of("wasm").expect("is required; qed");
let mut source_input = source::SourceInput::new(target_dir, wasm_binary);
let source_target_val = matches.value_of("source_target").unwrap_or_else(|| source::EMSCRIPTEN_TRIPLET);
if source_target_val == source::UNKNOWN_TRIPLET {
source_input = source_input.unknown()
} else if source_target_val == source::EMSCRIPTEN_TRIPLET {
source_input = source_input.emscripten()
} else {
eprintln!("--target can be: '{}' or '{}'", source::EMSCRIPTEN_TRIPLET, source::UNKNOWN_TRIPLET);
::std::process::exit(1);
}
if let Some(final_name) = matches.value_of("final_name") {
source_input = source_input.with_final(final_name);
}
process_output(&source_input)?;
let path = wasm_path(&source_input);
let mut module = parity_wasm::deserialize_file(&path)
.map_err(|e| Error::Decoding(e, path.to_string()))?;
if let source::SourceTarget::Emscripten = source_input.target() {
module = ununderscore_funcs(module);
}
if let source::SourceTarget::Unknown = source_input.target() {
// 49152 is 48kb!
if matches.is_present("enforce_stack_adjustment") {
let stack_size: u32 = matches.value_of("shrink_stack").unwrap_or_else(|| "49152").parse().expect("New stack size is not valid u32");
assert!(stack_size <= 1024*1024);
let (new_module, new_stack_top) = shrink_unknown_stack(module, 1024 * 1024 - stack_size);
module = new_module;
let mut stack_top_page = new_stack_top / 65536;
if new_stack_top % 65536 > 0 { stack_top_page += 1 };
module = externalize_mem(module, Some(stack_top_page), 16);
} else {
module = externalize_mem(module, None, 16);
}
}
if let Some(runtime_type) = matches.value_of("runtime_type") {
let runtime_type: &[u8] = runtime_type.as_bytes();
if runtime_type.len() != 4 {
panic!("--runtime-type should be equal to 4 bytes");
}
let runtime_version: u32 = matches.value_of("runtime_version").unwrap_or("1").parse()
.expect("--runtime-version should be a positive integer");
module = utils::inject_runtime_type(module, &runtime_type, runtime_version);
}
let mut ctor_module = module.clone();
if !matches.is_present("skip_optimization") {
utils::optimize(
&mut module,
vec![CALL_SYMBOL]
)?;
}
if let Some(save_raw_path) = matches.value_of("save_raw") {
parity_wasm::serialize_to_file(save_raw_path, module.clone()).map_err(Error::Encoding)?;
}
let raw_module = parity_wasm::serialize(module).map_err(Error::Encoding)?;
// If module has an exported function with name=CREATE_SYMBOL
// build will pack the module (raw_module) into this funciton and export as CALL_SYMBOL.
// Otherwise it will just save an optimised raw_module
if has_ctor(&ctor_module) {
if !matches.is_present("skip_optimization") {
utils::optimize(&mut ctor_module, vec![CREATE_SYMBOL])?;
}
let ctor_module = utils::pack_instance(raw_module, ctor_module)?;
parity_wasm::serialize_to_file(&path, ctor_module).map_err(Error::Encoding)?;
} else {
let mut file = fs::File::create(&path)?;
file.write_all(&raw_module)?;
}
Ok(())
}
fn main() {
if let Err(e) = do_main() {
eprintln!("{}", e);
std::process::exit(1)
}
}
#[cfg(test)]
mod tests {
extern crate tempdir;
use self::tempdir::TempDir;
use std::fs;
use super::process_output;
use super::source::SourceInput;
#[test]
fn processes_cargo_output() {
let tmp_dir = TempDir::new("target").expect("temp dir failed");
let target_path = tmp_dir.path().join("wasm32-unknown-emscripten").join("release");
fs::create_dir_all(target_path.clone()).expect("create dir failed");
{
use std::io::Write;
let wasm_path = target_path.join("example_wasm.wasm");
let mut f = fs::File::create(wasm_path).expect("create fail failed");
f.write(b"\0asm").expect("write file failed");
}
let path = tmp_dir.path().to_string_lossy();
let input = SourceInput::new(&path, "example-wasm");
process_output(&input).expect("process output failed");
assert!(
fs::metadata(tmp_dir.path().join("example-wasm.wasm")).expect("metadata failed").is_file()
)
}
}
-62
View File
@@ -1,62 +0,0 @@
//! Configuration of source binaries
pub const UNKNOWN_TRIPLET: &str = "wasm32-unknown-unknown";
pub const EMSCRIPTEN_TRIPLET: &str = "wasm32-unknown-emscripten";
/// Target configiration of previous build step
#[derive(Debug, Clone, Copy)]
pub enum SourceTarget {
Emscripten,
Unknown,
}
/// Configuration of previous build step (cargo compilation)
#[derive(Debug)]
pub struct SourceInput<'a> {
target_dir: &'a str,
bin_name: &'a str,
final_name: &'a str,
target: SourceTarget,
}
impl<'a> SourceInput<'a> {
pub fn new<'b>(target_dir: &'b str, bin_name: &'b str) -> SourceInput<'b> {
SourceInput {
target_dir: target_dir,
bin_name: bin_name,
final_name: bin_name,
target: SourceTarget::Emscripten,
}
}
pub fn unknown(mut self) -> Self {
self.target = SourceTarget::Unknown;
self
}
pub fn emscripten(mut self) -> Self {
self.target = SourceTarget::Emscripten;
self
}
pub fn with_final(mut self, final_name: &'a str) -> Self {
self.final_name = final_name;
self
}
pub fn target_dir(&self) -> &str {
self.target_dir
}
pub fn bin_name(&self) -> &str {
self.bin_name
}
pub fn final_name(&self) -> &str {
self.final_name
}
pub fn target(&self) -> SourceTarget {
self.target
}
}
-23
View File
@@ -1,23 +0,0 @@
extern crate parity_wasm;
extern crate pwasm_utils as utils;
extern crate pwasm_utils_cli as logger;
use std::env;
fn main() {
logger::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let module = utils::externalize(
parity_wasm::deserialize_file(&args[1]).expect("Module to deserialize ok"),
vec!["_free", "_malloc", "_memcpy", "_memset", "_memmove"],
);
parity_wasm::serialize_to_file(&args[2], module).expect("Module to serialize ok");
}
-24
View File
@@ -1,24 +0,0 @@
extern crate parity_wasm;
extern crate pwasm_utils as utils;
extern crate pwasm_utils_cli as logger;
use std::env;
fn main() {
logger::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
// Loading module
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
let result = utils::inject_gas_counter(
module, &Default::default()
).expect("Failed to inject gas. Some forbidden opcodes?");
parity_wasm::serialize_to_file(&args[2], result).expect("Module serialization to succeed")
}
-45
View File
@@ -1,45 +0,0 @@
extern crate parity_wasm;
extern crate pwasm_utils as utils;
extern crate pwasm_utils_cli as logger;
extern crate clap;
use clap::{App, Arg};
fn main() {
logger::init_log();
let matches = App::new("wasm-opt")
.arg(Arg::with_name("input")
.index(1)
.required(true)
.help("Input WASM file"))
.arg(Arg::with_name("output")
.index(2)
.required(true)
.help("Output WASM file"))
.arg(Arg::with_name("exports")
.long("exports")
.short("e")
.takes_value(true)
.value_name("functions")
.help("Comma-separated list of exported functions to keep. Default: _call"))
.get_matches();
let exports = matches
.value_of("exports")
.unwrap_or("_call")
.split(',')
.collect();
let input = matches.value_of("input").expect("is required; qed");
let output = matches.value_of("output").expect("is required; qed");
let mut module = parity_wasm::deserialize_file(&input).unwrap();
// Invoke optimizer
// Contract is supposed to have only these functions as public api
// All other symbols not usable by this list is optimized away
utils::optimize(&mut module, exports).expect("Optimizer to finish without errors");
parity_wasm::serialize_to_file(&output, module).unwrap();
}
-27
View File
@@ -1,27 +0,0 @@
#[macro_use] extern crate log;
#[macro_use] extern crate lazy_static;
extern crate env_logger;
use std::env;
use log::LevelFilter;
use env_logger::Builder;
lazy_static! {
static ref LOG_DUMMY: bool = {
let mut builder = Builder::new();
builder.filter(None, LevelFilter::Info);
if let Ok(log) = env::var("RUST_LOG") {
builder.parse(&log);
}
builder.init();
trace!("logger initialized");
true
};
}
/// Intialize log with default settings
pub fn init_log() {
let _ = *LOG_DUMMY;
}
-28
View File
@@ -1,28 +0,0 @@
extern crate pwasm_utils as utils;
extern crate parity_wasm;
extern crate pwasm_utils_cli as logger;
use std::env;
use utils::stack_height;
fn main() {
logger::init_log();
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return;
}
let input_file = &args[1];
let output_file = &args[2];
// Loading module
let module = parity_wasm::deserialize_file(&input_file).expect("Module deserialization to succeed");
let result = stack_height::inject_limiter(
module, 1024
).expect("Failed to inject stack height counter");
parity_wasm::serialize_to_file(&output_file, result).expect("Module serialization to succeed")
}
+18
View File
@@ -0,0 +1,18 @@
_default:
just --list
# Run rustfmt and ensure the code meets the expectation of the checks in the CI
format:
cargo +nightly fmt --all
# Run basic checks similar to what the CI does to ensure your code is fine
check:
cargo +nightly fmt --all -- --check
cargo +stable clippy --all-targets --all-features -- -D warnings
# Run the tests
test:
cargo test --all-features
# So you are ready? This runs format, check and test
ready: format check test
+23
View File
@@ -0,0 +1,23 @@
# Basic
hard_tabs = true
max_width = 100
use_small_heuristics = "Max"
# Imports
imports_granularity = "Crate"
reorder_imports = true
# Consistency
newline_style = "Unix"
# Format comments
comment_width = 100
wrap_comments = true
# Misc
chain_width = 80
spaces_around_ranges = false
binop_separator = "Back"
reorder_impl_items = false
match_arm_leading_pipes = "Preserve"
match_arm_blocks = false
match_block_trailing_comma = true
trailing_comma = "Vertical"
trailing_semicolon = false
use_field_init_shorthand = true
+161
View File
@@ -0,0 +1,161 @@
use alloc::{format, vec::Vec};
use parity_wasm::elements;
/// Export all declared mutable globals as `prefix_index`.
///
/// This will export all internal mutable globals under the name of
/// concat(`prefix`, `"_"`, `i`) where i is the index inside the range of
/// [0..total number of internal mutable globals].
pub fn export_mutable_globals(module: &mut elements::Module, prefix: &str) {
let exports = global_section(module)
.map(|section| {
section
.entries()
.iter()
.enumerate()
.filter_map(
|(index, global)| {
if global.global_type().is_mutable() {
Some(index)
} else {
None
}
},
)
.collect::<Vec<_>>()
})
.unwrap_or_default();
if module.export_section().is_none() {
module
.sections_mut()
.push(elements::Section::Export(elements::ExportSection::default()));
}
for (symbol_index, export) in exports.into_iter().enumerate() {
let new_entry = elements::ExportEntry::new(
format!("{}_{}", prefix, symbol_index),
elements::Internal::Global(
(module.import_count(elements::ImportCountType::Global) + export) as _,
),
);
export_section(module)
.expect("added above if does not exists")
.entries_mut()
.push(new_entry);
}
}
fn export_section(module: &mut elements::Module) -> Option<&mut elements::ExportSection> {
for section in module.sections_mut() {
if let elements::Section::Export(sect) = section {
return Some(sect)
}
}
None
}
fn global_section(module: &mut elements::Module) -> Option<&mut elements::GlobalSection> {
for section in module.sections_mut() {
if let elements::Section::Global(sect) = section {
return Some(sect)
}
}
None
}
#[cfg(test)]
mod tests {
use super::export_mutable_globals;
use parity_wasm::elements;
fn parse_wat(source: &str) -> elements::Module {
let module_bytes = wat::parse_str(source).unwrap();
wasmparser::validate(&module_bytes).unwrap();
elements::deserialize_buffer(module_bytes.as_ref()).expect("failed to parse module")
}
macro_rules! test_export_global {
(name = $name:ident; input = $input:expr; expected = $expected:expr) => {
#[test]
fn $name() {
let mut input_module = parse_wat($input);
let expected_module = parse_wat($expected);
export_mutable_globals(&mut input_module, "exported_internal_global");
let actual_bytes = elements::serialize(input_module)
.expect("injected module must have a function body");
let expected_bytes = elements::serialize(expected_module)
.expect("injected module must have a function body");
let actual_wat = wasmprinter::print_bytes(actual_bytes).unwrap();
let expected_wat = wasmprinter::print_bytes(expected_bytes).unwrap();
if actual_wat != expected_wat {
for diff in diff::lines(&expected_wat, &actual_wat) {
match diff {
diff::Result::Left(l) => println!("-{}", l),
diff::Result::Both(l, _) => println!(" {}", l),
diff::Result::Right(r) => println!("+{}", r),
}
}
panic!()
}
}
};
}
test_export_global! {
name = simple;
input = r#"
(module
(global (;0;) (mut i32) (i32.const 1))
(global (;1;) (mut i32) (i32.const 0)))
"#;
expected = r#"
(module
(global (;0;) (mut i32) (i32.const 1))
(global (;1;) (mut i32) (i32.const 0))
(export "exported_internal_global_0" (global 0))
(export "exported_internal_global_1" (global 1)))
"#
}
test_export_global! {
name = with_import;
input = r#"
(module
(import "env" "global" (global $global i64))
(global (;0;) (mut i32) (i32.const 1))
(global (;1;) (mut i32) (i32.const 0)))
"#;
expected = r#"
(module
(import "env" "global" (global $global i64))
(global (;0;) (mut i32) (i32.const 1))
(global (;1;) (mut i32) (i32.const 0))
(export "exported_internal_global_0" (global 1))
(export "exported_internal_global_1" (global 2)))
"#
}
test_export_global! {
name = with_import_and_some_are_immutable;
input = r#"
(module
(import "env" "global" (global $global i64))
(global (;0;) i32 (i32.const 1))
(global (;1;) (mut i32) (i32.const 0)))
"#;
expected = r#"
(module
(import "env" "global" (global $global i64))
(global (;0;) i32 (i32.const 1))
(global (;1;) (mut i32) (i32.const 0))
(export "exported_internal_global_0" (global 2)))
"#
}
}
-207
View File
@@ -1,207 +0,0 @@
use std::string::String;
use std::vec::Vec;
use std::borrow::ToOwned;
use parity_wasm::{elements, builder};
use optimizer::{import_section, export_section};
use byteorder::{LittleEndian, ByteOrder};
type Insertion = (usize, u32, u32, String);
pub fn update_call_index(opcodes: &mut elements::Opcodes, original_imports: usize, inserts: &[Insertion]) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Call(ref mut call_index) => {
if let Some(pos) = inserts.iter().position(|x| x.1 == *call_index) {
*call_index = (original_imports + pos) as u32;
} else if *call_index as usize > original_imports {
*call_index += inserts.len() as u32;
}
},
_ => { }
}
}
}
pub fn memory_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::MemorySection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Memory(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn externalize_mem(mut module: elements::Module, adjust_pages: Option<u32>, max_pages: u32) -> elements::Module {
let mut entry = memory_section(&mut module)
.expect("Memory section to exist")
.entries_mut()
.pop()
.expect("Own memory entry to exist in memory section");
if let Some(adjust_pages) = adjust_pages {
assert!(adjust_pages <= max_pages);
entry = elements::MemoryType::new(adjust_pages, Some(max_pages));
}
if entry.limits().maximum().is_none() {
entry = elements::MemoryType::new(entry.limits().initial(), Some(max_pages));
}
let mut builder = builder::from_module(module);
builder.push_import(
elements::ImportEntry::new(
"env".to_owned(),
"memory".to_owned(),
elements::External::Memory(entry),
)
);
builder.build()
}
fn foreach_public_func_name<F>(mut module: elements::Module, f: F) -> elements::Module
where F: Fn(&mut String)
{
import_section(&mut module).map(|is| {
for entry in is.entries_mut() {
if let elements::External::Function(_) = *entry.external() {
f(entry.field_mut())
}
}
});
export_section(&mut module).map(|es| {
for entry in es.entries_mut() {
if let elements::Internal::Function(_) = *entry.internal() {
f(entry.field_mut())
}
}
});
module
}
pub fn underscore_funcs(module: elements::Module) -> elements::Module {
foreach_public_func_name(module, |n| n.insert(0, '_'))
}
pub fn ununderscore_funcs(module: elements::Module) -> elements::Module {
foreach_public_func_name(module, |n| { n.remove(0); })
}
pub fn shrink_unknown_stack(
mut module: elements::Module,
// for example, `shrink_amount = (1MB - 64KB)` will limit stack to 64KB
shrink_amount: u32,
) -> (elements::Module, u32) {
let mut new_stack_top = 0;
for section in module.sections_mut() {
match section {
&mut elements::Section::Data(ref mut data_section) => {
for ref mut data_segment in data_section.entries_mut() {
if data_segment.offset().code() == &[elements::Opcode::I32Const(4), elements::Opcode::End] {
assert_eq!(data_segment.value().len(), 4);
let current_val = LittleEndian::read_u32(data_segment.value());
let new_val = current_val - shrink_amount;
LittleEndian::write_u32(data_segment.value_mut(), new_val);
new_stack_top = new_val;
}
}
},
_ => continue
}
}
(module, new_stack_top)
}
pub fn externalize(
module: elements::Module,
replaced_funcs: Vec<&str>,
) -> elements::Module {
// Save import functions number for later
let import_funcs_total = module
.import_section().expect("Import section to exist")
.entries()
.iter()
.filter(|e| if let &elements::External::Function(_) = e.external() { true } else { false })
.count();
// First, we find functions indices that are to be rewired to externals
// Triple is (function_index (callable), type_index, function_name)
let mut replaces: Vec<Insertion> = replaced_funcs
.into_iter()
.filter_map(|f| {
let export = module
.export_section().expect("Export section to exist")
.entries().iter().enumerate()
.find(|&(_, entry)| entry.field() == f)
.expect("All functions of interest to exist");
if let &elements::Internal::Function(func_idx) = export.1.internal() {
let type_ref = module
.function_section().expect("Functions section to exist")
.entries()[func_idx as usize - import_funcs_total]
.type_ref();
Some((export.0, func_idx, type_ref, export.1.field().to_owned()))
} else {
None
}
})
.collect();
replaces.sort_by_key(|e| e.0);
// Second, we duplicate them as import definitions
let mut mbuilder = builder::from_module(module);
for &(_, _, type_ref, ref field) in replaces.iter() {
mbuilder.push_import(
builder::import()
.module("env")
.field(field)
.external().func(type_ref)
.build()
);
}
// Back to mutable access
let mut module = mbuilder.build();
// Third, rewire all calls to imported functions and update all other calls indices
for section in module.sections_mut() {
match section {
&mut elements::Section::Code(ref mut code_section) => {
for ref mut func_body in code_section.bodies_mut() {
update_call_index(func_body.code_mut(), import_funcs_total, &replaces);
}
},
&mut elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
},
_ => {}
}
}
},
&mut elements::Section::Element(ref mut elements_section) => {
for ref mut segment in elements_section.entries_mut() {
// update all indirect call addresses initial values
for func_index in segment.members_mut() {
if *func_index >= import_funcs_total as u32 { *func_index += replaces.len() as u32; }
}
}
},
_ => { }
}
}
module
}
-614
View File
@@ -1,614 +0,0 @@
use std::vec::Vec;
use parity_wasm::{elements, builder};
use rules;
pub fn update_call_index(opcodes: &mut elements::Opcodes, inserted_index: u32) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Call(ref mut call_index) => {
if *call_index >= inserted_index { *call_index += 1}
},
_ => { },
}
}
}
/// A block of code represented by it's start position and cost.
///
/// The block typically starts with instructions such as `loop`, `block`, `if`, etc.
///
/// An example of block:
///
/// ```ignore
/// loop
/// i32.const 1
/// get_local 0
/// i32.sub
/// tee_local 0
/// br_if 0
/// end
/// ```
///
/// The start of the block is `i32.const 1`.
///
#[derive(Debug)]
struct BlockEntry {
/// Index of the first instruction (aka `Opcode`) in the block.
start_pos: usize,
/// Sum of costs of all instructions until end of the block.
cost: u32,
}
struct Counter {
/// All blocks in the order of theirs start position.
blocks: Vec<BlockEntry>,
// Stack of blocks. Each element is an index to a `self.blocks` vector.
stack: Vec<usize>,
}
impl Counter {
fn new() -> Counter {
Counter {
stack: Vec::new(),
blocks: Vec::new(),
}
}
/// Begin a new block.
fn begin(&mut self, cursor: usize) {
let block_idx = self.blocks.len();
self.blocks.push(BlockEntry {
start_pos: cursor,
cost: 1,
});
self.stack.push(block_idx);
}
/// Finalize the current block.
///
/// Finalized blocks have final cost which will not change later.
fn finalize(&mut self) -> Result<(), ()> {
self.stack.pop().ok_or_else(|| ())?;
Ok(())
}
/// Increment the cost of the current block by the specified value.
fn increment(&mut self, val: u32) -> Result<(), ()> {
let stack_top = self.stack.last_mut().ok_or_else(|| ())?;
let top_block = self.blocks.get_mut(*stack_top).ok_or_else(|| ())?;
top_block.cost = top_block.cost.checked_add(val).ok_or_else(|| ())?;
Ok(())
}
}
fn inject_grow_counter(opcodes: &mut elements::Opcodes, grow_counter_func: u32) -> usize {
use parity_wasm::elements::Opcode::*;
let mut counter = 0;
for opcode in opcodes.elements_mut() {
match *opcode {
GrowMemory(_) => {
*opcode = Call(grow_counter_func);
counter += 1;
},
_ => {}
}
}
counter
}
fn add_grow_counter(module: elements::Module, rules: &rules::Set, gas_func: u32) -> elements::Module {
use parity_wasm::elements::Opcode::*;
let mut b = builder::from_module(module);
b.push_function(
builder::function()
.signature().params().i32().build().with_return_type(Some(elements::ValueType::I32)).build()
.body()
.with_opcodes(elements::Opcodes::new(vec![
GetLocal(0),
GetLocal(0),
I32Const(rules.grow_cost() as i32),
I32Mul,
// todo: there should be strong guarantee that it does not return anything on stack?
Call(gas_func),
GrowMemory(0),
End,
]))
.build()
.build()
);
b.build()
}
pub fn inject_counter(
opcodes: &mut elements::Opcodes,
rules: &rules::Set,
gas_func: u32,
) -> Result<(), ()> {
use parity_wasm::elements::Opcode::*;
let mut counter = Counter::new();
// Begin an implicit function (i.e. `func...end`) block.
counter.begin(0);
for cursor in 0..opcodes.elements().len() {
let opcode = &opcodes.elements()[cursor];
match *opcode {
Block(_) | If(_) | Loop(_) => {
// Increment previous block with the cost of the current opcode.
let opcode_cost = rules.process(opcode)?;
counter.increment(opcode_cost)?;
// Begin new block. The cost of the following opcodes until `End` or `Else` will
// be included into this block.
counter.begin(cursor + 1);
}
End => {
// Just finalize current block.
counter.finalize()?;
},
Else => {
// `Else` opcode is being encountered. So the case we are looking at:
//
// if
// ...
// else <-- cursor
// ...
// end
//
// Finalize the current block ('then' part of the if statement),
// and begin another one for the 'else' part.
counter.finalize()?;
counter.begin(cursor + 1);
}
_ => {
// An ordinal non control flow instruction. Just increment the cost of the current block.
let opcode_cost = rules.process(opcode)?;
counter.increment(opcode_cost)?;
}
}
}
// Then insert metering calls.
let mut cumulative_offset = 0;
for block in counter.blocks {
let effective_pos = block.start_pos + cumulative_offset;
opcodes.elements_mut().insert(effective_pos, I32Const(block.cost as i32));
opcodes.elements_mut().insert(effective_pos+1, Call(gas_func));
// Take into account these two inserted instructions.
cumulative_offset += 2;
}
Ok(())
}
/// Injects gas counter.
///
/// Can only fail if encounters operation forbidden by gas rules,
/// in this case it returns error with the original module.
pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
-> Result<elements::Module, elements::Module>
{
// Injecting gas counting external
let mut mbuilder = builder::from_module(module);
let import_sig = mbuilder.push_signature(
builder::signature()
.param().i32()
.build_sig()
);
mbuilder.push_import(
builder::import()
.module("env")
.field("gas")
.external().func(import_sig)
.build()
);
// back to plain module
let mut module = mbuilder.build();
// calculate actual function index of the imported definition
// (substract all imports that are NOT functions)
let gas_func = module.import_count(elements::ImportCountType::Function) as u32 - 1;
let total_func = module.functions_space() as u32;
let mut need_grow_counter = false;
let mut error = false;
// Updating calling addresses (all calls to function index >= `gas_func` should be incremented)
for section in module.sections_mut() {
match section {
&mut elements::Section::Code(ref mut code_section) => {
for ref mut func_body in code_section.bodies_mut() {
update_call_index(func_body.code_mut(), gas_func);
if let Err(_) = inject_counter(func_body.code_mut(), rules, gas_func) {
error = true;
break;
}
if rules.grow_cost() > 0 {
if inject_grow_counter(func_body.code_mut(), total_func) > 0 {
need_grow_counter = true;
}
}
}
},
&mut elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= gas_func { *func_index += 1}
},
_ => {}
}
}
},
&mut elements::Section::Element(ref mut elements_section) => {
for ref mut segment in elements_section.entries_mut() {
// update all indirect call addresses initial values
for func_index in segment.members_mut() {
if *func_index >= gas_func { *func_index += 1}
}
}
},
_ => { }
}
}
if error { return Err(module); }
if need_grow_counter { Ok(add_grow_counter(module, rules, gas_func)) } else { Ok(module) }
}
#[cfg(test)]
mod tests {
extern crate wabt;
use parity_wasm::{serialize, builder, elements};
use super::*;
use rules;
#[test]
fn simple_grow() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
GetGlobal(0),
GrowMemory(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &rules::Set::default().with_grow_cost(10000)).unwrap();
assert_eq!(
&vec![
I32Const(3),
Call(0),
GetGlobal(0),
Call(2),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[0]
.code().elements()
);
assert_eq!(
&vec![
GetLocal(0),
GetLocal(0),
I32Const(10000),
I32Mul,
Call(0),
GrowMemory(0),
End,
][..],
injected_module
.code_section().expect("function section should exist").bodies()[1]
.code().elements()
);
let binary = serialize(injected_module).expect("serialization failed");
self::wabt::wasm2wat(&binary).unwrap();
}
#[test]
fn grow_no_gas_no_track() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
GetGlobal(0),
GrowMemory(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &rules::Set::default()).unwrap();
assert_eq!(
&vec![
I32Const(3),
Call(0),
GetGlobal(0),
GrowMemory(0),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[0]
.code().elements()
);
assert_eq!(injected_module.functions_space(), 2);
let binary = serialize(injected_module).expect("serialization failed");
self::wabt::wasm2wat(&binary).unwrap();
}
#[test]
fn simple() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
GetGlobal(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
assert_eq!(
&vec![
I32Const(2),
Call(0),
GetGlobal(0),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[0]
.code().elements()
);
}
#[test]
fn nested() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
GetGlobal(0),
Block(elements::BlockType::NoResult),
GetGlobal(0),
GetGlobal(0),
GetGlobal(0),
End,
GetGlobal(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
assert_eq!(
&vec![
I32Const(4),
Call(0),
GetGlobal(0),
Block(elements::BlockType::NoResult),
I32Const(4),
Call(0),
GetGlobal(0),
GetGlobal(0),
GetGlobal(0),
End,
GetGlobal(0),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[0]
.code().elements()
);
}
#[test]
fn ifelse() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
GetGlobal(0),
If(elements::BlockType::NoResult),
GetGlobal(0),
GetGlobal(0),
GetGlobal(0),
Else,
GetGlobal(0),
GetGlobal(0),
End,
GetGlobal(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
assert_eq!(
&vec![
I32Const(4),
Call(0),
GetGlobal(0),
If(elements::BlockType::NoResult),
I32Const(4),
Call(0),
GetGlobal(0),
GetGlobal(0),
GetGlobal(0),
Else,
I32Const(3),
Call(0),
GetGlobal(0),
GetGlobal(0),
End,
GetGlobal(0),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[0]
.code().elements()
);
}
#[test]
fn call_index() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body().build()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
Call(0),
If(elements::BlockType::NoResult),
Call(0),
Call(0),
Call(0),
Else,
Call(0),
Call(0),
End,
Call(0),
End
]
))
.build()
.build()
.build();
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
assert_eq!(
&vec![
I32Const(4),
Call(0),
Call(1),
If(elements::BlockType::NoResult),
I32Const(4),
Call(0),
Call(1),
Call(1),
Call(1),
Else,
I32Const(3),
Call(0),
Call(1),
Call(1),
End,
Call(1),
End
][..],
injected_module
.code_section().expect("function section should exist").bodies()[1]
.code().elements()
);
}
#[test]
fn forbidden() {
use parity_wasm::elements::Opcode::*;
let module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
F32Const(555555),
End
]
))
.build()
.build()
.build();
let rules = rules::Set::default().with_forbidden_floats();
if let Err(_) = inject_gas_counter(module, &rules) { }
else { panic!("Should be error because of the forbidden operation")}
}
}
+139
View File
@@ -0,0 +1,139 @@
//! Provides backends for the gas metering instrumentation
use parity_wasm::elements;
/// Implementation details of the specific method of the gas metering.
#[derive(Clone)]
pub enum GasMeter {
/// Gas metering with an external function.
External {
/// Name of the module to import the gas function from.
module: &'static str,
/// Name of the external gas function to be imported.
function: &'static str,
},
/// Gas metering with a local function and a mutable global.
Internal {
/// Name of the mutable global to be exported.
global: &'static str,
/// Body of the local gas counting function to be injected.
func_instructions: elements::Instructions,
/// Cost of the gas function execution.
cost: u64,
},
}
use super::Rules;
/// Under the hood part of the gas metering mechanics.
pub trait Backend {
/// Provides the gas metering implementation details.
fn gas_meter<R: Rules>(self, module: &elements::Module, rules: &R) -> GasMeter;
}
/// Gas metering with an external host function.
pub mod host_function {
use super::{Backend, GasMeter, Rules};
use parity_wasm::elements::Module;
/// Injects invocations of the gas charging host function into each metering block.
pub struct Injector {
/// The name of the module to import the gas function from.
module: &'static str,
/// The name of the gas function to import.
name: &'static str,
}
impl Injector {
pub fn new(module: &'static str, name: &'static str) -> Self {
Self { module, name }
}
}
impl Backend for Injector {
fn gas_meter<R: Rules>(self, _module: &Module, _rules: &R) -> GasMeter {
GasMeter::External { module: self.module, function: self.name }
}
}
}
/// Gas metering with a mutable global.
///
/// # Note
///
/// Not for all execution engines this method gives performance wins compared to using an [external
/// host function](host_function). See benchmarks and size overhead tests for examples of how to
/// make measurements needed to decide which gas metering method is better for your particular case.
///
/// # Warning
///
/// It is not recommended to apply [stack limiter](crate::inject_stack_limiter) instrumentation to a
/// module instrumented with this type of gas metering. This could lead to a massive module size
/// bloat. This is a known issue to be fixed in upcoming versions.
pub mod mutable_global {
use super::{Backend, GasMeter, Rules};
use alloc::vec;
use parity_wasm::elements::{self, Instruction, Module};
/// Injects a mutable global variable and a local function to the module to track
/// current gas left.
///
/// The function is called in every metering block. In case of falling out of gas, the global is
/// set to the sentinel value `U64::MAX` and `unreachable` instruction is called. The execution
/// engine should take care of getting the current global value and setting it back in order to
/// sync the gas left value during an execution.
pub struct Injector {
/// The export name of the gas tracking global.
pub global_name: &'static str,
}
impl Injector {
pub fn new(global_name: &'static str) -> Self {
Self { global_name }
}
}
impl Backend for Injector {
fn gas_meter<R: Rules>(self, module: &Module, rules: &R) -> GasMeter {
let gas_global_idx = module.globals_space() as u32;
let func_instructions = vec![
Instruction::GetGlobal(gas_global_idx),
Instruction::GetLocal(0),
Instruction::I64GeU,
Instruction::If(elements::BlockType::NoResult),
Instruction::GetGlobal(gas_global_idx),
Instruction::GetLocal(0),
Instruction::I64Sub,
Instruction::SetGlobal(gas_global_idx),
Instruction::Else,
// sentinel val u64::MAX
Instruction::I64Const(-1i64), // non-charged instruction
Instruction::SetGlobal(gas_global_idx), // non-charged instruction
Instruction::Unreachable, // non-charged instruction
Instruction::End,
Instruction::End,
];
// calculate gas used for the gas charging func execution itself
let mut gas_fn_cost = func_instructions.iter().fold(0, |cost: u64, instruction| {
cost.saturating_add(rules.instruction_cost(instruction).unwrap_or(u32::MAX).into())
});
// don't charge for the instructions used to fail when out of gas
let fail_cost = [
Instruction::I64Const(-1i64), // non-charged instruction
Instruction::SetGlobal(gas_global_idx), // non-charged instruction
Instruction::Unreachable, // non-charged instruction
]
.iter()
.fold(0, |cost: u64, instruction| {
cost.saturating_add(rules.instruction_cost(instruction).unwrap_or(u32::MAX).into())
});
// the fail costs are a subset of the overall costs and hence this never underflows
gas_fn_cost -= fail_cost;
GasMeter::Internal {
global: self.global_name,
func_instructions: elements::Instructions::new(func_instructions),
cost: gas_fn_cost,
}
}
}
}
File diff suppressed because it is too large Load Diff
+367
View File
@@ -0,0 +1,367 @@
//! This module is used to validate the correctness of the gas metering algorithm.
//!
//! Since the gas metering algorithm is complex, this checks correctness by fuzzing. The testing
//! strategy is to generate random, valid Wasm modules using Binaryen's translate-to-fuzz
//! functionality, then ensure for all functions defined, in all execution paths though the
//! function body that do not trap that the amount of gas charged by the proposed metering
//! instructions is correct. This is done by constructing a control flow graph and exhaustively
//! searching through all paths, which may take exponential time in the size of the function body in
//! the worst case.
use super::{ConstantCostRules, MeteredBlock, Rules};
use parity_wasm::elements::{FuncBody, Instruction};
use std::collections::BTreeMap as Map;
/// An ID for a node in a ControlFlowGraph.
type NodeId = usize;
/// A node in a control flow graph is commonly known as a basic block. This is a sequence of
/// operations that are always executed sequentially.
#[derive(Debug, Default)]
struct ControlFlowNode {
/// The index of the first instruction in the basic block. This is only used for debugging.
first_instr_pos: Option<usize>,
/// The actual gas cost of executing all instructions in the basic block.
actual_cost: u64,
/// The amount of gas charged by the injected metering instructions within this basic block.
charged_cost: u64,
/// Whether there are any other nodes in the graph that loop back to this one. Every cycle in
/// the control flow graph contains at least one node with this flag set.
is_loop_target: bool,
/// Edges in the "forward" direction of the graph. The graph of nodes and their forward edges
/// forms a directed acyclic graph (DAG).
forward_edges: Vec<NodeId>,
/// Edges in the "backwards" direction. These edges form cycles in the graph.
loopback_edges: Vec<NodeId>,
}
/// A control flow graph where nodes are basic blocks and edges represent possible transitions
/// between them in execution flow. The graph has two types of edges, forward and loop-back edges.
/// The subgraph with only the forward edges forms a directed acyclic graph (DAG); including the
/// loop-back edges introduces cycles.
#[derive(Debug)]
pub struct ControlFlowGraph {
nodes: Vec<ControlFlowNode>,
}
impl ControlFlowGraph {
fn new() -> Self {
ControlFlowGraph { nodes: Vec::new() }
}
fn get_node(&self, node_id: NodeId) -> &ControlFlowNode {
self.nodes.get(node_id).unwrap()
}
fn get_node_mut(&mut self, node_id: NodeId) -> &mut ControlFlowNode {
self.nodes.get_mut(node_id).unwrap()
}
fn add_node(&mut self) -> NodeId {
self.nodes.push(ControlFlowNode::default());
self.nodes.len() - 1
}
fn increment_actual_cost(&mut self, node_id: NodeId, cost: u32) {
self.get_node_mut(node_id).actual_cost += u64::from(cost);
}
fn increment_charged_cost(&mut self, node_id: NodeId, cost: u64) {
self.get_node_mut(node_id).charged_cost += cost;
}
fn set_first_instr_pos(&mut self, node_id: NodeId, first_instr_pos: usize) {
self.get_node_mut(node_id).first_instr_pos = Some(first_instr_pos)
}
fn new_edge(&mut self, from_id: NodeId, target_frame: &ControlFrame) {
if target_frame.is_loop {
self.new_loopback_edge(from_id, target_frame.entry_node);
} else {
self.new_forward_edge(from_id, target_frame.exit_node);
}
}
fn new_forward_edge(&mut self, from_id: NodeId, to_id: NodeId) {
self.get_node_mut(from_id).forward_edges.push(to_id)
}
fn new_loopback_edge(&mut self, from_id: NodeId, to_id: NodeId) {
self.get_node_mut(from_id).loopback_edges.push(to_id);
self.get_node_mut(to_id).is_loop_target = true;
}
}
/// A control frame is opened upon entry into a function and by the `block`, `if`, and `loop`
/// instructions and is closed by `end` instructions.
struct ControlFrame {
is_loop: bool,
entry_node: NodeId,
exit_node: NodeId,
active_node: NodeId,
}
impl ControlFrame {
fn new(entry_node_id: NodeId, exit_node_id: NodeId, is_loop: bool) -> Self {
ControlFrame {
is_loop,
entry_node: entry_node_id,
exit_node: exit_node_id,
active_node: entry_node_id,
}
}
}
/// Construct a control flow graph from a function body and the metered blocks computed for it.
///
/// This assumes that the function body has been validated already, otherwise this may panic.
fn build_control_flow_graph(
body: &FuncBody,
rules: &impl Rules,
blocks: &[MeteredBlock],
) -> Result<ControlFlowGraph, ()> {
let mut graph = ControlFlowGraph::new();
let entry_node_id = graph.add_node();
let terminal_node_id = graph.add_node();
graph.set_first_instr_pos(entry_node_id, 0);
let mut stack = vec![ControlFrame::new(entry_node_id, terminal_node_id, false)];
let mut metered_blocks_iter = blocks.iter().peekable();
let locals_count = body
.locals()
.iter()
.try_fold(0u32, |count, val_type| count.checked_add(val_type.count()))
.ok_or(())?;
let locals_init_cost = rules.call_per_local_cost().checked_mul(locals_count).ok_or(())?;
for (cursor, instruction) in body.code().elements().iter().enumerate() {
let active_node_id = stack
.last()
.expect("module is valid by pre-condition; control stack must not be empty; qed")
.active_node;
// Increment the charged cost if there are metering instructions to be inserted here.
let apply_block =
metered_blocks_iter.peek().map_or(false, |block| block.start_pos == cursor);
if apply_block {
let next_metered_block =
metered_blocks_iter.next().expect("peek returned an item; qed");
graph.increment_charged_cost(active_node_id, next_metered_block.cost);
}
// Add locals initialization cost to the function block.
if cursor == 0 {
graph.increment_actual_cost(active_node_id, locals_init_cost);
}
let instruction_cost = rules.instruction_cost(instruction).ok_or(())?;
match instruction {
Instruction::Block(_) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let exit_node_id = graph.add_node();
stack.push(ControlFrame::new(active_node_id, exit_node_id, false));
},
Instruction::If(_) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let then_node_id = graph.add_node();
let exit_node_id = graph.add_node();
stack.push(ControlFrame::new(then_node_id, exit_node_id, false));
graph.new_forward_edge(active_node_id, then_node_id);
graph.set_first_instr_pos(then_node_id, cursor + 1);
},
Instruction::Loop(_) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let loop_node_id = graph.add_node();
let exit_node_id = graph.add_node();
stack.push(ControlFrame::new(loop_node_id, exit_node_id, true));
graph.new_forward_edge(active_node_id, loop_node_id);
graph.set_first_instr_pos(loop_node_id, cursor + 1);
},
Instruction::Else => {
let active_frame_idx = stack.len() - 1;
let prev_frame_idx = stack.len() - 2;
let else_node_id = graph.add_node();
stack[active_frame_idx].active_node = else_node_id;
let prev_node_id = stack[prev_frame_idx].active_node;
graph.new_forward_edge(prev_node_id, else_node_id);
graph.set_first_instr_pos(else_node_id, cursor + 1);
},
Instruction::End => {
let closing_frame = stack.pop()
.expect("module is valid by pre-condition; ends correspond to control stack frames; qed");
graph.new_forward_edge(active_node_id, closing_frame.exit_node);
graph.set_first_instr_pos(closing_frame.exit_node, cursor + 1);
if let Some(active_frame) = stack.last_mut() {
active_frame.active_node = closing_frame.exit_node;
}
},
Instruction::Br(label) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let active_frame_idx = stack.len() - 1;
let target_frame_idx = active_frame_idx - (*label as usize);
graph.new_edge(active_node_id, &stack[target_frame_idx]);
// Next instruction is unreachable, but carry on anyway.
let new_node_id = graph.add_node();
stack[active_frame_idx].active_node = new_node_id;
graph.set_first_instr_pos(new_node_id, cursor + 1);
},
Instruction::BrIf(label) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let active_frame_idx = stack.len() - 1;
let target_frame_idx = active_frame_idx - (*label as usize);
graph.new_edge(active_node_id, &stack[target_frame_idx]);
let new_node_id = graph.add_node();
stack[active_frame_idx].active_node = new_node_id;
graph.new_forward_edge(active_node_id, new_node_id);
graph.set_first_instr_pos(new_node_id, cursor + 1);
},
Instruction::BrTable(br_table_data) => {
graph.increment_actual_cost(active_node_id, instruction_cost);
let active_frame_idx = stack.len() - 1;
for &label in [br_table_data.default].iter().chain(br_table_data.table.iter()) {
let target_frame_idx = active_frame_idx - (label as usize);
graph.new_edge(active_node_id, &stack[target_frame_idx]);
}
let new_node_id = graph.add_node();
stack[active_frame_idx].active_node = new_node_id;
graph.set_first_instr_pos(new_node_id, cursor + 1);
},
Instruction::Return => {
graph.increment_actual_cost(active_node_id, instruction_cost);
graph.new_forward_edge(active_node_id, terminal_node_id);
let active_frame_idx = stack.len() - 1;
let new_node_id = graph.add_node();
stack[active_frame_idx].active_node = new_node_id;
graph.set_first_instr_pos(new_node_id, cursor + 1);
},
_ => graph.increment_actual_cost(active_node_id, instruction_cost),
}
}
assert!(stack.is_empty());
Ok(graph)
}
/// Exhaustively search through all paths in the control flow graph, starting from the first node
/// and ensure that 1) all paths with only forward edges ending with the terminal node have an
/// equal total actual gas cost and total charged gas cost, and 2) all cycles beginning with a loop
/// entry point and ending with a node with a loop-back edge to the entry point have equal actual
/// and charged gas costs. If this returns true, then the metered blocks used to construct the
/// control flow graph are correct with respect to the function body.
///
/// In the worst case, this runs in time exponential in the size of the graph.
fn validate_graph_gas_costs(graph: &ControlFlowGraph) -> bool {
fn visit(
graph: &ControlFlowGraph,
node_id: NodeId,
mut total_actual: u64,
mut total_charged: u64,
loop_costs: &mut Map<NodeId, (u64, u64)>,
) -> bool {
let node = graph.get_node(node_id);
total_actual += node.actual_cost;
total_charged += node.charged_cost;
if node.is_loop_target {
loop_costs.insert(node_id, (node.actual_cost, node.charged_cost));
}
if node.forward_edges.is_empty() && total_actual != total_charged {
return false
}
for loop_node_id in node.loopback_edges.iter() {
let (loop_actual, loop_charged) = loop_costs
.get_mut(loop_node_id)
.expect("cannot arrive at loopback edge without visiting loop entry node");
if loop_actual != loop_charged {
return false
}
}
for next_node_id in node.forward_edges.iter() {
if !visit(graph, *next_node_id, total_actual, total_charged, loop_costs) {
return false
}
}
if node.is_loop_target {
loop_costs.remove(&node_id);
}
true
}
// Recursively explore all paths through the execution graph starting from the entry node.
visit(graph, 0, 0, 0, &mut Map::new())
}
/// Validate that the metered blocks are correct with respect to the function body by exhaustively
/// searching all paths through the control flow graph.
///
/// This assumes that the function body has been validated already, otherwise this may panic.
fn validate_metering_injections(
body: &FuncBody,
rules: &impl Rules,
blocks: &[MeteredBlock],
) -> Result<bool, ()> {
let graph = build_control_flow_graph(body, rules, blocks)?;
Ok(validate_graph_gas_costs(&graph))
}
mod tests {
use super::{super::determine_metered_blocks, *};
use binaryen::tools::translate_to_fuzz_mvp;
use parity_wasm::elements;
use rand::{thread_rng, RngCore};
#[test]
fn test_build_control_flow_graph() {
for _ in 0..20 {
let mut rand_input = [0u8; 2048];
thread_rng().fill_bytes(&mut rand_input);
let module_bytes = translate_to_fuzz_mvp(&rand_input).write();
let module: elements::Module = elements::deserialize_buffer(&module_bytes)
.expect("failed to parse Wasm blob generated by translate_to_fuzz");
for func_body in module.code_section().iter().flat_map(|section| section.bodies()) {
let rules = ConstantCostRules::default();
let locals_count = func_body.locals().iter().map(|val_type| val_type.count()).sum();
let metered_blocks =
determine_metered_blocks(func_body.code(), &rules, locals_count).unwrap();
let success =
validate_metering_injections(func_body, &rules, &metered_blocks).unwrap();
assert!(success);
}
}
}
}
+6 -36
View File
@@ -1,41 +1,11 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
extern crate parity_wasm;
extern crate byteorder;
#[macro_use] extern crate log;
mod export_globals;
pub mod gas_metering;
mod stack_limiter;
pub static CREATE_SYMBOL: &'static str = "deploy";
pub static CALL_SYMBOL: &'static str = "call";
pub static RET_SYMBOL: &'static str = "ret";
pub mod rules;
mod optimizer;
mod gas;
mod symbols;
mod ext;
mod pack;
mod runtime_type;
pub mod stack_height;
pub use optimizer::{optimize, Error as OptimizerError};
pub use gas::inject_gas_counter;
pub use ext::{externalize, externalize_mem, underscore_funcs, ununderscore_funcs, shrink_unknown_stack};
pub use pack::{pack_instance, Error as PackingError};
pub use runtime_type::inject_runtime_type;
#[cfg(not(feature = "std"))]
mod std {
pub use core::*;
pub use alloc::{vec, string, boxed, borrow};
pub mod collections {
pub use alloc::{BTreeMap, BTreeSet};
}
}
pub use export_globals::export_mutable_globals;
pub use parity_wasm;
pub use stack_limiter::inject as inject_stack_limiter;
-623
View File
@@ -1,623 +0,0 @@
#[cfg(features = "std")]
use std::collections::{HashSet as Set};
#[cfg(not(features = "std"))]
use std::collections::{BTreeSet as Set};
use std::vec::Vec;
use parity_wasm::elements;
use symbols::{Symbol, expand_symbols, push_code_symbols, resolve_function};
#[derive(Debug)]
pub enum Error {
/// Since optimizer starts with export entries, export
/// section is supposed to exist.
NoExportSection,
}
pub fn optimize(
module: &mut elements::Module, // Module to optimize
used_exports: Vec<&str>, // List of only exports that will be usable after optimization
) -> Result<(), Error> {
// WebAssembly exports optimizer
// Motivation: emscripten compiler backend compiles in many unused exports
// which in turn compile in unused imports and leaves unused functions
// Algo starts from the top, listing all items that should stay
let mut stay = Set::new();
for (index, entry) in module.export_section().ok_or(Error::NoExportSection)?.entries().iter().enumerate() {
if used_exports.iter().find(|e| **e == entry.field()).is_some() {
stay.insert(Symbol::Export(index));
}
}
// If there is start function in module, it should stary
module.start_section().map(|ss| stay.insert(resolve_function(&module, ss)));
// All symbols used in data/element segments are also should be preserved
let mut init_symbols = Vec::new();
if let Some(data_section) = module.data_section() {
for segment in data_section.entries() {
push_code_symbols(&module, segment.offset().code(), &mut init_symbols);
}
}
if let Some(elements_section) = module.elements_section() {
for segment in elements_section.entries() {
push_code_symbols(&module, segment.offset().code(), &mut init_symbols);
for func_index in segment.members() {
stay.insert(resolve_function(&module, *func_index));
}
}
}
for symbol in init_symbols.drain(..) { stay.insert(symbol); }
// Call function which will traverse the list recursively, filling stay with all symbols
// that are already used by those which already there
expand_symbols(module, &mut stay);
for symbol in stay.iter() {
trace!("symbol to stay: {:?}", symbol);
}
// Keep track of referreable symbols to rewire calls/globals
let mut eliminated_funcs = Vec::new();
let mut eliminated_globals = Vec::new();
let mut eliminated_types = Vec::new();
// First, iterate through types
let mut index = 0;
let mut old_index = 0;
{
loop {
if type_section(module).map(|section| section.types_mut().len()).unwrap_or(0) == index { break; }
if stay.contains(&Symbol::Type(old_index)) {
index += 1;
} else {
type_section(module)
.expect("If type section does not exists, the loop will break at the beginning of first iteration")
.types_mut().remove(index);
eliminated_types.push(old_index);
trace!("Eliminated type({})", old_index);
}
old_index += 1;
}
}
// Second, iterate through imports
let mut top_funcs = 0;
let mut top_globals = 0;
index = 0;
old_index = 0;
if let Some(imports) = import_section(module) {
loop {
let mut remove = false;
match imports.entries()[index].external() {
&elements::External::Function(_) => {
if stay.contains(&Symbol::Import(old_index)) {
index += 1;
} else {
remove = true;
eliminated_funcs.push(top_funcs);
trace!("Eliminated import({}) func({}, {})", old_index, top_funcs, imports.entries()[index].field());
}
top_funcs += 1;
},
&elements::External::Global(_) => {
if stay.contains(&Symbol::Import(old_index)) {
index += 1;
} else {
remove = true;
eliminated_globals.push(top_globals);
trace!("Eliminated import({}) global({}, {})", old_index, top_globals, imports.entries()[index].field());
}
top_globals += 1;
},
_ => {
index += 1;
}
}
if remove {
imports.entries_mut().remove(index);
}
old_index += 1;
if index == imports.entries().len() { break; }
}
}
// Third, iterate through globals
if let Some(globals) = global_section(module) {
index = 0;
old_index = 0;
loop {
if globals.entries_mut().len() == index { break; }
if stay.contains(&Symbol::Global(old_index)) {
index += 1;
} else {
globals.entries_mut().remove(index);
eliminated_globals.push(top_globals + old_index);
trace!("Eliminated global({})", top_globals + old_index);
}
old_index += 1;
}
}
// Forth, delete orphaned functions
if function_section(module).is_some() && code_section(module).is_some() {
index = 0;
old_index = 0;
loop {
if function_section(module).expect("Functons section to exist").entries_mut().len() == index { break; }
if stay.contains(&Symbol::Function(old_index)) {
index += 1;
} else {
function_section(module).expect("Functons section to exist").entries_mut().remove(index);
code_section(module).expect("Code section to exist").bodies_mut().remove(index);
eliminated_funcs.push(top_funcs + old_index);
trace!("Eliminated function({})", top_funcs + old_index);
}
old_index += 1;
}
}
// Fifth, eliminate unused exports
{
let exports = export_section(module).ok_or(Error::NoExportSection)?;
index = 0;
old_index = 0;
loop {
if exports.entries_mut().len() == index { break; }
if stay.contains(&Symbol::Export(old_index)) {
index += 1;
} else {
trace!("Eliminated export({}, {})", old_index, exports.entries_mut()[index].field());
exports.entries_mut().remove(index);
}
old_index += 1;
}
}
if eliminated_globals.len() > 0 || eliminated_funcs.len() > 0 || eliminated_types.len() > 0 {
// Finaly, rewire all calls, globals references and types to the new indices
// (only if there is anything to do)
eliminated_globals.sort();
eliminated_funcs.sort();
eliminated_types.sort();
for section in module.sections_mut() {
match section {
&mut elements::Section::Start(ref mut func_index) if eliminated_funcs.len() > 0 => {
let totalle = eliminated_funcs.iter().take_while(|i| (**i as u32) < *func_index).count();
*func_index -= totalle as u32;
},
&mut elements::Section::Function(ref mut function_section) if eliminated_types.len() > 0 => {
for ref mut func_signature in function_section.entries_mut() {
let totalle = eliminated_types.iter().take_while(|i| (**i as u32) < func_signature.type_ref()).count();
*func_signature.type_ref_mut() -= totalle as u32;
}
},
&mut elements::Section::Import(ref mut import_section) if eliminated_types.len() > 0 => {
for ref mut import_entry in import_section.entries_mut() {
if let &mut elements::External::Function(ref mut type_ref) = import_entry.external_mut() {
let totalle = eliminated_types.iter().take_while(|i| (**i as u32) < *type_ref).count();
*type_ref -= totalle as u32;
}
}
},
&mut elements::Section::Code(ref mut code_section) if eliminated_globals.len() > 0 || eliminated_funcs.len() > 0 => {
for ref mut func_body in code_section.bodies_mut() {
if eliminated_funcs.len() > 0 {
update_call_index(func_body.code_mut(), &eliminated_funcs);
}
if eliminated_globals.len() > 0 {
update_global_index(func_body.code_mut().elements_mut(), &eliminated_globals)
}
if eliminated_types.len() > 0 {
update_type_index(func_body.code_mut(), &eliminated_types)
}
}
},
&mut elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
let totalle = eliminated_funcs.iter().take_while(|i| (**i as u32) < *func_index).count();
*func_index -= totalle as u32;
},
&mut elements::Internal::Global(ref mut global_index) => {
let totalle = eliminated_globals.iter().take_while(|i| (**i as u32) < *global_index).count();
*global_index -= totalle as u32;
},
_ => {}
}
}
},
&mut elements::Section::Global(ref mut global_section) => {
for ref mut global_entry in global_section.entries_mut() {
update_global_index(global_entry.init_expr_mut().code_mut(), &eliminated_globals)
}
},
&mut elements::Section::Data(ref mut data_section) => {
for ref mut segment in data_section.entries_mut() {
update_global_index(segment.offset_mut().code_mut(), &eliminated_globals)
}
},
&mut elements::Section::Element(ref mut elements_section) => {
for ref mut segment in elements_section.entries_mut() {
update_global_index(segment.offset_mut().code_mut(), &eliminated_globals);
// update all indirect call addresses initial values
for func_index in segment.members_mut() {
let totalle = eliminated_funcs.iter().take_while(|i| (**i as u32) < *func_index).count();
*func_index -= totalle as u32;
}
}
},
_ => { }
}
}
}
Ok(())
}
pub fn update_call_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut Call(ref mut call_index) => {
let totalle = eliminated_indices.iter().take_while(|i| (**i as u32) < *call_index).count();
trace!("rewired call {} -> call {}", *call_index, *call_index - totalle as u32);
*call_index -= totalle as u32;
},
_ => { },
}
}
}
/// Updates global references considering the _ordered_ list of eliminated indices
pub fn update_global_index(opcodes: &mut Vec<elements::Opcode>, eliminated_indices: &[usize]) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.iter_mut() {
match opcode {
&mut GetGlobal(ref mut index) | &mut SetGlobal(ref mut index) => {
let totalle = eliminated_indices.iter().take_while(|i| (**i as u32) < *index).count();
trace!("rewired global {} -> global {}", *index, *index - totalle as u32);
*index -= totalle as u32;
},
_ => { },
}
}
}
/// Updates global references considering the _ordered_ list of eliminated indices
pub fn update_type_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes.elements_mut().iter_mut() {
match opcode {
&mut CallIndirect(ref mut call_index, _) => {
let totalle = eliminated_indices.iter().take_while(|i| (**i as u32) < *call_index).count();
trace!("rewired call_indrect {} -> call_indirect {}", *call_index, *call_index - totalle as u32);
*call_index -= totalle as u32;
},
_ => { },
}
}
}
pub fn import_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::ImportSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Import(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn global_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::GlobalSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Global(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn function_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::FunctionSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Function(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn code_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::CodeSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Code(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn export_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::ExportSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Export(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
pub fn type_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::TypeSection> {
for section in module.sections_mut() {
match section {
&mut elements::Section::Type(ref mut sect) => {
return Some(sect);
},
_ => { }
}
}
None
}
#[cfg(test)]
mod tests {
use parity_wasm::{builder, elements};
use super::*;
/// @spec 0
/// Optimizer presumes that export section exists and contains
/// all symbols passed as a second parameter. Since empty module
/// obviously contains no export section, optimizer should return
/// error on it.
#[test]
fn empty() {
let mut module = builder::module().build();
let result = optimize(&mut module, vec!["_call"]);
assert!(result.is_err());
}
/// @spec 1
/// Imagine the unoptimized module has two own functions, `_call` and `_random`
/// and exports both of them in the export section. During optimization, the `_random`
/// function should vanish completely, given we pass `_call` as the only function to stay
/// in the module.
#[test]
fn minimal() {
let mut module = builder::module()
.function()
.signature().param().i32().build()
.build()
.function()
.signature()
.param().i32()
.param().i32()
.build()
.build()
.export()
.field("_call")
.internal().func(0).build()
.export()
.field("_random")
.internal().func(1).build()
.build();
assert_eq!(module.export_section().expect("export section to be generated").entries().len(), 2);
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
assert_eq!(
1,
module.export_section().expect("export section to be generated").entries().len(),
"There should only 1 (one) export entry in the optimized module"
);
assert_eq!(
1,
module.function_section().expect("functions section to be generated").entries().len(),
"There should 2 (two) functions in the optimized module"
);
}
/// @spec 2
/// Imagine there is one exported function in unoptimized module, `_call`, that we specify as the one
/// to stay during the optimization. The code of this function uses global during the execution.
/// This sayed global should survive the optimization.
#[test]
fn globals() {
let mut module = builder::module()
.global()
.value_type().i32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::GetGlobal(0),
elements::Opcode::End
]
))
.build()
.build()
.export()
.field("_call")
.internal().func(0).build()
.build();
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
assert_eq!(
1,
module.global_section().expect("global section to be generated").entries().len(),
"There should 1 (one) global entry in the optimized module, since _call function uses it"
);
}
/// @spec 2
/// Imagine there is one exported function in unoptimized module, `_call`, that we specify as the one
/// to stay during the optimization. The code of this function uses one global during the execution,
/// but we have a bunch of other unused globals in the code. Last globals should not survive the optimization,
/// while the former should.
#[test]
fn globals_2() {
let mut module = builder::module()
.global()
.value_type().i32()
.build()
.global()
.value_type().i64()
.build()
.global()
.value_type().f32()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::GetGlobal(1),
elements::Opcode::End
]
))
.build()
.build()
.export()
.field("_call")
.internal().func(0).build()
.build();
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
assert_eq!(
1,
module.global_section().expect("global section to be generated").entries().len(),
"There should 1 (one) global entry in the optimized module, since _call function uses only one"
);
}
/// @spec 3
/// Imagine the unoptimized module has two own functions, `_call` and `_random`
/// and exports both of them in the export section. Function `_call` also calls `_random`
/// in its function body. The optimization should kick `_random` function from the export section
/// but preserve it's body.
#[test]
fn call_ref() {
let mut module = builder::module()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::Call(1),
elements::Opcode::End
]
))
.build()
.build()
.function()
.signature()
.param().i32()
.param().i32()
.build()
.build()
.export()
.field("_call")
.internal().func(0).build()
.export()
.field("_random")
.internal().func(1).build()
.build();
assert_eq!(module.export_section().expect("export section to be generated").entries().len(), 2);
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
assert_eq!(
1,
module.export_section().expect("export section to be generated").entries().len(),
"There should only 1 (one) export entry in the optimized module"
);
assert_eq!(
2,
module.function_section().expect("functions section to be generated").entries().len(),
"There should 2 (two) functions in the optimized module"
);
}
/// @spec 4
/// Imagine the unoptimized module has an indirect call to function of type 1
/// The type should persist so that indirect call would work
#[test]
fn call_indirect() {
let mut module = builder::module()
.function()
.signature().param().i32().param().i32().build()
.build()
.function()
.signature().param().i32().param().i32().build()
.build()
.function()
.signature().param().i32().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::CallIndirect(1, 0),
elements::Opcode::End
]
))
.build()
.build()
.export()
.field("_call")
.internal().func(2).build()
.build();
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
assert_eq!(
2,
module.type_section().expect("type section to be generated").types().len(),
"There should 2 (two) types left in the module, 1 for indirect call and one for _call"
);
let indirect_opcode = &module.code_section().expect("code section to be generated").bodies()[0].code().elements()[0];
match *indirect_opcode {
elements::Opcode::CallIndirect(0, 0) => {},
_ => {
panic!(
"Expected call_indirect to use index 0 after optimization, since previois 0th was eliminated, but got {:?}",
indirect_opcode
);
}
}
}
}
-338
View File
@@ -1,338 +0,0 @@
use std::fmt;
use std::vec::Vec;
use std::borrow::ToOwned;
use parity_wasm::elements::{
self, Section, DataSection, Opcode, DataSegment, InitExpr, Internal, External,
ImportCountType,
};
use parity_wasm::builder;
use super::{CREATE_SYMBOL, CALL_SYMBOL, RET_SYMBOL};
use super::gas::update_call_index;
/// Pack error.
///
/// Pack has number of assumptions of passed module structure.
/// When they are violated, pack_instance returns one of these.
#[derive(Debug)]
pub enum Error {
MalformedModule,
NoTypeSection,
NoExportSection,
NoCodeSection,
InvalidCreateSignature,
NoCreateSymbol,
InvalidCreateMember,
NoImportSection,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::MalformedModule => write!(f, "Module internal references are inconsistent"),
Error::NoTypeSection => write!(f, "No type section in the module"),
Error::NoExportSection => write!(f, "No export section in the module"),
Error::NoCodeSection => write!(f, "No code section inthe module"),
Error::InvalidCreateSignature => write!(f, "Exported symbol `deploy` has invalid signature, should be () -> ()"),
Error::InvalidCreateMember => write!(f, "Exported symbol `deploy` should be a function"),
Error::NoCreateSymbol => write!(f, "No exported `deploy` symbol"),
Error::NoImportSection => write!(f, "No import section in the module"),
}
}
}
/// If module has an exported "_create" function we want to pack it into "constructor".
/// `raw_module` is the actual contract code
/// `ctor_module` is the constructor which should return `raw_module`
pub fn pack_instance(raw_module: Vec<u8>, mut ctor_module: elements::Module) -> Result<elements::Module, Error> {
// Total number of constructor module import functions
let ctor_import_functions = ctor_module.import_section().map(|x| x.functions()).unwrap_or(0);
// We need to find an internal ID of function witch is exported as "_create"
// in order to find it in the Code section of the module
let mut create_func_id = {
let found_entry = ctor_module.export_section().ok_or(Error::NoExportSection)?.entries().iter()
.find(|entry| CREATE_SYMBOL == entry.field()).ok_or(Error::NoCreateSymbol)?;
let function_index: usize = match found_entry.internal() {
&Internal::Function(index) => index as usize,
_ => { return Err(Error::InvalidCreateMember) },
};
// Calculates a function index within module's function section
let function_internal_index = function_index - ctor_import_functions;
// Constructor should be of signature `func(i32)` (void), fail otherwise
let type_id = ctor_module.function_section().ok_or(Error::NoCodeSection)?
.entries().get(function_index - ctor_import_functions).ok_or(Error::MalformedModule)?
.type_ref();
let &elements::Type::Function(ref func) = ctor_module.type_section().ok_or(Error::NoTypeSection)?
.types().get(type_id as usize).ok_or(Error::MalformedModule)?;
// Deploy should have no arguments and also should return nothing
if !func.params().is_empty() {
return Err(Error::InvalidCreateSignature);
}
if func.return_type().is_some() {
return Err(Error::InvalidCreateSignature);
}
function_internal_index
};
let ret_function_id = {
let mut id = 0;
let mut found = false;
for entry in ctor_module.import_section().ok_or(Error::NoImportSection)?.entries().iter() {
if let External::Function(_) = *entry.external() {
if entry.field() == RET_SYMBOL { found = true; break; }
else { id += 1; }
}
}
if !found {
let mut mbuilder = builder::from_module(ctor_module);
let import_sig = mbuilder.push_signature(
builder::signature()
.param().i32().param().i32()
.build_sig()
);
mbuilder.push_import(
builder::import()
.module("env")
.field("ret")
.external().func(import_sig)
.build()
);
ctor_module = mbuilder.build();
let ret_func = ctor_module.import_count(ImportCountType::Function) as u32 - 1;
for section in ctor_module.sections_mut() {
match *section {
elements::Section::Code(ref mut code_section) => {
for ref mut func_body in code_section.bodies_mut() {
update_call_index(func_body.code_mut(), ret_func);
}
},
elements::Section::Export(ref mut export_section) => {
for ref mut export in export_section.entries_mut() {
match export.internal_mut() {
&mut elements::Internal::Function(ref mut func_index) => {
if *func_index >= ret_func { *func_index += 1}
},
_ => {}
}
}
},
elements::Section::Element(ref mut elements_section) => {
for ref mut segment in elements_section.entries_mut() {
// update all indirect call addresses initial values
for func_index in segment.members_mut() {
if *func_index >= ret_func { *func_index += 1}
}
}
},
_ => { }
}
}
create_func_id += 1;
ret_func
}
else { id }
};
// If new function is put in ctor module, it will have this callable index
let last_function_index = ctor_module.functions_space();
// We ensure here that module has the DataSection
if ctor_module
.sections()
.iter()
.find(|section| match **section { Section::Data(ref _d) => true, _ => false })
.is_none() {
// DataSection has to be the last non-custom section according the to the spec
ctor_module.sections_mut().push(Section::Data(DataSection::with_entries(vec![])));
}
// Code data address is an address where we put the contract's code (raw_module)
let mut code_data_address = 0i32;
for section in ctor_module.sections_mut() {
match section {
&mut Section::Data(ref mut data_section) => {
let (index, offset) = if let Some(ref entry) = data_section.entries().iter().last() {
if let Opcode::I32Const(offst) = entry.offset().code()[0] {
let len = entry.value().len() as i32;
let offst = offst as i32;
(entry.index(), offst + (len + 4) - len % 4)
} else {
(0, 0)
}
} else {
(0, 0)
};
let code_data = DataSegment::new(
index,
InitExpr::new(vec![Opcode::I32Const(offset), Opcode::End]),
raw_module.clone()
);
data_section.entries_mut().push(code_data);
code_data_address = offset;
},
_ => {;}
}
}
let mut new_module = builder::from_module(ctor_module)
.function()
.signature().build()
.body().with_opcodes(elements::Opcodes::new(
vec![
Opcode::Call((create_func_id + ctor_import_functions) as u32),
Opcode::I32Const(code_data_address),
Opcode::I32Const(raw_module.len() as i32),
Opcode::Call(ret_function_id as u32),
Opcode::End,
])).build()
.build()
.build();
for section in new_module.sections_mut() {
match section {
&mut Section::Export(ref mut export_section) => {
for entry in export_section.entries_mut().iter_mut() {
if CREATE_SYMBOL == entry.field() {
// change _create export name into default _call
*entry.field_mut() = CALL_SYMBOL.to_owned();
*entry.internal_mut() = elements::Internal::Function(last_function_index as u32);
}
}
},
_ => { },
}
};
Ok(new_module)
}
#[cfg(test)]
mod test {
extern crate parity_wasm;
use parity_wasm::builder;
use super::*;
use super::super::optimize;
fn test_packer(mut module: elements::Module) {
let mut ctor_module = module.clone();
optimize(&mut module, vec![CALL_SYMBOL]).expect("Optimizer to finish without errors");
optimize(&mut ctor_module, vec![CREATE_SYMBOL]).expect("Optimizer to finish without errors");
let raw_module = parity_wasm::serialize(module).unwrap();
let ctor_module = pack_instance(raw_module.clone(), ctor_module).expect("Packing failed");
let data_section = ctor_module.data_section().expect("Packed module has to have a data section");
let data_segment = data_section.entries().iter().last().expect("Packed module has to have a data section with at least one entry");
assert!(data_segment.value() == AsRef::<[u8]>::as_ref(&raw_module), "Last data segment should be equal to the raw module");
}
#[test]
fn no_data_section() {
test_packer(builder::module()
.import()
.module("env")
.field("memory")
.external().memory(1 as u32, Some(1 as u32))
.build()
.function()
.signature()
.params().i32().i32().build()
.build()
.body().build()
.build()
.function()
.signature().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::End
]
))
.build()
.build()
.function()
.signature().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::End
]
))
.build()
.build()
.export()
.field(CALL_SYMBOL)
.internal().func(1)
.build()
.export()
.field(CREATE_SYMBOL)
.internal().func(2)
.build()
.build()
);
}
#[test]
fn with_data_section() {
test_packer(builder::module()
.import()
.module("env")
.field("memory")
.external().memory(1 as u32, Some(1 as u32))
.build()
.data()
.offset(elements::Opcode::I32Const(16)).value(vec![0u8])
.build()
.function()
.signature()
.params().i32().i32().build()
.build()
.body().build()
.build()
.function()
.signature().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::End
]
))
.build()
.build()
.function()
.signature().build()
.body()
.with_opcodes(elements::Opcodes::new(
vec![
elements::Opcode::End
]
))
.build()
.build()
.export()
.field(CALL_SYMBOL)
.internal().func(1)
.build()
.export()
.field(CREATE_SYMBOL)
.internal().func(2)
.build()
.build()
);
}
}
-315
View File
@@ -1,315 +0,0 @@
#[cfg(features = "std")]
use std::collections::{HashMap as Map};
#[cfg(not(features = "std"))]
use std::collections::{BTreeMap as Map};
use parity_wasm::elements;
pub struct UnknownInstruction;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Metering {
Regular,
Forbidden,
Fixed(u32),
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum InstructionType {
Bit,
Add,
Mul,
Div,
Load,
Store,
Const,
FloatConst,
Local,
Global,
ControlFlow,
IntegerComparsion,
FloatComparsion,
Float,
Conversion,
FloatConversion,
Reinterpretation,
Unreachable,
Nop,
CurrentMemory,
GrowMemory,
}
impl ::std::str::FromStr for InstructionType {
type Err = UnknownInstruction;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"bit" => Ok(InstructionType::Bit),
"add" => Ok(InstructionType::Add),
"mul" => Ok(InstructionType::Mul),
"div" => Ok(InstructionType::Div),
"load" => Ok(InstructionType::Load),
"store" => Ok(InstructionType::Store),
"const" => Ok(InstructionType::Const),
"local" => Ok(InstructionType::Local),
"global" => Ok(InstructionType::Global),
"flow" => Ok(InstructionType::ControlFlow),
"integer_comp" => Ok(InstructionType::IntegerComparsion),
"float_comp" => Ok(InstructionType::FloatComparsion),
"float" => Ok(InstructionType::Float),
"conversion" => Ok(InstructionType::Conversion),
"float_conversion" => Ok(InstructionType::FloatConversion),
"reinterpret" => Ok(InstructionType::Reinterpretation),
"unreachable" => Ok(InstructionType::Unreachable),
"nop" => Ok(InstructionType::Nop),
"currrent_mem" => Ok(InstructionType::CurrentMemory),
"grow_mem" => Ok(InstructionType::GrowMemory),
_ => Err(UnknownInstruction),
}
}
}
impl InstructionType {
pub fn op(opcode: &elements::Opcode) -> Self {
use parity_wasm::elements::Opcode::*;
match *opcode {
Unreachable => InstructionType::Unreachable,
Nop => InstructionType::Nop,
Block(_) => InstructionType::ControlFlow,
Loop(_) => InstructionType::ControlFlow,
If(_) => InstructionType::ControlFlow,
Else => InstructionType::ControlFlow,
End => InstructionType::ControlFlow,
Br(_) => InstructionType::ControlFlow,
BrIf(_) => InstructionType::ControlFlow,
BrTable(_, _) => InstructionType::ControlFlow,
Return => InstructionType::ControlFlow,
Call(_) => InstructionType::ControlFlow,
CallIndirect(_, _) => InstructionType::ControlFlow,
Drop => InstructionType::ControlFlow,
Select => InstructionType::ControlFlow,
GetLocal(_) => InstructionType::Local,
SetLocal(_) => InstructionType::Local,
TeeLocal(_) => InstructionType::Local,
GetGlobal(_) => InstructionType::Local,
SetGlobal(_) => InstructionType::Local,
I32Load(_, _) => InstructionType::Load,
I64Load(_, _) => InstructionType::Load,
F32Load(_, _) => InstructionType::Load,
F64Load(_, _) => InstructionType::Load,
I32Load8S(_, _) => InstructionType::Load,
I32Load8U(_, _) => InstructionType::Load,
I32Load16S(_, _) => InstructionType::Load,
I32Load16U(_, _) => InstructionType::Load,
I64Load8S(_, _) => InstructionType::Load,
I64Load8U(_, _) => InstructionType::Load,
I64Load16S(_, _) => InstructionType::Load,
I64Load16U(_, _) => InstructionType::Load,
I64Load32S(_, _) => InstructionType::Load,
I64Load32U(_, _) => InstructionType::Load,
I32Store(_, _) => InstructionType::Store,
I64Store(_, _) => InstructionType::Store,
F32Store(_, _) => InstructionType::Store,
F64Store(_, _) => InstructionType::Store,
I32Store8(_, _) => InstructionType::Store,
I32Store16(_, _) => InstructionType::Store,
I64Store8(_, _) => InstructionType::Store,
I64Store16(_, _) => InstructionType::Store,
I64Store32(_, _) => InstructionType::Store,
CurrentMemory(_) => InstructionType::CurrentMemory,
GrowMemory(_) => InstructionType::GrowMemory,
I32Const(_) => InstructionType::Const,
I64Const(_) => InstructionType::Const,
F32Const(_) => InstructionType::FloatConst,
F64Const(_) => InstructionType::FloatConst,
I32Eqz => InstructionType::IntegerComparsion,
I32Eq => InstructionType::IntegerComparsion,
I32Ne => InstructionType::IntegerComparsion,
I32LtS => InstructionType::IntegerComparsion,
I32LtU => InstructionType::IntegerComparsion,
I32GtS => InstructionType::IntegerComparsion,
I32GtU => InstructionType::IntegerComparsion,
I32LeS => InstructionType::IntegerComparsion,
I32LeU => InstructionType::IntegerComparsion,
I32GeS => InstructionType::IntegerComparsion,
I32GeU => InstructionType::IntegerComparsion,
I64Eqz => InstructionType::IntegerComparsion,
I64Eq => InstructionType::IntegerComparsion,
I64Ne => InstructionType::IntegerComparsion,
I64LtS => InstructionType::IntegerComparsion,
I64LtU => InstructionType::IntegerComparsion,
I64GtS => InstructionType::IntegerComparsion,
I64GtU => InstructionType::IntegerComparsion,
I64LeS => InstructionType::IntegerComparsion,
I64LeU => InstructionType::IntegerComparsion,
I64GeS => InstructionType::IntegerComparsion,
I64GeU => InstructionType::IntegerComparsion,
F32Eq => InstructionType::FloatComparsion,
F32Ne => InstructionType::FloatComparsion,
F32Lt => InstructionType::FloatComparsion,
F32Gt => InstructionType::FloatComparsion,
F32Le => InstructionType::FloatComparsion,
F32Ge => InstructionType::FloatComparsion,
F64Eq => InstructionType::FloatComparsion,
F64Ne => InstructionType::FloatComparsion,
F64Lt => InstructionType::FloatComparsion,
F64Gt => InstructionType::FloatComparsion,
F64Le => InstructionType::FloatComparsion,
F64Ge => InstructionType::FloatComparsion,
I32Clz => InstructionType::Bit,
I32Ctz => InstructionType::Bit,
I32Popcnt => InstructionType::Bit,
I32Add => InstructionType::Add,
I32Sub => InstructionType::Add,
I32Mul => InstructionType::Mul,
I32DivS => InstructionType::Div,
I32DivU => InstructionType::Div,
I32RemS => InstructionType::Div,
I32RemU => InstructionType::Div,
I32And => InstructionType::Bit,
I32Or => InstructionType::Bit,
I32Xor => InstructionType::Bit,
I32Shl => InstructionType::Bit,
I32ShrS => InstructionType::Bit,
I32ShrU => InstructionType::Bit,
I32Rotl => InstructionType::Bit,
I32Rotr => InstructionType::Bit,
I64Clz => InstructionType::Bit,
I64Ctz => InstructionType::Bit,
I64Popcnt => InstructionType::Bit,
I64Add => InstructionType::Add,
I64Sub => InstructionType::Add,
I64Mul => InstructionType::Mul,
I64DivS => InstructionType::Div,
I64DivU => InstructionType::Div,
I64RemS => InstructionType::Div,
I64RemU => InstructionType::Div,
I64And => InstructionType::Bit,
I64Or => InstructionType::Bit,
I64Xor => InstructionType::Bit,
I64Shl => InstructionType::Bit,
I64ShrS => InstructionType::Bit,
I64ShrU => InstructionType::Bit,
I64Rotl => InstructionType::Bit,
I64Rotr => InstructionType::Bit,
F32Abs => InstructionType::Float,
F32Neg => InstructionType::Float,
F32Ceil => InstructionType::Float,
F32Floor => InstructionType::Float,
F32Trunc => InstructionType::Float,
F32Nearest => InstructionType::Float,
F32Sqrt => InstructionType::Float,
F32Add => InstructionType::Float,
F32Sub => InstructionType::Float,
F32Mul => InstructionType::Float,
F32Div => InstructionType::Float,
F32Min => InstructionType::Float,
F32Max => InstructionType::Float,
F32Copysign => InstructionType::Float,
F64Abs => InstructionType::Float,
F64Neg => InstructionType::Float,
F64Ceil => InstructionType::Float,
F64Floor => InstructionType::Float,
F64Trunc => InstructionType::Float,
F64Nearest => InstructionType::Float,
F64Sqrt => InstructionType::Float,
F64Add => InstructionType::Float,
F64Sub => InstructionType::Float,
F64Mul => InstructionType::Float,
F64Div => InstructionType::Float,
F64Min => InstructionType::Float,
F64Max => InstructionType::Float,
F64Copysign => InstructionType::Float,
I32WrapI64 => InstructionType::Conversion,
I64ExtendSI32 => InstructionType::Conversion,
I64ExtendUI32 => InstructionType::Conversion,
I32TruncSF32 => InstructionType::FloatConversion,
I32TruncUF32 => InstructionType::FloatConversion,
I32TruncSF64 => InstructionType::FloatConversion,
I32TruncUF64 => InstructionType::FloatConversion,
I64TruncSF32 => InstructionType::FloatConversion,
I64TruncUF32 => InstructionType::FloatConversion,
I64TruncSF64 => InstructionType::FloatConversion,
I64TruncUF64 => InstructionType::FloatConversion,
F32ConvertSI32 => InstructionType::FloatConversion,
F32ConvertUI32 => InstructionType::FloatConversion,
F32ConvertSI64 => InstructionType::FloatConversion,
F32ConvertUI64 => InstructionType::FloatConversion,
F32DemoteF64 => InstructionType::FloatConversion,
F64ConvertSI32 => InstructionType::FloatConversion,
F64ConvertUI32 => InstructionType::FloatConversion,
F64ConvertSI64 => InstructionType::FloatConversion,
F64ConvertUI64 => InstructionType::FloatConversion,
F64PromoteF32 => InstructionType::FloatConversion,
I32ReinterpretF32 => InstructionType::Reinterpretation,
I64ReinterpretF64 => InstructionType::Reinterpretation,
F32ReinterpretI32 => InstructionType::Reinterpretation,
F64ReinterpretI64 => InstructionType::Reinterpretation,
}
}
}
#[derive(Debug)]
pub struct Set {
regular: u32,
entries: Map<InstructionType, Metering>,
grow: u32,
}
impl Default for Set {
fn default() -> Self {
Set {
regular: 1,
entries: Map::new(),
grow: 0,
}
}
}
impl Set {
pub fn new(regular: u32, entries: Map<InstructionType, Metering>) -> Self {
Set { regular: regular, entries: entries, grow: 0 }
}
pub fn process(&self, opcode: &elements::Opcode) -> Result<u32, ()> {
match self.entries.get(&InstructionType::op(opcode)).map(|x| *x) {
None | Some(Metering::Regular) => Ok(self.regular),
Some(Metering::Forbidden) => Err(()),
Some(Metering::Fixed(val)) => Ok(val),
}
}
pub fn grow_cost(&self) -> u32 {
self.grow
}
pub fn with_grow_cost(mut self, val: u32) -> Self {
self.grow = val;
self
}
pub fn with_forbidden_floats(mut self) -> Self {
self.entries.insert(InstructionType::Float, Metering::Forbidden);
self.entries.insert(InstructionType::FloatComparsion, Metering::Forbidden);
self.entries.insert(InstructionType::FloatConst, Metering::Forbidden);
self.entries.insert(InstructionType::FloatConversion, Metering::Forbidden);
self
}
}
-43
View File
@@ -1,43 +0,0 @@
use parity_wasm::{elements, builder};
use self::elements::{ Module, GlobalEntry, External, ExportEntry, GlobalType, ValueType, InitExpr, Opcode, Internal };
use byteorder::{ LittleEndian, ByteOrder };
pub fn inject_runtime_type(module: Module, runtime_type: &[u8], runtime_version: u32) -> Module {
let runtime_type: u32 = LittleEndian::read_u32(&runtime_type);
let globals_count: u32 = match module.global_section() {
Some(ref section) => section.entries().len() as u32,
None => 0
};
let imported_globals_count: u32 = match module.import_section() {
Some(ref section) => section.entries().iter().filter(|e| match *e.external() {
External::Global(ref _a) => true,
_ => false
}).count() as u32,
None => 0
};
let total_globals_count: u32 = globals_count + imported_globals_count;
builder::from_module(module)
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(runtime_type as i32), Opcode::End])))
.with_export(ExportEntry::new("RUNTIME_TYPE".into(), Internal::Global(total_globals_count)))
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(runtime_version as i32), Opcode::End])))
.with_export(ExportEntry::new("RUNTIME_VERSION".into(), Internal::Global(total_globals_count + 1)))
.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_injects() {
let mut module = builder::module()
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(42 as i32)])))
.build();
module = inject_runtime_type(module, b"emcc", 1);
let global_section = module.global_section().expect("Global section expected");
assert_eq!(3, global_section.entries().len());
let export_section = module.export_section().expect("Export section expected");
assert!(export_section.entries().iter().find(|e| e.field() == "RUNTIME_TYPE" ).is_some());
assert!(export_section.entries().iter().find(|e| e.field() == "RUNTIME_VERSION" ).is_some());
}
}
-436
View File
@@ -1,436 +0,0 @@
//! The pass that tries to make stack overflows deterministic, by introducing
//! an upper bound of the stack size.
//!
//! This pass introduces a global mutable variable to track stack height,
//! and instruments all calls with preamble and postamble.
//!
//! Stack height is increased prior the call. Otherwise, the check would
//! be made after the stack frame is allocated.
//!
//! The preamble is inserted before the call. It increments
//! the global stack height variable with statically determined "stack cost"
//! of the callee. If after the increment the stack height exceeds
//! the limit (specified by the `rules`) then execution traps.
//! Otherwise, the call is executed.
//!
//! The postamble is inserted after the call. The purpose of the postamble is to decrease
//! the stack height by the "stack cost" of the callee function.
//!
//! Note, that we can't instrument all possible ways to return from the function. The simplest
//! example would be a trap issued by the host function.
//! That means stack height global won't be equal to zero upon the next execution after such trap.
//!
//! # Thunks
//!
//! Because stack height is increased prior the call few problems arises:
//!
//! - Stack height isn't increased upon an entry to the first function, i.e. exported function.
//! - It is statically unknown what function will be invoked in an indirect call.
//!
//! The solution for this problems is to generate a intermediate functions, called 'thunks', which
//! will increase before and decrease the stack height after the call to original function, and
//! then make exported function and table entries to point to a corresponding thunks.
//!
//! # Stack cost
//!
//! Stack cost of the function is calculated as a sum of it's locals
//! and the maximal height of the value stack.
//!
//! All values are treated equally, as they have the same size.
//!
//! The rationale for this it makes it possible to use this very naive wasm executor, that is:
//!
//! - values are implemented by a union, so each value takes a size equal to
//! the size of the largest possible value type this union can hold. (In MVP it is 8 bytes)
//! - each value from the value stack is placed on the native stack.
//! - each local variable and function argument is placed on the native stack.
//! - arguments pushed by the caller are copied into callee stack rather than shared
//! between the frames.
//! - upon entry into the function entire stack frame is allocated.
use std::string::String;
use std::vec::Vec;
use parity_wasm::elements::{self, Type};
use parity_wasm::builder;
/// Macro to generate preamble and postamble.
macro_rules! instrument_call {
($callee_idx: expr, $callee_stack_cost: expr, $stack_height_global_idx: expr, $stack_limit: expr) => {{
use $crate::parity_wasm::elements::Opcode::*;
[
// stack_height += stack_cost(F)
GetGlobal($stack_height_global_idx),
I32Const($callee_stack_cost),
I32Add,
SetGlobal($stack_height_global_idx),
// if stack_counter > LIMIT: unreachable
GetGlobal($stack_height_global_idx),
I32Const($stack_limit as i32),
I32GtU,
If(elements::BlockType::NoResult),
Unreachable,
End,
// Original call
Call($callee_idx),
// stack_height -= stack_cost(F)
GetGlobal($stack_height_global_idx),
I32Const($callee_stack_cost),
I32Sub,
SetGlobal($stack_height_global_idx),
]
}};
}
mod max_height;
mod thunk;
/// Error that occured during processing the module.
///
/// This means that the module is invalid.
#[derive(Debug)]
pub struct Error(String);
pub(crate) struct Context {
stack_height_global_idx: Option<u32>,
func_stack_costs: Option<Vec<u32>>,
stack_limit: u32,
}
impl Context {
/// Returns index in a global index space of a stack_height global variable.
///
/// Panics if it haven't generated yet.
fn stack_height_global_idx(&self) -> u32 {
self.stack_height_global_idx.expect(
"stack_height_global_idx isn't yet generated;
Did you call `inject_stack_counter_global`",
)
}
/// Returns `stack_cost` for `func_idx`.
///
/// Panics if stack costs haven't computed yet or `func_idx` is greater
/// than the last function index.
fn stack_cost(&self, func_idx: u32) -> Option<u32> {
self.func_stack_costs
.as_ref()
.expect(
"func_stack_costs isn't yet computed;
Did you call `compute_stack_costs`?",
)
.get(func_idx as usize)
.cloned()
}
/// Returns stack limit specified by the rules.
fn stack_limit(&self) -> u32 {
self.stack_limit
}
}
/// Instrument a module with stack height limiter.
///
/// See module-level documentation for more details.
///
/// # Errors
///
/// Returns `Err` if module is invalid and can't be
pub fn inject_limiter(
mut module: elements::Module,
stack_limit: u32,
) -> Result<elements::Module, Error> {
let mut ctx = Context {
stack_height_global_idx: None,
func_stack_costs: None,
stack_limit,
};
generate_stack_height_global(&mut ctx, &mut module);
compute_stack_costs(&mut ctx, &module)?;
instrument_functions(&mut ctx, &mut module)?;
let module = thunk::generate_thunks(&mut ctx, module)?;
Ok(module)
}
/// Generate a new global that will be used for tracking current stack height.
fn generate_stack_height_global(ctx: &mut Context, module: &mut elements::Module) {
let global_entry = builder::global()
.value_type()
.i32()
.mutable()
.init_expr(elements::Opcode::I32Const(0))
.build();
// Try to find an existing global section.
for section in module.sections_mut() {
match *section {
elements::Section::Global(ref mut gs) => {
gs.entries_mut().push(global_entry);
let stack_height_global_idx = (gs.entries().len() as u32) - 1;
ctx.stack_height_global_idx = Some(stack_height_global_idx);
return;
}
_ => {}
}
}
// Existing section not found, create one!
module.sections_mut().push(elements::Section::Global(
elements::GlobalSection::with_entries(vec![global_entry]),
));
ctx.stack_height_global_idx = Some(0);
}
/// Calculate stack costs for all functions.
///
/// Returns a vector with a stack cost for each function, including imports.
fn compute_stack_costs(ctx: &mut Context, module: &elements::Module) -> Result<(), Error> {
let func_imports = module.import_count(elements::ImportCountType::Function);
let mut func_stack_costs = vec![0; module.functions_space()];
// TODO: optimize!
for (func_idx, func_stack_cost) in func_stack_costs.iter_mut().enumerate() {
// We can't calculate stack_cost of the import functions.
if func_idx >= func_imports {
*func_stack_cost = compute_stack_cost(func_idx as u32, &module)?;
}
}
ctx.func_stack_costs = Some(func_stack_costs);
Ok(())
}
/// Stack cost of the given *defined* function is the sum of it's locals count (that is,
/// number of arguments plus number of local variables) and the maximal stack
/// height.
fn compute_stack_cost(func_idx: u32, module: &elements::Module) -> Result<u32, Error> {
// To calculate the cost of a function we need to convert index from
// function index space to defined function spaces.
let func_imports = module.import_count(elements::ImportCountType::Function) as u32;
let defined_func_idx = func_idx.checked_sub(func_imports).ok_or_else(|| {
Error("This should be a index of a defined function".into())
})?;
let code_section = module.code_section().ok_or_else(|| {
Error("Due to validation code section should exists".into())
})?;
let body = &code_section
.bodies()
.get(defined_func_idx as usize)
.ok_or_else(|| Error("Function body is out of bounds".into()))?;
let locals_count = body.locals().len() as u32;
let max_stack_height =
max_height::compute(
defined_func_idx,
module
)?;
Ok(locals_count + max_stack_height)
}
fn instrument_functions(ctx: &mut Context, module: &mut elements::Module) -> Result<(), Error> {
for section in module.sections_mut() {
match *section {
elements::Section::Code(ref mut code_section) => {
for func_body in code_section.bodies_mut() {
let mut opcodes = func_body.code_mut();
instrument_function(ctx, opcodes)?;
}
}
_ => {}
}
}
Ok(())
}
/// This function searches `call` instructions and wrap each call
/// with preamble and postamble.
///
/// Before:
///
/// ```text
/// get_local 0
/// get_local 1
/// call 228
/// drop
/// ```
///
/// After:
///
/// ```text
/// get_local 0
/// get_local 1
///
/// < ... preamble ... >
///
/// call 228
///
/// < .. postamble ... >
///
/// drop
/// ```
fn instrument_function(
ctx: &mut Context,
opcodes: &mut elements::Opcodes,
) -> Result<(), Error> {
use parity_wasm::elements::Opcode::*;
let mut cursor = 0;
loop {
if cursor >= opcodes.elements().len() {
break;
}
enum Action {
InstrumentCall {
callee_idx: u32,
callee_stack_cost: u32,
},
Nop,
}
let action: Action = {
let opcode = &opcodes.elements()[cursor];
match *opcode {
Call(ref callee_idx) => {
let callee_stack_cost = ctx
.stack_cost(*callee_idx)
.ok_or_else(||
Error(
format!("Call to function that out-of-bounds: {}", callee_idx)
)
)?;
// Instrument only calls to a functions which stack_cost is
// non-zero.
if callee_stack_cost > 0 {
Action::InstrumentCall {
callee_idx: *callee_idx,
callee_stack_cost,
}
} else {
Action::Nop
}
},
_ => Action::Nop,
}
};
match action {
// We need to wrap a `call idx` instruction
// with a code that adjusts stack height counter
// and then restores it.
Action::InstrumentCall { callee_idx, callee_stack_cost } => {
let new_seq = instrument_call!(
callee_idx,
callee_stack_cost as i32,
ctx.stack_height_global_idx(),
ctx.stack_limit()
);
// Replace the original `call idx` instruction with
// a wrapped call sequence.
//
// To splice actually take a place, we need to consume iterator
// splice returns. So we just `count()` it.
let _ = opcodes
.elements_mut()
.splice(cursor..(cursor + 1), new_seq.iter().cloned())
.count();
// Advance cursor to be after the inserted sequence.
cursor += new_seq.len();
}
// Do nothing for other instructions.
_ => {
cursor += 1;
}
}
}
Ok(())
}
fn resolve_func_type(
func_idx: u32,
module: &elements::Module,
) -> Result<&elements::FunctionType, Error> {
let types = module.type_section().map(|ts| ts.types()).unwrap_or(&[]);
let functions = module
.function_section()
.map(|fs| fs.entries())
.unwrap_or(&[]);
let func_imports = module.import_count(elements::ImportCountType::Function);
let sig_idx = if func_idx < func_imports as u32 {
module
.import_section()
.expect("function import count is not zero; import section must exists; qed")
.entries()
.iter()
.filter_map(|entry| match *entry.external() {
elements::External::Function(ref idx) => Some(*idx),
_ => None,
})
.nth(func_idx as usize)
.expect(
"func_idx is less than function imports count;
nth function import must be `Some`;
qed",
)
} else {
functions
.get(func_idx as usize - func_imports)
.ok_or_else(|| Error(format!("Function at index {} is not defined", func_idx)))?
.type_ref()
};
let Type::Function(ref ty) = *types.get(sig_idx as usize).ok_or_else(|| {
Error(format!(
"Signature {} (specified by func {}) isn't defined",
sig_idx, func_idx
))
})?;
Ok(ty)
}
#[cfg(test)]
mod tests {
extern crate wabt;
use parity_wasm::elements;
use super::*;
fn parse_wat(source: &str) -> elements::Module {
elements::deserialize_buffer(&wabt::wat2wasm(source).expect("Failed to wat2wasm"))
.expect("Failed to deserialize the module")
}
fn validate_module(module: elements::Module) {
let binary = elements::serialize(module).expect("Failed to serialize");
wabt::Module::read_binary(&binary, &Default::default())
.expect("Wabt failed to read final binary")
.validate()
.expect("Invalid module");
}
#[test]
fn test_with_params_and_result() {
let module = parse_wat(
r#"
(module
(func (export "i32.add") (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add
)
)
"#,
);
let module = inject_limiter(module, 1024)
.expect("Failed to inject stack counter");
validate_module(module);
}
}
-163
View File
@@ -1,163 +0,0 @@
#[cfg(features = "std")]
use std::collections::{HashMap as Map};
#[cfg(not(features = "std"))]
use std::collections::{BTreeMap as Map};
use std::vec::Vec;
use parity_wasm::elements::{self, FunctionType, Internal};
use parity_wasm::builder;
use super::{resolve_func_type, Context, Error};
struct Thunk {
signature: FunctionType,
// Index in function space of this thunk.
idx: Option<u32>,
original_func_idx: u32,
callee_stack_cost: u32,
}
pub(crate) fn generate_thunks(
ctx: &mut Context,
module: elements::Module,
) -> Result<elements::Module, Error> {
// First, we need to collect all function indicies that should be replaced by thunks
// Function indicies which needs to generate thunks.
let mut need_thunks: Vec<u32> = Vec::new();
let mut replacement_map: Map<u32, Thunk> = {
let exports = module
.export_section()
.map(|es| es.entries())
.unwrap_or(&[]);
let elem_segments = module
.elements_section()
.map(|es| es.entries())
.unwrap_or(&[]);
let exported_func_indicies = exports.iter().filter_map(|entry| match *entry.internal() {
Internal::Function(ref function_idx) => Some(*function_idx),
_ => None,
});
let table_func_indicies = elem_segments
.iter()
.flat_map(|segment| segment.members())
.cloned();
// Replacement map is at least export section size.
let mut replacement_map: Map<u32, Thunk> = Map::new();
for func_idx in exported_func_indicies.chain(table_func_indicies) {
let callee_stack_cost = ctx.stack_cost(func_idx).ok_or_else(|| {
Error(format!("function with idx {} isn't found", func_idx))
})?;
// Don't generate a thunk if stack_cost of a callee is zero.
if callee_stack_cost != 0 {
need_thunks.push(func_idx);
replacement_map.insert(func_idx, Thunk {
signature: resolve_func_type(func_idx, &module)?.clone(),
idx: None,
callee_stack_cost,
original_func_idx: func_idx,
});
}
}
replacement_map
};
// Then, we generate a thunk for each original function.
// Save current func_idx
let mut next_func_idx = module.functions_space() as u32;
let mut mbuilder = builder::from_module(module);
for func_idx in need_thunks {
let mut thunk = replacement_map
.get_mut(&func_idx)
.expect(
"`func_idx` should come from `need_thunks`;
`need_thunks` is populated with the same items that in `replacement_map`;
qed"
);
let instrumented_call = instrument_call!(
thunk.original_func_idx as u32,
thunk.callee_stack_cost as i32,
ctx.stack_height_global_idx(),
ctx.stack_limit()
);
// Thunk body consist of:
// - argument pushing
// - instrumented call
// - end
let mut thunk_body: Vec<elements::Opcode> = Vec::with_capacity(
thunk.signature.params().len() +
instrumented_call.len() +
1
);
for (arg_idx, _) in thunk.signature.params().iter().enumerate() {
thunk_body.push(elements::Opcode::GetLocal(arg_idx as u32));
}
thunk_body.extend(instrumented_call.iter().cloned());
thunk_body.push(elements::Opcode::End);
// TODO: Don't generate a signature, but find an existing one.
mbuilder = mbuilder.function()
// Signature of the thunk should match the original function signature.
.signature()
.with_params(thunk.signature.params().to_vec())
.with_return_type(thunk.signature.return_type().clone())
.build()
.body()
.with_opcodes(elements::Opcodes::new(
thunk_body
))
.build()
.build();
thunk.idx = Some(next_func_idx);
next_func_idx += 1;
}
let mut module = mbuilder.build();
// And finally, fixup thunks in export and table sections.
// Fixup original function index to a index of a thunk generated earlier.
let fixup = |function_idx: &mut u32| {
// Check whether this function is in replacement_map, since
// we can skip thunk generation (e.g. if stack_cost of function is 0).
if let Some(ref thunk) = replacement_map.get(function_idx) {
*function_idx = thunk
.idx
.expect("At this point an index must be assigned to each thunk");
}
};
for section in module.sections_mut() {
match *section {
elements::Section::Export(ref mut export_section) => {
for entry in export_section.entries_mut() {
match *entry.internal_mut() {
Internal::Function(ref mut function_idx) => fixup(function_idx),
_ => {}
}
}
}
elements::Section::Element(ref mut elem_section) => {
for segment in elem_section.entries_mut() {
for function_idx in segment.members_mut() {
fixup(function_idx)
}
}
}
_ => {}
}
}
Ok(module)
}
@@ -1,7 +1,15 @@
use std::vec::Vec;
use super::resolve_func_type;
use alloc::vec::Vec;
use parity_wasm::elements::{self, BlockType, Type};
use super::{resolve_func_type, Error};
#[cfg(feature = "sign_ext")]
use parity_wasm::elements::SignExtInstruction;
// The cost in stack items that should be charged per call of a function. This is
// is a static cost that is added to each function call. This makes sense because even
// if a function does not use any parameters or locals some stack space on the host
// machine might be consumed to hold some context.
const ACTIVATION_FRAME_COST: u32 = 2;
/// Control stack frame.
#[derive(Debug)]
@@ -34,10 +42,7 @@ struct Stack {
impl Stack {
fn new() -> Stack {
Stack {
height: 0,
control_stack: Vec::new(),
}
Stack { height: ACTIVATION_FRAME_COST, control_stack: Vec::new() }
}
/// Returns current height of the value stack.
@@ -47,59 +52,44 @@ impl Stack {
/// Returns a reference to a frame by specified depth relative to the top of
/// control stack.
fn frame(&self, rel_depth: u32) -> Result<&Frame, Error> {
fn frame(&self, rel_depth: u32) -> Result<&Frame, &'static str> {
let control_stack_height: usize = self.control_stack.len();
let last_idx = control_stack_height
.checked_sub(1)
.ok_or_else(|| Error("control stack is empty".into()))?;
let idx = last_idx
.checked_sub(rel_depth as usize)
.ok_or_else(|| Error("control stack out-of-bounds".into()))?;
let last_idx = control_stack_height.checked_sub(1).ok_or("control stack is empty")?;
let idx = last_idx.checked_sub(rel_depth as usize).ok_or("control stack out-of-bounds")?;
Ok(&self.control_stack[idx])
}
/// Mark successive instructions as unreachable.
///
/// This effectively makes stack polymorphic.
fn mark_unreachable(&mut self) -> Result<(), Error> {
trace!(target: "max_height", "unreachable");
let top_frame = self.control_stack
.last_mut()
.ok_or_else(|| Error("stack must be non-empty".into()))?;
fn mark_unreachable(&mut self) -> Result<(), &'static str> {
let top_frame = self.control_stack.last_mut().ok_or("stack must be non-empty")?;
top_frame.is_polymorphic = true;
Ok(())
}
/// Push control frame into the control stack.
fn push_frame(&mut self, frame: Frame) {
trace!(target: "max_height", "push_frame: {:?}", frame);
self.control_stack.push(frame);
}
/// Pop control frame from the control stack.
///
/// Returns `Err` if the control stack is empty.
fn pop_frame(&mut self) -> Result<Frame, Error> {
trace!(target: "max_height", "pop_frame: {:?}", self.control_stack.last());
Ok(self.control_stack
.pop()
.ok_or_else(|| Error("stack must be non-empty".into()))?)
fn pop_frame(&mut self) -> Result<Frame, &'static str> {
self.control_stack.pop().ok_or("stack must be non-empty")
}
/// Truncate the height of value stack to the specified height.
fn trunc(&mut self, new_height: u32) {
trace!(target: "max_height", "trunc: {}", new_height);
self.height = new_height;
}
/// Push specified number of values into the value stack.
///
/// Returns `Err` if the height overflow usize value.
fn push_values(&mut self, value_count: u32) -> Result<(), Error> {
trace!(target: "max_height", "push: {}", value_count);
self.height = self.height
.checked_add(value_count)
.ok_or_else(|| Error("stack overflow".into()))?;
fn push_values(&mut self, value_count: u32) -> Result<(), &'static str> {
self.height = self.height.checked_add(value_count).ok_or("stack overflow")?;
Ok(())
}
@@ -107,10 +97,9 @@ impl Stack {
///
/// Returns `Err` if the stack happen to be negative value after
/// values popped.
fn pop_values(&mut self, value_count: u32) -> Result<(), Error> {
trace!(target: "max_height", "pop: {}", value_count);
fn pop_values(&mut self, value_count: u32) -> Result<(), &'static str> {
if value_count == 0 {
return Ok(());
return Ok(())
}
{
let top_frame = self.frame(0)?;
@@ -121,51 +110,40 @@ impl Stack {
return if top_frame.is_polymorphic {
Ok(())
} else {
Err(Error("trying to pop more values than pushed".into()))
return Err("trying to pop more values than pushed")
}
}
}
self.height = self.height
.checked_sub(value_count)
.ok_or_else(|| Error("stack underflow".into()))?;
self.height = self.height.checked_sub(value_count).ok_or("stack underflow")?;
Ok(())
}
}
/// This function expects the function to be validated.
pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, Error> {
use parity_wasm::elements::Opcode::*;
pub fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, &'static str> {
use parity_wasm::elements::Instruction::*;
let func_section = module
.function_section()
.ok_or_else(|| Error("No function section".into()))?;
let code_section = module
.code_section()
.ok_or_else(|| Error("No code section".into()))?;
let type_section = module
.type_section()
.ok_or_else(|| Error("No type section".into()))?;
trace!(target: "max_height", "func_idx: {}", func_idx);
let func_section = module.function_section().ok_or("No function section")?;
let code_section = module.code_section().ok_or("No code section")?;
let type_section = module.type_section().ok_or("No type section")?;
// Get a signature and a body of the specified function.
let func_sig_idx = func_section
.entries()
.get(func_idx as usize)
.ok_or_else(|| Error("Function is not found in func section".into()))?
.ok_or("Function is not found in func section")?
.type_ref();
let Type::Function(ref func_signature) = *type_section
let Type::Function(func_signature) = type_section
.types()
.get(func_sig_idx as usize)
.ok_or_else(|| Error("Function is not found in func section".into()))?;
.ok_or("Function is not found in func section")?;
let body = code_section
.bodies()
.get(func_idx as usize)
.ok_or_else(|| Error("Function body for the index isn't found".into()))?;
let opcodes = body.code();
.ok_or("Function body for the index isn't found")?;
let instructions = body.code();
let mut stack = Stack::new();
let mut max_height: u32 = 0;
@@ -173,11 +151,7 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
// Add implicit frame for the function. Breaks to this frame and execution of
// the last end should deal with this frame.
let func_arity: u32 = if func_signature.return_type().is_some() {
1
} else {
0
};
let func_arity = func_signature.results().len() as u32;
stack.push_frame(Frame {
is_polymorphic: false,
end_arity: func_arity,
@@ -186,8 +160,8 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
});
loop {
if pc >= opcodes.elements().len() {
break;
if pc >= instructions.elements().len() {
break
}
// If current value stack is higher than maximal height observed so far,
@@ -197,14 +171,16 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
max_height = stack.height();
}
let opcode = &opcodes.elements()[pc];
trace!(target: "max_height", "{:?}", opcode);
let opcode = &instructions.elements()[pc];
match *opcode {
Nop => {}
match opcode {
Nop => {},
Block(ty) | Loop(ty) | If(ty) => {
let end_arity = if ty == BlockType::NoResult { 0 } else { 1 };
let end_arity = u32::from(*ty != BlockType::NoResult);
let branch_arity = if let Loop(_) = *opcode { 0 } else { end_arity };
if let If(_) = *opcode {
stack.pop_values(1)?;
}
let height = stack.height();
stack.push_frame(Frame {
is_polymorphic: false,
@@ -212,31 +188,31 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
branch_arity,
start_height: height,
});
}
},
Else => {
// The frame at the top should be pushed by `If`. So we leave
// it as is.
}
},
End => {
let frame = stack.pop_frame()?;
stack.trunc(frame.start_height);
stack.push_values(frame.end_arity)?;
}
},
Unreachable => {
stack.mark_unreachable()?;
}
},
Br(target) => {
// Pop values for the destination block result.
let target_arity = stack.frame(target)?.branch_arity;
let target_arity = stack.frame(*target)?.branch_arity;
stack.pop_values(target_arity)?;
// This instruction unconditionally transfers control to the specified block,
// thus all instruction until the end of the current block is deemed unreachable
stack.mark_unreachable()?;
}
},
BrIf(target) => {
// Pop values for the destination block result.
let target_arity = stack.frame(target)?.branch_arity;
let target_arity = stack.frame(*target)?.branch_arity;
stack.pop_values(target_arity)?;
// Pop condition value.
@@ -244,17 +220,15 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
// Push values back.
stack.push_values(target_arity)?;
}
BrTable(ref targets, default_target) => {
let arity_of_default = stack.frame(default_target)?.branch_arity;
},
BrTable(br_table_data) => {
let arity_of_default = stack.frame(br_table_data.default)?.branch_arity;
// Check that all jump targets have an equal arities.
for target in targets.iter() {
for target in &*br_table_data.table {
let arity = stack.frame(*target)?.branch_arity;
if arity != arity_of_default {
return Err(Error(
"Arity of all jump-targets must be equal".into()
))
return Err("Arity of all jump-targets must be equal")
}
}
@@ -265,39 +239,40 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
// This instruction doesn't let control flow to go further, since the control flow
// should take either one of branches depending on the value or the default branch.
stack.mark_unreachable()?;
}
},
Return => {
// Pop return values of the function. Mark successive instructions as unreachable
// since this instruction doesn't let control flow to go further.
stack.pop_values(func_arity)?;
stack.mark_unreachable()?;
}
},
Call(idx) => {
let ty = resolve_func_type(idx, module)?;
let ty = resolve_func_type(*idx, module)?;
// Pop values for arguments of the function.
stack.pop_values(ty.params().len() as u32)?;
// Push result of the function execution to the stack.
let callee_arity = if ty.return_type().is_some() { 1 } else { 0 };
let callee_arity = ty.results().len() as u32;
stack.push_values(callee_arity)?;
}
},
CallIndirect(x, _) => {
let Type::Function(ref ty) = *type_section
.types()
.get(x as usize)
.ok_or_else(|| Error("Type not found".into()))?;
let Type::Function(ty) =
type_section.types().get(*x as usize).ok_or("Type not found")?;
// Pop the offset into the function table.
stack.pop_values(1)?;
// Pop values for arguments of the function.
stack.pop_values(ty.params().len() as u32)?;
// Push result of the function execution to the stack.
let callee_arity = if ty.return_type().is_some() { 1 } else { 0 };
let callee_arity = ty.results().len() as u32;
stack.push_values(callee_arity)?;
}
},
Drop => {
stack.pop_values(1)?;
}
},
Select => {
// Pop two values and one condition.
stack.pop_values(2)?;
@@ -305,118 +280,128 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
// Push the selected value.
stack.push_values(1)?;
}
},
GetLocal(_) => {
stack.push_values(1)?;
}
},
SetLocal(_) => {
stack.pop_values(1)?;
}
},
TeeLocal(_) => {
// This instruction pops and pushes the value, so
// effectively it doesn't modify the stack height.
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
GetGlobal(_) => {
stack.push_values(1)?;
}
},
SetGlobal(_) => {
stack.pop_values(1)?;
}
I32Load(_, _)
| I64Load(_, _)
| F32Load(_, _)
| F64Load(_, _)
| I32Load8S(_, _)
| I32Load8U(_, _)
| I32Load16S(_, _)
| I32Load16U(_, _)
| I64Load8S(_, _)
| I64Load8U(_, _)
| I64Load16S(_, _)
| I64Load16U(_, _)
| I64Load32S(_, _)
| I64Load32U(_, _) => {
},
I32Load(_, _) |
I64Load(_, _) |
F32Load(_, _) |
F64Load(_, _) |
I32Load8S(_, _) |
I32Load8U(_, _) |
I32Load16S(_, _) |
I32Load16U(_, _) |
I64Load8S(_, _) |
I64Load8U(_, _) |
I64Load16S(_, _) |
I64Load16U(_, _) |
I64Load32S(_, _) |
I64Load32U(_, _) => {
// These instructions pop the address and pushes the result,
// which effictively don't modify the stack height.
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
I32Store(_, _)
| I64Store(_, _)
| F32Store(_, _)
| F64Store(_, _)
| I32Store8(_, _)
| I32Store16(_, _)
| I64Store8(_, _)
| I64Store16(_, _)
| I64Store32(_, _) => {
I32Store(_, _) |
I64Store(_, _) |
F32Store(_, _) |
F64Store(_, _) |
I32Store8(_, _) |
I32Store16(_, _) |
I64Store8(_, _) |
I64Store16(_, _) |
I64Store32(_, _) => {
// These instructions pop the address and the value.
stack.pop_values(2)?;
}
},
CurrentMemory(_) => {
// Pushes current memory size
stack.push_values(1)?;
}
},
GrowMemory(_) => {
// Grow memory takes the value of pages to grow and pushes
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
I32Const(_) | I64Const(_) | F32Const(_) | F64Const(_) => {
// These instructions just push the single literal value onto the stack.
stack.push_values(1)?;
}
},
I32Eqz | I64Eqz => {
// These instructions pop the value and compare it against zero, and pushes
// the result of the comparison.
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
I32Eq | I32Ne | I32LtS | I32LtU | I32GtS | I32GtU | I32LeS | I32LeU | I32GeS
| I32GeU | I64Eq | I64Ne | I64LtS | I64LtU | I64GtS | I64GtU | I64LeS | I64LeU
| I64GeS | I64GeU | F32Eq | F32Ne | F32Lt | F32Gt | F32Le | F32Ge | F64Eq | F64Ne
| F64Lt | F64Gt | F64Le | F64Ge => {
I32Eq | I32Ne | I32LtS | I32LtU | I32GtS | I32GtU | I32LeS | I32LeU | I32GeS |
I32GeU | I64Eq | I64Ne | I64LtS | I64LtU | I64GtS | I64GtU | I64LeS | I64LeU |
I64GeS | I64GeU | F32Eq | F32Ne | F32Lt | F32Gt | F32Le | F32Ge | F64Eq | F64Ne |
F64Lt | F64Gt | F64Le | F64Ge => {
// Comparison operations take two operands and produce one result.
stack.pop_values(2)?;
stack.push_values(1)?;
}
},
I32Clz | I32Ctz | I32Popcnt | I64Clz | I64Ctz | I64Popcnt | F32Abs | F32Neg
| F32Ceil | F32Floor | F32Trunc | F32Nearest | F32Sqrt | F64Abs | F64Neg | F64Ceil
| F64Floor | F64Trunc | F64Nearest | F64Sqrt => {
I32Clz | I32Ctz | I32Popcnt | I64Clz | I64Ctz | I64Popcnt | F32Abs | F32Neg |
F32Ceil | F32Floor | F32Trunc | F32Nearest | F32Sqrt | F64Abs | F64Neg | F64Ceil |
F64Floor | F64Trunc | F64Nearest | F64Sqrt => {
// Unary operators take one operand and produce one result.
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
I32Add | I32Sub | I32Mul | I32DivS | I32DivU | I32RemS | I32RemU | I32And | I32Or
| I32Xor | I32Shl | I32ShrS | I32ShrU | I32Rotl | I32Rotr | I64Add | I64Sub
| I64Mul | I64DivS | I64DivU | I64RemS | I64RemU | I64And | I64Or | I64Xor | I64Shl
| I64ShrS | I64ShrU | I64Rotl | I64Rotr | F32Add | F32Sub | F32Mul | F32Div
| F32Min | F32Max | F32Copysign | F64Add | F64Sub | F64Mul | F64Div | F64Min
| F64Max | F64Copysign => {
I32Add | I32Sub | I32Mul | I32DivS | I32DivU | I32RemS | I32RemU | I32And | I32Or |
I32Xor | I32Shl | I32ShrS | I32ShrU | I32Rotl | I32Rotr | I64Add | I64Sub |
I64Mul | I64DivS | I64DivU | I64RemS | I64RemU | I64And | I64Or | I64Xor | I64Shl |
I64ShrS | I64ShrU | I64Rotl | I64Rotr | F32Add | F32Sub | F32Mul | F32Div |
F32Min | F32Max | F32Copysign | F64Add | F64Sub | F64Mul | F64Div | F64Min |
F64Max | F64Copysign => {
// Binary operators take two operands and produce one result.
stack.pop_values(2)?;
stack.push_values(1)?;
}
},
I32WrapI64 | I32TruncSF32 | I32TruncUF32 | I32TruncSF64 | I32TruncUF64
| I64ExtendSI32 | I64ExtendUI32 | I64TruncSF32 | I64TruncUF32 | I64TruncSF64
| I64TruncUF64 | F32ConvertSI32 | F32ConvertUI32 | F32ConvertSI64 | F32ConvertUI64
| F32DemoteF64 | F64ConvertSI32 | F64ConvertUI32 | F64ConvertSI64 | F64ConvertUI64
| F64PromoteF32 | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32
| F64ReinterpretI64 => {
I32WrapI64 | I32TruncSF32 | I32TruncUF32 | I32TruncSF64 | I32TruncUF64 |
I64ExtendSI32 | I64ExtendUI32 | I64TruncSF32 | I64TruncUF32 | I64TruncSF64 |
I64TruncUF64 | F32ConvertSI32 | F32ConvertUI32 | F32ConvertSI64 | F32ConvertUI64 |
F32DemoteF64 | F64ConvertSI32 | F64ConvertUI32 | F64ConvertSI64 | F64ConvertUI64 |
F64PromoteF32 | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 |
F64ReinterpretI64 => {
// Conversion operators take one value and produce one result.
stack.pop_values(1)?;
stack.push_values(1)?;
}
},
#[cfg(feature = "sign_ext")]
SignExt(SignExtInstruction::I32Extend8S) |
SignExt(SignExtInstruction::I32Extend16S) |
SignExt(SignExtInstruction::I64Extend8S) |
SignExt(SignExtInstruction::I64Extend16S) |
SignExt(SignExtInstruction::I64Extend32S) => {
stack.pop_values(1)?;
stack.push_values(1)?;
},
}
pc += 1;
}
@@ -426,12 +411,11 @@ pub(crate) fn compute(func_idx: u32, module: &elements::Module) -> Result<u32, E
#[cfg(test)]
mod tests {
extern crate wabt;
use parity_wasm::elements;
use super::*;
use parity_wasm::elements;
fn parse_wat(source: &str) -> elements::Module {
elements::deserialize_buffer(&wabt::wat2wasm(source).expect("Failed to wat2wasm"))
elements::deserialize_buffer(&wat::parse_str(source).expect("Failed to wat2wasm"))
.expect("Failed to deserialize the module")
}
@@ -453,7 +437,7 @@ mod tests {
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 3);
assert_eq!(height, 3 + ACTIVATION_FRAME_COST);
}
#[test]
@@ -470,7 +454,7 @@ mod tests {
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 1);
assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
}
#[test]
@@ -481,46 +465,114 @@ mod tests {
(memory 0)
(func (result i32)
unreachable
grow_memory
memory.grow
)
)
"#,
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 0);
assert_eq!(height, ACTIVATION_FRAME_COST);
}
#[test]
fn yet_another_test() {
const SOURCE: &'static str = r#"
let module = parse_wat(
r#"
(module
(memory 0)
(func
;; Push two values and then pop them.
;; This will make max depth to be equal to 2.
i32.const 0
i32.const 1
drop
drop
;; Push two values and then pop them.
;; This will make max depth to be equal to 2.
i32.const 0
i32.const 1
drop
drop
;; Code after `unreachable` shouldn't have an effect
;; on the max depth.
unreachable
i32.const 0
i32.const 1
i32.const 2
;; Code after `unreachable` shouldn't have an effect
;; on the max depth.
unreachable
i32.const 0
i32.const 1
i32.const 2
)
)
"#;
let module = elements::deserialize_buffer(&wabt::Wat2Wasm::new()
.validate(false)
.convert(SOURCE)
.expect("Failed to wat2wasm")
.as_ref())
.expect("Failed to deserialize the module");
"#,
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 2);
assert_eq!(height, 2 + ACTIVATION_FRAME_COST);
}
#[test]
fn call_indirect() {
let module = parse_wat(
r#"
(module
(table $ptr 1 1 funcref)
(elem $ptr (i32.const 0) func 1)
(func $main
(call_indirect (i32.const 0))
(call_indirect (i32.const 0))
(call_indirect (i32.const 0))
)
(func $callee
i64.const 42
drop
)
)
"#,
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
}
#[test]
fn breaks() {
let module = parse_wat(
r#"
(module
(func $main
block (result i32)
block (result i32)
i32.const 99
br 1
end
end
drop
)
)
"#,
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
}
#[test]
fn if_else_works() {
let module = parse_wat(
r#"
(module
(func $main
i32.const 7
i32.const 1
if (result i32)
i32.const 42
else
i32.const 99
end
i32.const 97
drop
drop
drop
)
)
"#,
);
let height = compute(0, &module).unwrap();
assert_eq!(height, 3 + ACTIVATION_FRAME_COST);
}
}
+380
View File
@@ -0,0 +1,380 @@
//! Contains the code for the stack height limiter instrumentation.
use alloc::{vec, vec::Vec};
use core::mem;
use parity_wasm::{
builder,
elements::{self, Instruction, Instructions, Type},
};
/// Macro to generate preamble and postamble.
macro_rules! instrument_call {
($callee_idx: expr, $callee_stack_cost: expr, $stack_height_global_idx: expr, $stack_limit: expr) => {{
use $crate::parity_wasm::elements::Instruction::*;
[
// stack_height += stack_cost(F)
GetGlobal($stack_height_global_idx),
I32Const($callee_stack_cost),
I32Add,
SetGlobal($stack_height_global_idx),
// if stack_counter > LIMIT: unreachable
GetGlobal($stack_height_global_idx),
I32Const($stack_limit as i32),
I32GtU,
If(elements::BlockType::NoResult),
Unreachable,
End,
// Original call
Call($callee_idx),
// stack_height -= stack_cost(F)
GetGlobal($stack_height_global_idx),
I32Const($callee_stack_cost),
I32Sub,
SetGlobal($stack_height_global_idx),
]
}};
}
mod max_height;
mod thunk;
pub struct Context {
stack_height_global_idx: u32,
func_stack_costs: Vec<u32>,
stack_limit: u32,
}
impl Context {
/// Returns index in a global index space of a stack_height global variable.
fn stack_height_global_idx(&self) -> u32 {
self.stack_height_global_idx
}
/// Returns `stack_cost` for `func_idx`.
fn stack_cost(&self, func_idx: u32) -> Option<u32> {
self.func_stack_costs.get(func_idx as usize).cloned()
}
/// Returns stack limit specified by the rules.
fn stack_limit(&self) -> u32 {
self.stack_limit
}
}
/// Inject the instumentation that makes stack overflows deterministic, by introducing
/// an upper bound of the stack size.
///
/// This pass introduces a global mutable variable to track stack height,
/// and instruments all calls with preamble and postamble.
///
/// Stack height is increased prior the call. Otherwise, the check would
/// be made after the stack frame is allocated.
///
/// The preamble is inserted before the call. It increments
/// the global stack height variable with statically determined "stack cost"
/// of the callee. If after the increment the stack height exceeds
/// the limit (specified by the `rules`) then execution traps.
/// Otherwise, the call is executed.
///
/// The postamble is inserted after the call. The purpose of the postamble is to decrease
/// the stack height by the "stack cost" of the callee function.
///
/// Note, that we can't instrument all possible ways to return from the function. The simplest
/// example would be a trap issued by the host function.
/// That means stack height global won't be equal to zero upon the next execution after such trap.
///
/// # Thunks
///
/// Because stack height is increased prior the call few problems arises:
///
/// - Stack height isn't increased upon an entry to the first function, i.e. exported function.
/// - Start function is executed externally (similar to exported functions).
/// - It is statically unknown what function will be invoked in an indirect call.
///
/// The solution for this problems is to generate a intermediate functions, called 'thunks', which
/// will increase before and decrease the stack height after the call to original function, and
/// then make exported function and table entries, start section to point to a corresponding thunks.
///
/// # Stack cost
///
/// Stack cost of the function is calculated as a sum of it's locals
/// and the maximal height of the value stack.
///
/// All values are treated equally, as they have the same size.
///
/// The rationale is that this makes it possible to use the following very naive wasm executor:
///
/// - values are implemented by a union, so each value takes a size equal to the size of the largest
/// possible value type this union can hold. (In MVP it is 8 bytes)
/// - each value from the value stack is placed on the native stack.
/// - each local variable and function argument is placed on the native stack.
/// - arguments pushed by the caller are copied into callee stack rather than shared between the
/// frames.
/// - upon entry into the function entire stack frame is allocated.
pub fn inject(
mut module: elements::Module,
stack_limit: u32,
) -> Result<elements::Module, &'static str> {
let mut ctx = Context {
stack_height_global_idx: generate_stack_height_global(&mut module),
func_stack_costs: compute_stack_costs(&module)?,
stack_limit,
};
instrument_functions(&mut ctx, &mut module)?;
let module = thunk::generate_thunks(&mut ctx, module)?;
Ok(module)
}
/// Generate a new global that will be used for tracking current stack height.
fn generate_stack_height_global(module: &mut elements::Module) -> u32 {
let global_entry = builder::global()
.value_type()
.i32()
.mutable()
.init_expr(Instruction::I32Const(0))
.build();
// Try to find an existing global section.
for section in module.sections_mut() {
if let elements::Section::Global(gs) = section {
gs.entries_mut().push(global_entry);
return (gs.entries().len() as u32) - 1
}
}
// Existing section not found, create one!
module
.sections_mut()
.push(elements::Section::Global(elements::GlobalSection::with_entries(vec![global_entry])));
0
}
/// Calculate stack costs for all functions.
///
/// Returns a vector with a stack cost for each function, including imports.
fn compute_stack_costs(module: &elements::Module) -> Result<Vec<u32>, &'static str> {
let func_imports = module.import_count(elements::ImportCountType::Function);
// TODO: optimize!
(0..module.functions_space())
.map(|func_idx| {
if func_idx < func_imports {
// We can't calculate stack_cost of the import functions.
Ok(0)
} else {
compute_stack_cost(func_idx as u32, module)
}
})
.collect()
}
/// Stack cost of the given *defined* function is the sum of it's locals count (that is,
/// number of arguments plus number of local variables) and the maximal stack
/// height.
fn compute_stack_cost(func_idx: u32, module: &elements::Module) -> Result<u32, &'static str> {
// To calculate the cost of a function we need to convert index from
// function index space to defined function spaces.
let func_imports = module.import_count(elements::ImportCountType::Function) as u32;
let defined_func_idx = func_idx
.checked_sub(func_imports)
.ok_or("This should be a index of a defined function")?;
let code_section =
module.code_section().ok_or("Due to validation code section should exists")?;
let body = &code_section
.bodies()
.get(defined_func_idx as usize)
.ok_or("Function body is out of bounds")?;
let mut locals_count: u32 = 0;
for local_group in body.locals() {
locals_count =
locals_count.checked_add(local_group.count()).ok_or("Overflow in local count")?;
}
let max_stack_height = max_height::compute(defined_func_idx, module)?;
locals_count
.checked_add(max_stack_height)
.ok_or("Overflow in adding locals_count and max_stack_height")
}
fn instrument_functions(
ctx: &mut Context,
module: &mut elements::Module,
) -> Result<(), &'static str> {
for section in module.sections_mut() {
if let elements::Section::Code(code_section) = section {
for func_body in code_section.bodies_mut() {
let opcodes = func_body.code_mut();
instrument_function(ctx, opcodes)?;
}
}
}
Ok(())
}
/// This function searches `call` instructions and wrap each call
/// with preamble and postamble.
///
/// Before:
///
/// ```text
/// local.get 0
/// local.get 1
/// call 228
/// drop
/// ```
///
/// After:
///
/// ```text
/// local.get 0
/// local.get 1
///
/// < ... preamble ... >
///
/// call 228
///
/// < .. postamble ... >
///
/// drop
/// ```
fn instrument_function(ctx: &mut Context, func: &mut Instructions) -> Result<(), &'static str> {
use Instruction::*;
struct InstrumentCall {
offset: usize,
callee: u32,
cost: u32,
}
let calls: Vec<_> = func
.elements()
.iter()
.enumerate()
.filter_map(|(offset, instruction)| {
if let Call(callee) = instruction {
ctx.stack_cost(*callee).and_then(|cost| {
if cost > 0 {
Some(InstrumentCall { callee: *callee, offset, cost })
} else {
None
}
})
} else {
None
}
})
.collect();
// The `instrumented_call!` contains the call itself. This is why we need to subtract one.
let len = func.elements().len() + calls.len() * (instrument_call!(0, 0, 0, 0).len() - 1);
let original_instrs = mem::replace(func.elements_mut(), Vec::with_capacity(len));
let new_instrs = func.elements_mut();
let mut calls = calls.into_iter().peekable();
for (original_pos, instr) in original_instrs.into_iter().enumerate() {
// whether there is some call instruction at this position that needs to be instrumented
let did_instrument = if let Some(call) = calls.peek() {
if call.offset == original_pos {
let new_seq = instrument_call!(
call.callee,
call.cost as i32,
ctx.stack_height_global_idx(),
ctx.stack_limit()
);
new_instrs.extend_from_slice(&new_seq);
true
} else {
false
}
} else {
false
};
if did_instrument {
calls.next();
} else {
new_instrs.push(instr);
}
}
if calls.next().is_some() {
return Err("Not all calls were used")
}
Ok(())
}
fn resolve_func_type(
func_idx: u32,
module: &elements::Module,
) -> Result<&elements::FunctionType, &'static str> {
let types = module.type_section().map(|ts| ts.types()).unwrap_or(&[]);
let functions = module.function_section().map(|fs| fs.entries()).unwrap_or(&[]);
let func_imports = module.import_count(elements::ImportCountType::Function);
let sig_idx = if func_idx < func_imports as u32 {
module
.import_section()
.expect("function import count is not zero; import section must exists; qed")
.entries()
.iter()
.filter_map(|entry| match entry.external() {
elements::External::Function(idx) => Some(*idx),
_ => None,
})
.nth(func_idx as usize)
.expect(
"func_idx is less than function imports count;
nth function import must be `Some`;
qed",
)
} else {
functions
.get(func_idx as usize - func_imports)
.ok_or("Function at the specified index is not defined")?
.type_ref()
};
let Type::Function(ty) = types
.get(sig_idx as usize)
.ok_or("The signature as specified by a function isn't defined")?;
Ok(ty)
}
#[cfg(test)]
mod tests {
use super::*;
use parity_wasm::elements;
fn parse_wat(source: &str) -> elements::Module {
elements::deserialize_buffer(&wat::parse_str(source).expect("Failed to wat2wasm"))
.expect("Failed to deserialize the module")
}
fn validate_module(module: elements::Module) {
let binary = elements::serialize(module).expect("Failed to serialize");
wasmparser::validate(&binary).expect("Invalid module");
}
#[test]
fn test_with_params_and_result() {
let module = parse_wat(
r#"
(module
(func (export "i32.add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
)
)
"#,
);
let module = inject(module, 1024).expect("Failed to inject stack counter");
validate_module(module);
}
}
+135
View File
@@ -0,0 +1,135 @@
use alloc::{collections::BTreeMap as Map, vec::Vec};
use parity_wasm::{
builder,
elements::{self, FunctionType, Internal},
};
use super::{resolve_func_type, Context};
struct Thunk {
signature: FunctionType,
// Index in function space of this thunk.
idx: Option<u32>,
callee_stack_cost: u32,
}
pub fn generate_thunks(
ctx: &mut Context,
module: elements::Module,
) -> Result<elements::Module, &'static str> {
// First, we need to collect all function indices that should be replaced by thunks
let mut replacement_map: Map<u32, Thunk> = {
let exports = module.export_section().map(|es| es.entries()).unwrap_or(&[]);
let elem_segments = module.elements_section().map(|es| es.entries()).unwrap_or(&[]);
let start_func_idx = module.start_section();
let exported_func_indices = exports.iter().filter_map(|entry| match entry.internal() {
Internal::Function(function_idx) => Some(*function_idx),
_ => None,
});
let table_func_indices =
elem_segments.iter().flat_map(|segment| segment.members()).cloned();
// Replacement map is at least export section size.
let mut replacement_map: Map<u32, Thunk> = Map::new();
for func_idx in exported_func_indices
.chain(table_func_indices)
.chain(start_func_idx.into_iter())
{
let callee_stack_cost = ctx.stack_cost(func_idx).ok_or("function index isn't found")?;
// Don't generate a thunk if stack_cost of a callee is zero.
if callee_stack_cost != 0 {
replacement_map.insert(
func_idx,
Thunk {
signature: resolve_func_type(func_idx, &module)?.clone(),
idx: None,
callee_stack_cost,
},
);
}
}
replacement_map
};
// Then, we generate a thunk for each original function.
// Save current func_idx
let mut next_func_idx = module.functions_space() as u32;
let mut mbuilder = builder::from_module(module);
for (func_idx, thunk) in replacement_map.iter_mut() {
let instrumented_call = instrument_call!(
*func_idx,
thunk.callee_stack_cost as i32,
ctx.stack_height_global_idx(),
ctx.stack_limit()
);
// Thunk body consist of:
// - argument pushing
// - instrumented call
// - end
let mut thunk_body: Vec<elements::Instruction> =
Vec::with_capacity(thunk.signature.params().len() + instrumented_call.len() + 1);
for (arg_idx, _) in thunk.signature.params().iter().enumerate() {
thunk_body.push(elements::Instruction::GetLocal(arg_idx as u32));
}
thunk_body.extend_from_slice(&instrumented_call);
thunk_body.push(elements::Instruction::End);
// TODO: Don't generate a signature, but find an existing one.
mbuilder = mbuilder
.function()
// Signature of the thunk should match the original function signature.
.signature()
.with_params(thunk.signature.params().to_vec())
.with_results(thunk.signature.results().to_vec())
.build()
.body()
.with_instructions(elements::Instructions::new(thunk_body))
.build()
.build();
thunk.idx = Some(next_func_idx);
next_func_idx += 1;
}
let mut module = mbuilder.build();
// And finally, fixup thunks in export and table sections.
// Fixup original function index to a index of a thunk generated earlier.
let fixup = |function_idx: &mut u32| {
// Check whether this function is in replacement_map, since
// we can skip thunk generation (e.g. if stack_cost of function is 0).
if let Some(thunk) = replacement_map.get(function_idx) {
*function_idx =
thunk.idx.expect("At this point an index must be assigned to each thunk");
}
};
for section in module.sections_mut() {
match section {
elements::Section::Export(export_section) =>
for entry in export_section.entries_mut() {
if let Internal::Function(function_idx) = entry.internal_mut() {
fixup(function_idx)
}
},
elements::Section::Element(elem_section) =>
for segment in elem_section.entries_mut() {
for function_idx in segment.members_mut() {
fixup(function_idx)
}
},
elements::Section::Start(start_idx) => fixup(start_idx),
_ => {},
}
}
Ok(module)
}
-157
View File
@@ -1,157 +0,0 @@
#[cfg(features = "std")]
use std::collections::{HashSet as Set};
#[cfg(not(features = "std"))]
use std::collections::{BTreeSet as Set};
use std::vec::Vec;
use parity_wasm::elements;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
pub enum Symbol {
Type(usize),
Import(usize),
Global(usize),
Function(usize),
Export(usize),
}
pub fn resolve_function(module: &elements::Module, index: u32) -> Symbol {
let mut functions = 0;
if let Some(import_section) = module.import_section() {
for (item_index, item) in import_section.entries().iter().enumerate() {
match item.external() {
&elements::External::Function(_) => {
if functions == index {
return Symbol::Import(item_index as usize);
}
functions += 1;
},
_ => {}
}
}
}
Symbol::Function(index as usize - functions as usize)
}
pub fn resolve_global(module: &elements::Module, index: u32) -> Symbol {
let mut globals = 0;
if let Some(import_section) = module.import_section() {
for (item_index, item) in import_section.entries().iter().enumerate() {
match item.external() {
&elements::External::Global(_) => {
if globals == index {
return Symbol::Import(item_index as usize);
}
globals += 1;
},
_ => {}
}
}
}
Symbol::Global(index as usize - globals as usize)
}
pub fn push_code_symbols(module: &elements::Module, opcodes: &[elements::Opcode], dest: &mut Vec<Symbol>) {
use parity_wasm::elements::Opcode::*;
for opcode in opcodes {
match opcode {
&Call(idx) => {
dest.push(resolve_function(module, idx));
},
&CallIndirect(idx, _) => {
dest.push(Symbol::Type(idx as usize));
},
&GetGlobal(idx) | &SetGlobal(idx) => {
dest.push(resolve_global(module, idx))
},
_ => { },
}
}
}
pub fn expand_symbols(module: &elements::Module, set: &mut Set<Symbol>) {
use self::Symbol::*;
// symbols that were already processed
let mut stop: Set<Symbol> = Set::new();
let mut fringe = set.iter().cloned().collect::<Vec<Symbol>>();
loop {
let next = match fringe.pop() {
Some(s) if stop.contains(&s) => { continue; }
Some(s) => s,
_ => { break; }
};
trace!("Processing symbol {:?}", next);
match next {
Export(idx) => {
let entry = &module.export_section().expect("Export section to exist").entries()[idx];
match entry.internal() {
&elements::Internal::Function(func_idx) => {
let symbol = resolve_function(module, func_idx);
if !stop.contains(&symbol) {
fringe.push(symbol);
}
set.insert(symbol);
},
&elements::Internal::Global(global_idx) => {
let symbol = resolve_global(module, global_idx);
if !stop.contains(&symbol) {
fringe.push(symbol);
}
set.insert(symbol);
},
_ => {}
}
},
Import(idx) => {
let entry = &module.import_section().expect("Import section to exist").entries()[idx];
match entry.external() {
&elements::External::Function(type_idx) => {
let type_symbol = Symbol::Type(type_idx as usize);
if !stop.contains(&type_symbol) {
fringe.push(type_symbol);
}
set.insert(type_symbol);
},
_ => {}
}
},
Function(idx) => {
let body = &module.code_section().expect("Code section to exist").bodies()[idx];
let mut code_symbols = Vec::new();
push_code_symbols(module, body.code().elements(), &mut code_symbols);
for symbol in code_symbols.drain(..) {
if !stop.contains(&symbol) {
fringe.push(symbol);
}
set.insert(symbol);
}
let signature = &module.function_section().expect("Functions section to exist").entries()[idx];
let type_symbol = Symbol::Type(signature.type_ref() as usize);
if !stop.contains(&type_symbol) {
fringe.push(type_symbol);
}
set.insert(type_symbol);
},
Global(idx) => {
let entry = &module.global_section().expect("Global section to exist").entries()[idx];
let mut code_symbols = Vec::new();
push_code_symbols(module, entry.init_expr().code(), &mut code_symbols);
for symbol in code_symbols.drain(..) {
if !stop.contains(&symbol) {
fringe.push(symbol);
}
set.insert(symbol);
}
}
_ => {}
}
stop.insert(next);
}
}
+122 -58
View File
@@ -1,18 +1,16 @@
extern crate diff;
extern crate pwasm_utils as utils;
extern crate wabt;
extern crate parity_wasm;
use std::fs;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use parity_wasm::elements;
use std::{
fs,
io::{self, Read, Write},
path::{Path, PathBuf},
};
use wasm_instrument::{self as instrument, gas_metering, parity_wasm::elements};
use wasmparser::validate;
fn slurp<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let mut f = fs::File::open(path)?;
let mut buf = vec![];
f.read_to_end(&mut buf)?;
Ok(buf)
let mut f = fs::File::open(path)?;
let mut buf = vec![];
f.read_to_end(&mut buf)?;
Ok(buf)
}
fn dump<P: AsRef<Path>>(path: P, buf: &[u8]) -> io::Result<()> {
@@ -21,46 +19,41 @@ fn dump<P: AsRef<Path>>(path: P, buf: &[u8]) -> io::Result<()> {
Ok(())
}
fn validate_wasm(binary: &[u8]) -> Result<(), wabt::Error> {
wabt::Module::read_binary(
&binary,
&Default::default()
)?.validate()?;
Ok(())
}
fn run_diff_test<F: FnOnce(&[u8]) -> Vec<u8>>(test_dir: &str, name: &str, test: F) {
let mut fixture_path = PathBuf::from(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/",
));
fn run_diff_test<F: FnOnce(&[u8]) -> Vec<u8>>(
test_dir: &str,
in_name: &str,
out_name: &str,
test: F,
) {
let mut fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
fixture_path.push("tests");
fixture_path.push("fixtures");
fixture_path.push(test_dir);
fixture_path.push(name);
fixture_path.push(in_name);
let mut expected_path = PathBuf::from(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/expectations/"
));
let mut expected_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
expected_path.push("tests");
expected_path.push("expectations");
expected_path.push(test_dir);
expected_path.push(name);
expected_path.push(out_name);
let fixture_wat = slurp(&fixture_path).expect("Failed to read fixture");
let fixture_wasm = wabt::wat2wasm(fixture_wat).expect("Failed to read fixture");
validate_wasm(&fixture_wasm).expect("Fixture is invalid");
let fixture_wasm = wat::parse_file(&fixture_path).expect("Failed to read fixture");
validate(&fixture_wasm).expect("Fixture is invalid");
let expected_wat = slurp(&expected_path).unwrap_or_default();
let expected_wat = String::from_utf8_lossy(&expected_wat);
let expected_wat = std::str::from_utf8(&expected_wat).expect("Failed to decode expected wat");
let actual_wasm = test(fixture_wasm.as_ref());
validate_wasm(&actual_wasm).expect("Result module is invalid");
validate(&actual_wasm).expect("Result module is invalid");
let actual_wat = wabt::wasm2wat(&actual_wasm).expect("Failed to convert result wasm to wat");
let actual_wat =
wasmprinter::print_bytes(&actual_wasm).expect("Failed to convert result wasm to wat");
if actual_wat != expected_wat {
println!("difference!");
println!("--- {}", expected_path.display());
println!("+++ {} test {}", test_dir, name);
for diff in diff::lines(&expected_wat, &actual_wat) {
println!("+++ {} test {}", test_dir, out_name);
for diff in diff::lines(expected_wat, &actual_wat) {
match diff {
diff::Result::Left(l) => println!("-{}", l),
diff::Result::Both(l, _) => println!(" {}", l),
@@ -68,26 +61,97 @@ fn run_diff_test<F: FnOnce(&[u8]) -> Vec<u8>>(test_dir: &str, name: &str, test:
}
}
dump(&expected_path, actual_wat.as_bytes()).expect("Failed to write to expected");
panic!();
if std::env::var_os("BLESS").is_some() {
dump(&expected_path, actual_wat.as_bytes()).expect("Failed to write to expected");
} else {
panic!();
}
}
}
macro_rules! def_stack_height_test {
( $name:ident ) => {
#[test]
fn $name() {
run_diff_test("stack-height", concat!(stringify!($name), ".wat"), |input| {
let module = elements::deserialize_buffer(input).expect("Failed to deserialize");
let instrumented = utils::stack_height::inject_limiter(module, 1024).expect("Failed to instrument with stack counter");
elements::serialize(instrumented).expect("Failed to serialize")
});
}
};
mod stack_height {
use super::*;
macro_rules! def_stack_height_test {
( $name:ident ) => {
#[test]
fn $name() {
run_diff_test(
"stack-height",
concat!(stringify!($name), ".wat"),
concat!(stringify!($name), ".wat"),
|input| {
let module =
elements::deserialize_buffer(input).expect("Failed to deserialize");
let instrumented = instrument::inject_stack_limiter(module, 1024)
.expect("Failed to instrument with stack counter");
elements::serialize(instrumented).expect("Failed to serialize")
},
);
}
};
}
def_stack_height_test!(simple);
def_stack_height_test!(start);
def_stack_height_test!(table);
def_stack_height_test!(global);
def_stack_height_test!(imports);
def_stack_height_test!(many_locals);
def_stack_height_test!(empty_functions);
}
def_stack_height_test!(simple);
def_stack_height_test!(table);
def_stack_height_test!(global);
def_stack_height_test!(imports);
mod gas {
use super::*;
macro_rules! def_gas_test {
( ($input:ident, $name1:ident, $name2:ident) ) => {
#[test]
fn $name1() {
run_diff_test(
"gas",
concat!(stringify!($input), ".wat"),
concat!(stringify!($name1), ".wat"),
|input| {
let rules = gas_metering::ConstantCostRules::default();
let module: elements::Module =
elements::deserialize_buffer(input).expect("Failed to deserialize");
let module = module.parse_names().expect("Failed to parse names");
let backend = gas_metering::host_function::Injector::new("env", "gas");
let instrumented = gas_metering::inject(module, backend, &rules)
.expect("Failed to instrument with gas metering");
elements::serialize(instrumented).expect("Failed to serialize")
},
);
}
#[test]
fn $name2() {
run_diff_test(
"gas",
concat!(stringify!($input), ".wat"),
concat!(stringify!($name2), ".wat"),
|input| {
let rules = gas_metering::ConstantCostRules::default();
let module: elements::Module =
elements::deserialize_buffer(input).expect("Failed to deserialize");
let module = module.parse_names().expect("Failed to parse names");
let backend = gas_metering::mutable_global::Injector::new("gas_left");
let instrumented = gas_metering::inject(module, backend, &rules)
.expect("Failed to instrument with gas metering");
elements::serialize(instrumented).expect("Failed to serialize")
},
);
}
};
}
def_gas_test!((ifs, ifs_host_fn, ifs_mut_global));
def_gas_test!((simple, simple_host_fn, simple_mut_global));
def_gas_test!((start, start_host_fn, start_mut_global));
def_gas_test!((call, call_host_fn, call_mut_global));
def_gas_test!((branch, branch_host_fn, branch_mut_global));
}
+31
View File
@@ -0,0 +1,31 @@
(module
(type (;0;) (func (result i32)))
(type (;1;) (func (param i64)))
(import "env" "gas" (func (;0;) (type 1)))
(func $fibonacci_with_break (;1;) (type 0) (result i32)
(local i32 i32)
i64.const 15
call 0
block ;; label = @1
i32.const 0
local.set 0
i32.const 1
local.set 1
local.get 0
local.get 1
local.tee 0
i32.add
local.set 1
i32.const 1
br_if 0 (;@1;)
i64.const 5
call 0
local.get 0
local.get 1
local.tee 0
i32.add
local.set 1
end
local.get 1
)
)
@@ -0,0 +1,47 @@
(module
(type (;0;) (func (result i32)))
(type (;1;) (func (param i64)))
(func $fibonacci_with_break (;0;) (type 0) (result i32)
(local $x i32) (local $y i32)
i64.const 26
call 1
block ;; label = @1
i32.const 0
local.set $x
i32.const 1
local.set $y
local.get $x
local.get $y
local.tee $x
i32.add
local.set $y
i32.const 1
br_if 0 (;@1;)
i64.const 16
call 1
local.get $x
local.get $y
local.tee $x
i32.add
local.set $y
end
local.get $y
)
(func (;1;) (type 1) (param i64)
global.get 0
local.get 0
i64.ge_u
if ;; label = @1
global.get 0
local.get 0
i64.sub
global.set 0
else
i64.const -1
global.set 0
unreachable
end
)
(global (;0;) (mut i64) i64.const 0)
(export "gas_left" (global 0))
)
+22
View File
@@ -0,0 +1,22 @@
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (param i64)))
(import "env" "gas" (func (;0;) (type 1)))
(func $add_locals (;1;) (type 0) (param $x i32) (param $y i32) (result i32)
(local i32)
i64.const 6
call 0
local.get $x
local.get $y
call $add
local.set 2
local.get 2
)
(func $add (;2;) (type 0) (param i32 i32) (result i32)
i64.const 3
call 0
local.get 0
local.get 1
i32.add
)
)
@@ -0,0 +1,38 @@
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (param i64)))
(func $add_locals (;0;) (type 0) (param $x i32) (param $y i32) (result i32)
(local $t i32)
i64.const 17
call 2
local.get $x
local.get $y
call $add
local.set $t
local.get $t
)
(func $add (;1;) (type 0) (param $x i32) (param $y i32) (result i32)
i64.const 14
call 2
local.get $x
local.get $y
i32.add
)
(func (;2;) (type 1) (param i64)
global.get 0
local.get 0
i64.ge_u
if ;; label = @1
global.get 0
local.get 0
i64.sub
global.set 0
else
i64.const -1
global.set 0
unreachable
end
)
(global (;0;) (mut i64) i64.const 0)
(export "gas_left" (global 0))
)
+22
View File
@@ -0,0 +1,22 @@
(module
(type (;0;) (func (param i32) (result i32)))
(type (;1;) (func (param i64)))
(import "env" "gas" (func (;0;) (type 1)))
(func (;1;) (type 0) (param i32) (result i32)
i64.const 2
call 0
i32.const 1
if (result i32) ;; label = @1
i64.const 3
call 0
local.get 0
i32.const 1
i32.add
else
i64.const 2
call 0
local.get 0
i32.popcnt
end
)
)
+38
View File
@@ -0,0 +1,38 @@
(module
(type (;0;) (func (param i32) (result i32)))
(type (;1;) (func (param i64)))
(func (;0;) (type 0) (param $x i32) (result i32)
i64.const 13
call 1
i32.const 1
if (result i32) ;; label = @1
i64.const 14
call 1
local.get $x
i32.const 1
i32.add
else
i64.const 13
call 1
local.get $x
i32.popcnt
end
)
(func (;1;) (type 1) (param i64)
global.get 0
local.get 0
i64.ge_u
if ;; label = @1
global.get 0
local.get 0
i64.sub
global.set 0
else
i64.const -1
global.set 0
unreachable
end
)
(global (;0;) (mut i64) i64.const 0)
(export "gas_left" (global 0))
)
+27
View File
@@ -0,0 +1,27 @@
(module
(type (;0;) (func))
(type (;1;) (func (param i64)))
(import "env" "gas" (func (;0;) (type 1)))
(func (;1;) (type 0)
i64.const 2
call 0
i32.const 1
if ;; label = @1
i64.const 1
call 0
loop ;; label = @2
i64.const 2
call 0
i32.const 123
drop
end
end
)
(func (;2;) (type 0)
i64.const 1
call 0
block ;; label = @1
end
)
(export "simple" (func 1))
)
@@ -0,0 +1,43 @@
(module
(type (;0;) (func))
(type (;1;) (func (param i64)))
(func (;0;) (type 0)
i64.const 13
call 2
i32.const 1
if ;; label = @1
i64.const 12
call 2
loop ;; label = @2
i64.const 13
call 2
i32.const 123
drop
end
end
)
(func (;1;) (type 0)
i64.const 12
call 2
block ;; label = @1
end
)
(func (;2;) (type 1) (param i64)
global.get 0
local.get 0
i64.ge_u
if ;; label = @1
global.get 0
local.get 0
i64.sub
global.set 0
else
i64.const -1
global.set 0
unreachable
end
)
(global (;0;) (mut i64) i64.const 0)
(export "simple" (func 0))
(export "gas_left" (global 0))
)
+20
View File
@@ -0,0 +1,20 @@
(module
(type (;0;) (func (param i32 i32)))
(type (;1;) (func))
(type (;2;) (func (param i64)))
(import "env" "ext_return" (func $ext_return (;0;) (type 0)))
(import "env" "memory" (memory (;0;) 1 1))
(import "env" "gas" (func (;1;) (type 2)))
(func $start (;2;) (type 1)
i64.const 4
call 1
i32.const 8
i32.const 4
call $ext_return
unreachable
)
(func (;3;) (type 1))
(export "call" (func 3))
(start $start)
(data (;0;) (i32.const 8) "\01\02\03\04")
)
@@ -0,0 +1,36 @@
(module
(type (;0;) (func (param i32 i32)))
(type (;1;) (func))
(type (;2;) (func (param i64)))
(import "env" "ext_return" (func $ext_return (;0;) (type 0)))
(import "env" "memory" (memory (;0;) 1 1))
(func $start (;1;) (type 1)
i64.const 15
call 3
i32.const 8
i32.const 4
call $ext_return
unreachable
)
(func (;2;) (type 1))
(func (;3;) (type 2) (param i64)
global.get 0
local.get 0
i64.ge_u
if ;; label = @1
global.get 0
local.get 0
i64.sub
global.set 0
else
i64.const -1
global.set 0
unreachable
end
)
(global (;0;) (mut i64) i64.const 0)
(export "call" (func 2))
(export "gas_left" (global 0))
(start $start)
(data (;0;) (i32.const 8) "\01\02\03\04")
)
@@ -0,0 +1,56 @@
(module
(type (;0;) (func))
(func (;0;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 0
global.get 0
i32.const 2
i32.sub
global.set 0
)
(func (;1;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 0
global.get 0
i32.const 2
i32.sub
global.set 0
)
(func (;2;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 1
global.get 0
i32.const 2
i32.sub
global.set 0
)
(global (;0;) (mut i32) i32.const 0)
(export "main" (func 2))
)
+41 -38
View File
@@ -2,55 +2,58 @@
(type (;0;) (func))
(type (;1;) (func (param i32 i32) (result i32)))
(type (;2;) (func (param i32)))
(type (;3;) (func (param i32 i32) (result i32)))
(import "env" "foo" (func (;0;) (type 0)))
(func (;1;) (type 1) (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add)
(func (;2;) (type 2) (param i32)
(local i32)
get_global 0
(import "env" "foo" (func $foo (;0;) (type 0)))
(func $i32.add (;1;) (type 1) (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
)
(func (;2;) (type 2) (param $arg i32)
(local $tmp i32)
global.get $counter
i32.const 1
i32.add
tee_local 1
set_global 0
get_local 1
get_local 0
get_global 1
i32.const 2
local.tee $tmp
global.set $counter
local.get $tmp
local.get $arg
global.get 1
i32.const 4
i32.add
set_global 1
get_global 1
global.set 1
global.get 1
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 1
get_global 1
i32.const 2
call $i32.add
global.get 1
i32.const 4
i32.sub
set_global 1
drop)
(func (;3;) (type 3) (param i32 i32) (result i32)
get_local 0
get_local 1
get_global 1
i32.const 2
global.set 1
drop
)
(func (;3;) (type 1) (param i32 i32) (result i32)
local.get 0
local.get 1
global.get 1
i32.const 4
i32.add
set_global 1
get_global 1
global.set 1
global.get 1
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 1
get_global 1
i32.const 2
call $i32.add
global.get 1
i32.const 4
i32.sub
set_global 1)
(global (;0;) (mut i32) (i32.const 1))
(global (;1;) (mut i32) (i32.const 0))
(export "i32.add" (func 3)))
global.set 1
)
(global $counter (;0;) (mut i32) i32.const 1)
(global (;1;) (mut i32) i32.const 0)
(export "i32.add" (func 3))
)
+23 -21
View File
@@ -1,32 +1,34 @@
(module
(type (;0;) (func))
(type (;1;) (func (param i32 i32) (result i32)))
(type (;2;) (func (param i32 i32) (result i32)))
(import "env" "foo" (func (;0;) (type 0)))
(import "env" "boo" (func (;1;) (type 0)))
(import "env" "foo" (func $foo (;0;) (type 0)))
(import "env" "boo" (func $boo (;1;) (type 0)))
(func (;2;) (type 1) (param i32 i32) (result i32)
call 0
call 1
get_local 0
get_local 1
i32.add)
(func (;3;) (type 2) (param i32 i32) (result i32)
get_local 0
get_local 1
get_global 0
i32.const 2
call $foo
call $boo
local.get 0
local.get 1
i32.add
set_global 0
get_global 0
)
(func (;3;) (type 1) (param i32 i32) (result i32)
local.get 0
local.get 1
global.get 0
i32.const 4
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 2
get_global 0
i32.const 2
global.get 0
i32.const 4
i32.sub
set_global 0)
(global (;0;) (mut i32) (i32.const 0))
(export "i32.add" (func 3)))
global.set 0
)
(global (;0;) (mut i32) i32.const 0)
(export "i32.add" (func 3))
)
@@ -0,0 +1,24 @@
(module
(type (;0;) (func))
(func $one-group-many-locals (;0;) (type 0)
(local i64 i64 i32)
)
(func $main (;1;) (type 0)
global.get 0
i32.const 5
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call $one-group-many-locals
global.get 0
i32.const 5
i32.sub
global.set 0
)
(global (;0;) (mut i32) i32.const 0)
)
+15 -13
View File
@@ -1,24 +1,26 @@
(module
(type (;0;) (func))
(type (;1;) (func))
(func (;0;) (type 0)
i32.const 123
drop)
(func (;1;) (type 1)
get_global 0
i32.const 1
drop
)
(func (;1;) (type 0)
global.get 0
i32.const 3
i32.add
set_global 0
get_global 0
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 0
get_global 0
i32.const 1
global.get 0
i32.const 3
i32.sub
set_global 0)
(global (;0;) (mut i32) (i32.const 0))
(export "simple" (func 1)))
global.set 0
)
(global (;0;) (mut i32) i32.const 0)
(export "simple" (func 1))
)
+47
View File
@@ -0,0 +1,47 @@
(module
(type (;0;) (func (param i32 i32)))
(type (;1;) (func))
(import "env" "ext_return" (func $ext_return (;0;) (type 0)))
(import "env" "memory" (memory (;0;) 1 1))
(func $start (;1;) (type 1)
(local i32)
)
(func (;2;) (type 1))
(func (;3;) (type 1)
global.get 0
i32.const 3
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call $start
global.get 0
i32.const 3
i32.sub
global.set 0
)
(func (;4;) (type 1)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 2
global.get 0
i32.const 2
i32.sub
global.set 0
)
(global (;0;) (mut i32) i32.const 0)
(export "call" (func 4))
(start 3)
)
+47 -63
View File
@@ -2,87 +2,71 @@
(type (;0;) (func))
(type (;1;) (func (param i32)))
(type (;2;) (func (param i32 i32) (result i32)))
(type (;3;) (func (param i32 i32) (result i32)))
(type (;4;) (func (param i32)))
(type (;5;) (func (param i32 i32) (result i32)))
(import "env" "foo" (func (;0;) (type 0)))
(import "env" "foo" (func $foo (;0;) (type 0)))
(func (;1;) (type 1) (param i32)
get_local 0
local.get 0
i32.const 0
get_global 0
i32.const 2
global.get 0
i32.const 4
i32.add
set_global 0
get_global 0
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 2
get_global 0
i32.const 2
call $i32.add
global.get 0
i32.const 4
i32.sub
set_global 0
drop)
(func (;2;) (type 2) (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add)
(func (;3;) (type 3) (param i32 i32) (result i32)
get_local 0
get_local 1
get_global 0
i32.const 2
global.set 0
drop
)
(func $i32.add (;2;) (type 2) (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
set_global 0
get_global 0
)
(func (;3;) (type 1) (param i32)
local.get 0
global.get 0
i32.const 4
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 2
get_global 0
i32.const 2
i32.sub
set_global 0)
(func (;4;) (type 4) (param i32)
get_local 0
get_global 0
i32.const 2
i32.add
set_global 0
get_global 0
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 1
get_global 0
i32.const 2
global.get 0
i32.const 4
i32.sub
set_global 0)
(func (;5;) (type 5) (param i32 i32) (result i32)
get_local 0
get_local 1
get_global 0
i32.const 2
global.set 0
)
(func (;4;) (type 2) (param i32 i32) (result i32)
local.get 0
local.get 1
global.get 0
i32.const 4
i32.add
set_global 0
get_global 0
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
if ;; label = @1
unreachable
end
call 2
get_global 0
i32.const 2
call $i32.add
global.get 0
i32.const 4
i32.sub
set_global 0)
(table (;0;) 10 anyfunc)
(global (;0;) (mut i32) (i32.const 0))
(export "i32.add" (func 5))
(elem (i32.const 0) 0 4 5))
global.set 0
)
(table (;0;) 10 funcref)
(global (;0;) (mut i32) i32.const 0)
(export "i32.add" (func 4))
(elem (;0;) (i32.const 0) func $foo 3 4)
)
+27
View File
@@ -0,0 +1,27 @@
(module
(func $fibonacci_with_break (result i32)
(local $x i32) (local $y i32)
(block $unrolled_loop
(local.set $x (i32.const 0))
(local.set $y (i32.const 1))
local.get $x
local.get $y
local.tee $x
i32.add
local.set $y
i32.const 1
br_if $unrolled_loop
local.get $x
local.get $y
local.tee $x
i32.add
local.set $y
)
local.get $y
)
)
+19
View File
@@ -0,0 +1,19 @@
(module
(func $add_locals (param $x i32) (param $y i32) (result i32)
(local $t i32)
local.get $x
local.get $y
call $add
local.set $t
local.get $t
)
(func $add (param $x i32) (param $y i32) (result i32)
(i32.add
(local.get $x)
(local.get $y)
)
)
)
+9
View File
@@ -0,0 +1,9 @@
(module
(func (param $x i32) (result i32)
(if (result i32)
(i32.const 1)
(then (i32.add (local.get $x) (i32.const 1)))
(else (i32.popcnt (local.get $x)))
)
)
)
+17
View File
@@ -0,0 +1,17 @@
(module
(func (export "simple")
(if (i32.const 1)
(then
(loop
i32.const 123
drop
)
)
)
)
(func
block
end
)
)
+18
View File
@@ -0,0 +1,18 @@
(module
(import "env" "ext_return" (func $ext_return (param i32 i32)))
(import "env" "memory" (memory 1 1))
(start $start)
(func $start
(call $ext_return
(i32.const 8)
(i32.const 4)
)
(unreachable)
)
(func (export "call")
)
(data (i32.const 8) "\01\02\03\04")
)
+8
View File
@@ -0,0 +1,8 @@
(module
(func (;0;)
call 0
)
(func (;1;) (export "main")
call 0
)
)
+13 -13
View File
@@ -5,22 +5,22 @@
(global $counter (mut i32) (i32.const 1))
(func $i32.add (export "i32.add") (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add
local.get 0
local.get 1
i32.add
)
(func (param $arg i32)
(local $tmp i32)
(local $tmp i32)
get_global 0
i32.const 1
i32.add
tee_local $tmp
set_global $counter
global.get 0
i32.const 1
i32.add
local.tee $tmp
global.set $counter
get_local $tmp
get_local $arg
call $i32.add
drop
local.get $tmp
local.get $arg
call $i32.add
drop
)
)
+2 -2
View File
@@ -8,8 +8,8 @@
call $foo
call $boo
get_local 0
get_local 1
local.get 0
local.get 1
i32.add
)
)
+10
View File
@@ -0,0 +1,10 @@
(module
(func $one-group-many-locals
(local i64) (local i64) (local i32)
)
(func $main
(call
$one-group-many-locals
)
)
)
+11
View File
@@ -0,0 +1,11 @@
(module
(import "env" "ext_return" (func $ext_return (param i32 i32)))
(import "env" "memory" (memory 1 1))
(start $start)
(func $start
(local i32)
)
(func (export "call")
)
)
+8 -8
View File
@@ -1,17 +1,17 @@
(module
(import "env" "foo" (func $foo))
(func (param i32)
get_local 0
i32.const 0
call $i32.add
drop
local.get 0
i32.const 0
call $i32.add
drop
)
(func $i32.add (export "i32.add") (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add
local.get 0
local.get 1
i32.add
)
(table 10 anyfunc)
(table 10 funcref)
;; Refer all types of functions: imported, defined not exported and defined exported.
(elem (i32.const 0) 0 1 2)
+171
View File
@@ -0,0 +1,171 @@
use std::{
fs::{read, read_dir, ReadDir},
path::PathBuf,
};
use wasm_instrument::{
gas_metering::{self, host_function, mutable_global, ConstantCostRules},
inject_stack_limiter,
parity_wasm::{deserialize_buffer, elements::Module, serialize},
};
fn fixture_dir() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("benches");
path.push("fixtures");
path
}
use gas_metering::Backend;
fn gas_metered_mod_len<B: Backend>(orig_module: Module, backend: B) -> (Module, usize) {
let module = gas_metering::inject(orig_module, backend, &ConstantCostRules::default()).unwrap();
let bytes = serialize(module.clone()).unwrap();
let len = bytes.len();
(module, len)
}
fn stack_limited_mod_len(module: Module) -> (Module, usize) {
let module = inject_stack_limiter(module, 128).unwrap();
let bytes = serialize(module.clone()).unwrap();
let len = bytes.len();
(module, len)
}
struct InstrumentedWasmResults {
filename: String,
original_module_len: usize,
stack_limited_len: usize,
gas_metered_host_fn_len: usize,
gas_metered_mut_glob_len: usize,
gas_metered_host_fn_then_stack_limited_len: usize,
gas_metered_mut_glob_then_stack_limited_len: usize,
}
fn size_overheads_all(files: ReadDir) -> Vec<InstrumentedWasmResults> {
files
.map(|entry| {
let entry = entry.unwrap();
let filename = entry.file_name().into_string().unwrap();
let (original_module_len, orig_module) = {
let bytes = match entry.path().extension().unwrap().to_str() {
Some("wasm") => read(entry.path()).unwrap(),
Some("wat") =>
wat::parse_bytes(&read(entry.path()).unwrap()).unwrap().into_owned(),
_ => panic!("expected fixture_dir containing .wasm or .wat files only"),
};
let len = bytes.len();
let module: Module = deserialize_buffer(&bytes).unwrap();
(len, module)
};
let (gm_host_fn_module, gas_metered_host_fn_len) = gas_metered_mod_len(
orig_module.clone(),
host_function::Injector::new("env", "gas"),
);
let (gm_mut_global_module, gas_metered_mut_glob_len) =
gas_metered_mod_len(orig_module.clone(), mutable_global::Injector::new("gas_left"));
let stack_limited_len = stack_limited_mod_len(orig_module).1;
let (_gm_hf_sl_mod, gas_metered_host_fn_then_stack_limited_len) =
stack_limited_mod_len(gm_host_fn_module);
let (_gm_mg_sl_module, gas_metered_mut_glob_then_stack_limited_len) =
stack_limited_mod_len(gm_mut_global_module);
InstrumentedWasmResults {
filename,
original_module_len,
stack_limited_len,
gas_metered_host_fn_len,
gas_metered_mut_glob_len,
gas_metered_host_fn_then_stack_limited_len,
gas_metered_mut_glob_then_stack_limited_len,
}
})
.collect()
}
fn calc_size_overheads() -> Vec<InstrumentedWasmResults> {
let mut wasm_path = fixture_dir();
wasm_path.push("wasm");
let mut wat_path = fixture_dir();
wat_path.push("wat");
let mut results = size_overheads_all(read_dir(wasm_path).unwrap());
let results_wat = size_overheads_all(read_dir(wat_path).unwrap());
results.extend(results_wat);
results
}
/// Print the overhead of applying gas metering, stack
/// height limiting or both.
///
/// Use `cargo test print_size_overhead -- --nocapture`.
#[test]
fn print_size_overhead() {
let mut results = calc_size_overheads();
results.sort_unstable_by(|a, b| {
b.gas_metered_mut_glob_then_stack_limited_len
.cmp(&a.gas_metered_mut_glob_then_stack_limited_len)
});
for r in results {
let filename = r.filename;
let original_size = r.original_module_len / 1024;
let stack_limit = r.stack_limited_len * 100 / r.original_module_len;
let host_fn = r.gas_metered_host_fn_len * 100 / r.original_module_len;
let mut_glob = r.gas_metered_mut_glob_len * 100 / r.original_module_len;
let host_fn_sl = r.gas_metered_host_fn_then_stack_limited_len * 100 / r.original_module_len;
let mut_glob_sl =
r.gas_metered_mut_glob_then_stack_limited_len * 100 / r.original_module_len;
println!(
"{filename:30}: orig = {original_size:4} kb, stack_limiter = {stack_limit} %, \
gas_metered_host_fn = {host_fn} %, both = {host_fn_sl} %,\n \
{:69} gas_metered_mut_global = {mut_glob} %, both = {mut_glob_sl} %",
""
);
}
}
/// Compare module size overhead of applying gas metering with two methods.
///
/// Use `cargo test print_gas_metered_sizes -- --nocapture`.
#[test]
fn print_gas_metered_sizes() {
let overheads = calc_size_overheads();
let mut results = overheads
.iter()
.map(|r| {
let diff = (r.gas_metered_mut_glob_len * 100 / r.gas_metered_host_fn_len) as i32 - 100;
(diff, r)
})
.collect::<Vec<(i32, &InstrumentedWasmResults)>>();
results.sort_unstable_by(|a, b| b.0.cmp(&a.0));
println!(
"| {:28} | {:^16} | gas metered/host fn | gas metered/mut global | size diff |",
"fixture", "original size",
);
println!("|{:-^30}|{:-^18}|{:-^21}|{:-^24}|{:-^11}|", "", "", "", "", "",);
for r in results {
let filename = &r.1.filename;
let original_size = &r.1.original_module_len / 1024;
let host_fn = &r.1.gas_metered_host_fn_len / 1024;
let mut_glob = &r.1.gas_metered_mut_glob_len / 1024;
let host_fn_percent = &r.1.gas_metered_host_fn_len * 100 / r.1.original_module_len;
let mut_glob_percent = &r.1.gas_metered_mut_glob_len * 100 / r.1.original_module_len;
let host_fn = format!("{host_fn} kb ({host_fn_percent:}%)");
let mut_glob = format!("{mut_glob} kb ({mut_glob_percent:}%)");
let diff = &r.0;
println!(
"| {filename:28} | {original_size:13} kb | {host_fn:>19} | {mut_glob:>22} | {diff:+8}% |"
);
}
}