170 lines
3.8 KiB
Markdown
170 lines
3.8 KiB
Markdown
# WAG - The WebAssembly Code Generator
|
|
|
|
This Ruby gem allows you to generate WebAssembly programs programmatically using
|
|
a DSL.
|
|
|
|
It is closely modeled after WAT, the WebAssembly text format, and at this stage
|
|
generates WAT and compiles and validates it using [the WebAssembly Binary Toolkit][1].
|
|
|
|
Due to the flexibility of WAT this library is very flexible in what structures
|
|
it allows you to create. Be aware that you can build modules which are not
|
|
valid WASM. Always validate your modules by using `#to_wasm.valid?`.
|
|
|
|
## Keyword conflict
|
|
|
|
Any WASM instructions whose name conflicts with a Ruby keyword (eg `loop`,
|
|
`return`, etc) are also aliased with a underscore suffix for use in the DSL. The
|
|
methods defining the original names are also there, so can be used by the likes
|
|
of `public_send`, etc.
|
|
|
|
## Folding
|
|
|
|
WAG supports generating both the "folded" and "unfolded" variants of the WAT
|
|
language. As an example here are two implementations of Euclid's Greatest
|
|
Common Divisor algorithm:
|
|
|
|
### Example of unfolded generation
|
|
|
|
```ruby
|
|
unfolded = WAG::Module.new.build do
|
|
func(:gcd) do
|
|
param(:a, :i32)
|
|
param(:b, :i32)
|
|
result(:i32)
|
|
local(:r, :i32)
|
|
|
|
block
|
|
loop_
|
|
|
|
# let r = a % b
|
|
local.get(:a)
|
|
local.get(:b)
|
|
i32.rem_s
|
|
local.set(:r)
|
|
|
|
# let a = b and b = R
|
|
local.get(:b)
|
|
local.set(:a)
|
|
local.get(:r)
|
|
local.set(:b)
|
|
|
|
|
|
# if a % b == 0, return b
|
|
local.get(:a)
|
|
local.get(:b)
|
|
i32.rem_s
|
|
i32.eqz
|
|
br_if 1
|
|
|
|
br 0
|
|
end_
|
|
end_
|
|
|
|
local.get(:b)
|
|
return_
|
|
end
|
|
export("gcd").func(:gcd)
|
|
end
|
|
```
|
|
|
|
### Example of folded generation
|
|
```ruby
|
|
folded = WAG::Module.new.build do
|
|
func(:gcd) do
|
|
param(:a, :i32)
|
|
param(:b, :i32)
|
|
result(:i32)
|
|
|
|
local(:r, :i32)
|
|
|
|
block do
|
|
loop_ do
|
|
# let r = a % b
|
|
local.set(:r) do
|
|
i32.rem_s do
|
|
local.get(:a)
|
|
local.get(:b)
|
|
end
|
|
end
|
|
|
|
# let a = b and b = R
|
|
local.set(:a) do
|
|
local.get(:b)
|
|
end
|
|
local.set(:b) do
|
|
local.get(:r)
|
|
end
|
|
|
|
# if a % b == 0, return b
|
|
br_if(1) do
|
|
i32.eqz do
|
|
i32.rem_s do
|
|
local.get(:a)
|
|
local.get(:b)
|
|
end
|
|
end
|
|
end
|
|
|
|
br 0
|
|
end
|
|
end
|
|
|
|
return_ do
|
|
local.get(:b)
|
|
end
|
|
end
|
|
export("gcd") do
|
|
func(:gcd)
|
|
end
|
|
end
|
|
```
|
|
|
|
Both modules emit identical WASM bytecode and produce the same answers:
|
|
|
|
```ruby
|
|
folded.to_wasm.save("folded.wasm")
|
|
unfolded.to_wasm.save("unfolded.wasm")
|
|
```
|
|
|
|
```bash
|
|
$ sha256sum folded.wasm unfolded.wasm
|
|
0023ef97eba001226401e432912f2e644a6cbef107ba183546c51177eee46e2c folded.wasm
|
|
0023ef97eba001226401e432912f2e644a6cbef107ba183546c51177eee46e2c unfolded.wasm
|
|
$ wasmtime folded.wasm --invoke gcd 270 192
|
|
6
|
|
$ wasmtime unfolded.wasm --invoke gcd 270 192
|
|
6
|
|
```
|
|
|
|
1: https://github.com/WebAssembly/wabt
|
|
|
|
## Installation
|
|
|
|
Add this line to your application's `Gemfile`:
|
|
|
|
```ruby
|
|
gem 'wag'
|
|
```
|
|
|
|
And then execute:
|
|
|
|
$ bundle install
|
|
|
|
Or install it yourself as:
|
|
|
|
$ gem install wag
|
|
|
|
|
|
## Development
|
|
|
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
|
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
|
|
## Contributing
|
|
|
|
Bug reports and pull requests are welcome on GitLab at https://gitlab.com/jimsy/wag.
|
|
|
|
## License
|
|
|
|
The gem is available as open source under the terms of the [Hippocratic License](https://firstdonoharm.dev/version/2/1/license.html).
|