Skip to content

Latest commit

 

History

History
333 lines (226 loc) · 15.7 KB

CHANGELOG.md

File metadata and controls

333 lines (226 loc) · 15.7 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Types of changes

  • Added for new features.
  • Changed for changes in existing functionality.
  • Deprecated for soon-to-be removed features.
  • Removed for now removed features.
  • Fixed for any bug fixes.
  • Security in case of vulnerabilities.

[unreleased]

Added

[0.9.1 - 2024-07-27]

Same as 0.9.1, but with correct checksum for precompiled binaries

[0.9.0 - 2024-07-25]

Wasmtime rewrote their fuel-related API and simplified it. To remain consistent with Wasmtime, we follow this change in this release. A Wasmex Store now only implements set_fuel/2 and get_fuel/1. All other methods are removed with this release.

The underlying implementation of the fuel system got rewritten as well. If you are using fuel in your app, please check your fuel consumption values.

Added

  • official support for Elixir 1.15 and 1.16
  • fuel-related API got rewritten, because the underlying Wasm library (wasmtime) changed their API and we want to be consistent. Added Store.get_fuel/1 and Store.set_fuel/2 which is a much simpler API than before.
  • read and write a global’s value with Instance.get_global_value/3 and Instance.set_global_value/4 (#540)
  • ability to dynamically link wasm modules (#596) thanks @munjalpatel
  • ability to use 128 bit unsigned integers (wasm type V128)
  • added support for multi-value returns from WASM and elixir callbacks. This enables passing string return values safely by pointer and length, for example.

Removed

  • removed support for Elixir 1.12
  • with the fuel-related API changed, the existing methods on Store (consume_fuel, fuel_remaining, add_fuel) were removed. Please call set_fuel/2 and get_fuel/1 instead.

Changed

  • Dependency updates (most notably wasmtime and rustler) - thanks @RoyalIcing and @scrogson
  • removed dialyzer

[0.8.3] - 2023-05-24

Added

  • added support for riscv64gc-unknown-linux-gnu
  • added support for OTP 26

Changed

  • updated rustler from 0.27.0 to 0.28.0
  • updated wasmtime from 4.0.1 to 9.0.1

[0.8.2] - 2023-01-08

Added

  • list aarch64-unknown-linux-musl in rustler targets, so we actually include it in our releases

[0.8.1] - 2023-01-08

This release makes running user-provided Wasm binaries a whole bunch safter by providing restrictions on memory and CPU usage.

Have a look at Wasmex.StoreLimits for memory restrictions and Wasmer.EngineConfig on how to limit fuel (CPU usage quota).

The new Wasmex.EngineConfig allows better reporting when Wasm execution fails -- setting wasm_backtrace_details enables error backtraces to include file and line number information if that debug info is available in the running Wasm file.

A Wasmex.EngineConfig is used to create a Wasmex.Engine, which holds configuration for a Wasmex.Store. It allows us to selectively enable/disable more Wasm option (e.g. enabling certain Wasm proposals). Today, a Wasmex.Engine already gives us a faster way to precompile modules without the need to instantiate them through Wasmex.Engine.precompile_module/2.

Added

  • Added precompiled binary for aarch64-unknown-linux-musl
  • Added support for setting store limits. This allows users to limit memory usage, instance creation, table sizes and more. See Wasmex.StoreLimits for details.
  • Added support for metering/fuel_consumption. This allows users to limit CPU usage. A Wasmex.Store can be given fuel, where each Wasm instruction of a running Wasm binary uses a certain amount of fuel. If no fuel remains, execution stops. See Wasmex.EngineConfig for details.
  • Added Wasmex.EngineConfig as a place for more complex Wasm settings. With this release an engine can be configured to provide more detailed backtraces on errors during Wasm execution by setting the wasm_backtrace_details flag.
  • Added Wasmex.Engine.precompile_module/2 which allows module precompilation from a .wat or .wasm binary without the need to instantiate said module. A precompiled module can be hydrated with Module.unsafe_deserialize/2.
  • Added Wasmex.module/1 and Wasmex.store/1 to access the module and store of a running Wasmex GenServer process.
  • Added option to Wasmex.EngineConfig to configure the cranelift_opt_level (:none, :speed, :speed_and_size) allowing users to trade compilation time against execution speed

Changed

  • mix.exs now also requires at least Elixir 1.12
  • Module.unsafe_deserialize/2 now accepts a Wasmex.Engine in addition to the serialized module binary. It's best to hydrate a module using the same engine config used to serialize or precompile it. It has no harsh consequences today, but will be important when we add more Wasm features (e.g. SIMD support) in the future.
  • added typespecs for all public Wasmex methods
  • improved documentation and typespecs
  • allow starting the Wasmex GenServer with a %{bytes: bytes, store: store} map as a convenience to spare users the task of manually compiling a Wasmex.Module

[0.8.0] - 2023-01-03

This release brings some changes to our API because of the change of the underlying Wasm engine to wasmtime.

It brings a new abstraction, the Wasmex.Store, which holds all internal structures. Thus, the store (or a "caller" in function-call contexts) needs to be provided in most Wasmex APIs in the form of a Wasmex.StoreOrCaller struct.

The Wasm engine change requires us to do further changes, most notably a change in how Wasmex.Memory is accessed. We dropped support for different data types and simplified the memory model to be just an array of bytes. The concept of memory offsets was dropped.

Please visit the list of changes below for more details.

Added

  • Added support for OTP 25
  • Added support for Elixir 1.14

Removed

  • Removed official support for OTP 22 and 23
  • Removed official support for Elixir 1.12
  • Removed Wasmex.Module.set_name() without replacement as this is not supported by Wasmtime
  • Removed Wasmex.Memory.bytes_per_element() without replacement because we dropped support for different data types and now only handle bytes
  • Removed Wasmex.Pipe.set_len() without replacement
  • WASI directory/file preopens can not configure read/write/create permissions anymore because wasmtime does not support this feature well. We very much plan to add support back once wasmtime allows.

Changed

  • Changed the underlying Wasm engine from wasmer to wasmtime
  • Removed Wasmex.Instance.new() and Wasmex.Instance.new_wasi() in favor of Wasmex.Store.new() and Wasmex.Store.new_wasi().
  • WASI-options to Wasmex.Store.new_wasi() are now a proper struct Wasmex.Wasi.WasiOptions to improve typespecs, docs, and compile-time warnings.
  • Wasmex.Pipe went through an internal rewrite. It is now a positioned read/write stream. You may change the read/write position with Wasmex.Pipe.seek()
  • Renamed Wasmex.Pipe.create() to Wasmex.Pipe.new() to be consistent with other struct-creation calls
  • Renamed Wasmex.Memory.length() to Wasmex.Memory.size() for consistenct with other size methods
  • Renamed Wasmex.Memory.set() to Wasmex.Memory.set_byte()
  • Renamed Wasmex.Memory.get() to Wasmex.Memory.get_byte()
  • Updated and rewrote most of the docs - all examples are now doctests and tested on CI
  • Updated all Elixir/Rust dependencies

[0.7.1] - 2022-05-25

Added

  • Added an optional fourth parameter to call_function, timeout, which accepts a value in milliseconds that will cap the execution time of the function. The default behavior if not supplied is preserved, which is a 5 second timeout. Thanks @brooksmtownsend for this contribution

[0.7.0] - 2022-03-27

Added

  • Added support for precompiled binaries. This should reduce compilation time of wasmex significantly. At the same time it frees most of our users from needing to install Rust. Thanks @fahchen for implementing this feature

Changed

  • Wasmex now aims to support the last three elixir and OTP releases. The oldest supported versions for this release are elixir 1.11.4 and OTP 22.3 - Thanks to @fahchen for contributing the CI workflow to test older elixir/OTP versions
  • Moved CI systems from CircleCI to GitHub Actions. Let me thank CircleCI forthe years of free of charge CI runs, thanks! Let me also thank @fahchen for contributing this change
  • Thanks to @phaleth for fixing page sizes in our Memory documentation
  • Updated several project dependencies, most notably wasmer to 2.1.1

[0.6.0] - 2021-08-07

Added

  • Wasmex.Module.compile/1 which compiles a .wasm file into a module. This module can be given to the new methods Wasmex.Instance.new/2 and Wasmex.Instance.new_wasi/3 allowing to re-use precompiled modules. This has a big potential speed-up if one wishes to run a WASI instance multiple times. For example, the wasmex test suite went from 14.5s to 0.6s runtime with this release.
  • Wasmex.start_link can now be called with a precompiled module.
  • Wasmex.Module.compile/1 can now parse WebAssembly text format (WAT) too.
  • Wasm modules without exported memory can now be instantiated without error.
  • Added the following functions to Wasmex.Module:
    • serialize/1 and unsafe_deserialize/1 which allows serializing a module into a binary and back
    • name/1 and set_name/1 which allows getting/setting a modules name for better debugging
    • imports/1 and exports/1 which lists a modules imports and exports

Deprecated

  • Instance.from_bytes/2 and Instance.wasi_from_bytes/3 are deprecated in favor of Wasmex.Instance.new/2 and Wasmex.Instance.new_wasi/3. Both may be removed in any release after this one.

[0.5.0] - 2021-07-22

Added

# after a `wapm install cowsay`
{:ok, bytes } = File.read("wapm_packages/_/[email protected]/target/wasm32-wasi/release/cowsay.wasm")
{:ok, stdout} = Wasmex.Pipe.create()
{:ok, stdin} = Wasmex.Pipe.create()
{:ok, instance } = Wasmex.start_link(%{bytes: bytes, wasi: %{stdout: stdout, stdin: stdin}})
Wasmex.Pipe.write(stdin, "Why do you never see elephants hiding in trees? Because they're really good at it.")
{:ok, _} = Wasmex.call_function(instance, :_start, [])
IO.puts Wasmex.Pipe.read(stdout)
  ________________________________________
/ Why do you never see elephants hiding  \
| in trees? Because they're really good  |
\ at it.                                 /
 ----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
               ||----w |
                ||     ||
:ok

[0.4.0] - 2021-06-24

Added

  • added support for OTP 24.0 (by updating rustler)

Changed

  • Wasmex.Memory.bytes_per_element changed its signature from Wasmex.Memory.bytes_per_element(memory, :uint32, 0) to Wasmex.Memory.bytes_per_element(:uint32). The existing signature Wasmex.Memory.bytes_per_element(memory) still works as before.
  • changed the default development branch from master to main
  • targeting and testing on elixir 1.12 and OTP 24.0 now - older versions are likely still working, but will not be tested anymore.

Removed

  • Wasmex.Memory.grow/4 was removed. Instead Wasmex.Memory.grow/2 can be used interchangeably.

[0.3.1] - 2021-04-04

Added

  • added support for aarch64-darwin (apple silicon). Thanks @epellis

Changed

  • removed use of unsafe from wasm<->elixir value conversion. Thanks @Virviil

[0.3.0] - 2021-01-09

Notable Changes

This release features support for elixir function that can be exported to Wasm.

It also supports the latest wasmer v 1.0 🎉. Wasmer 1.0 is a partial rewrite of the Wasm engine we use that promises to be up to 9 times faster module compilation.

Added

  • added the instances first memory into the callback context
imports = %{
  env: %{
    read_and_set_memory:
      {:fn, [], [:i32],
        fn context ->
          memory = Map.get(context, :memory)
          42 = Wasmex.Memory.get(memory, :uint8, 0, 0) # assert that the first byte in the memory was set to 42
          Wasmex.Memory.set(memory, :uint8, 0, 0, 23)
          0
        end},
  }
}

instance = start_supervised!({Wasmex, %{bytes: @import_test_bytes, imports: imports}})
Wasmex.Memory.set(memory, :uint8, 0, 0, 42)

# asserts that the byte at memory[0] was set to 42 and then sets it to 23
{:ok, _} = Wasmex.call_function(instance, :a_wasm_fn_that_calls_read_and_set_memory, [])

assert 23 == Wasmex.Memory.get(memory, :uint8, 0, 0)
  • added support for function imports
imports = %{
  env: %{
    sum3: {:fn, [:i32, :i32, :i32], [:i32], fn (_context, a, b, c) -> a + b + c end},
  }
}
instance = start_supervised!({Wasmex, %{bytes: @import_test_bytes, imports: imports}})

{:ok, [6]} = Wasmex.call_function(instance, "use_the_imported_sum_fn", [1, 2, 3])

Thanks to

  • @bamorim for helping me plan and architect,
  • @myobie for help in implementation, especially for implementing the function signature checks,
  • @rylev for a second eye on our Rust code,
  • the @wasmerio team for the recent addition of DynFunc which made this feature possible, and
  • @bitcrowd for sponsoring me to work on this feature

Changed

  • Changed writing and reading strings from/to memory to be based on string length and not expect null-byte terminated strings. This allows for a more flexible memory handling when writing arbitrary data or strings containing null bytes to/from memory. Thanks @myobie for implementing this feature
  • Support writing non-string binaries to memory. Before we could only write valid UTF-8 strings to Wasm memory. Thanks again, @myobie, for implementing this feature
  • Updated the wasmer version, now supporting wasmer 1.0.
  • Updated to elixir 1.11 and Erlang OTP 23.2. Older versions might work, but are not officially tested

Fixed

  • could not convert callback result param to expected return signature error for a void callback.

[0.2.0] - 2020-04-14

This release brings is closer to a production-ready experience. Calls of WebAssembly functions are now handled asynchronously: Invoking a Wasm function via Instance.call_exported_function calls our Rust NIF as before, but does not directly execute the function. Instead, a new OS thread is spawned for the actual execution. This allows us to spend only few time in the NIF code (as required by the Erlang VM). Once the Wasm function in that thread returns, we send a message to the calling erlang process. To ease handling, we converted our main module Wasmex into a GenServer so that a Wasm function call can be used in a synchronous manner as before.

Added

  • The Wasmex module is now a GenServer. Wasm function calls are now asynchronous.

Changed

  • Removed unused Rust dependencies
  • Provide better error messages for Wasmex.Instance.from_bytes when the Wasm instance could not be instantiated.
  • Wasm function calls now return a list of return values instead of just one value (this is to prepare for Wasm tu officially support multiple return values)
  • Updated elixir and rust dependencies including wasmer to version 0.16.2

Removed

  • Instance.call_exported_function/2 use Instance.call_exported_function/3 instead.

Fixed

  • Enhanced documentation

[0.1.0] - 2020-01-15

Changed

  • First release