Skip to content

technohippy/wasmrb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WASM.rb

WASM Runner in Ruby language

I'm developing this tool for a learning purpose. There must be many bugs and unimplemented specs.

How to Install

$ gem install wasmrb

How to Test

$ ruby test/run-test.rb

How to Use

Load and Inspect

Code:

loader = WebAssembly::WASMLoader.new
mod = loader.load "add.wasm"
pp mod.to_hash
Shortcut:
mod = WebAssembly::load "add.wasm"
pp mod.to_hash

Output:

{:magic=>[0, 97, 115, 109],
 :version=>[1, 0, 0, 0],
 :sections=>
  [{:section=>"type",
    :id=>1,
    :size=>7,
    :types=>[{:params=>[:i32, :i32], :results=>[:i32]}]},
   {:section=>"function", :id=>3, :size=>2, :types=>[0]},
   {:section=>"export",
    :id=>7,
    :size=>7,
    :exports=>[{:name=>"add", :desc=>{:func=>0}}]},
   {:section=>"code",
    :id=>10,
    :size=>9,
    :codes=>
     [{:locals=>[],
       :expressions=>
        [{:name=>"local.get", :index=>0},
         {:name=>"local.get", :index=>1},
         {:name=>"i32.add"}]}]}]}

Run Exported Function

Code:

loader = WebAssembly::WASMLoader.new
mod = loader.load "add.wasm"
inst = mod.instantiate
puts inst.exports.add(1, 2)
Shortcut:
inst = WebAssembly::instantiate "add.wasm"
puts inst.exports.add(1, 2)

Output:

3

Code (with import_object):

loader = WebAssembly::WASMLoader.new
mod = loader.load "logger.wasm"

import_object = {
  :console => {
    :log => lambda {|msg| puts msg}
  }
}
inst = mod.instantiate import_object
inst.exports.logIt()
Shortcut:
import_object = {
  :console => {
    :log => lambda {|msg| puts msg}
  }
}
inst = WebAssembly::instantiate "logger.wasm", imprt_object
inst.exports.logIt()

Output:

13

Serialize Module into WASM

serializer = WebAssembly::WASMSerializer.new
bytes = serializer.serialize mod
File.binwrite "add.wasm", bytes.pack("C*")
Shortcut:
WebAssembly::serialize mod, "add.wasm"

Construct Module with Code

Code:

type_section = WebAssembly::TypeSection.new
type_section.add_functype WebAssembly::FuncType.new([:i32, :i32], [:i32])

function_section = WebAssembly::FunctionSection.new
function_section.add_type_index 0

export = WebAssembly::Export.new
export.name = "add"
export.desc = WebAssembly::FuncIndex.new 0
export_section = WebAssembly::ExportSection.new
export_section.add_export export

code = WebAssembly::Code.new
code.add_expression WebAssembly::LocalGetInstruction.new(0)
code.add_expression WebAssembly::LocalGetInstruction.new(1)
code.add_expression WebAssembly::I32AddInstruction.new
code_section = WebAssembly::CodeSection.new
code_section.add_code code

mod = WebAssembly::Module.new [type_section, function_section, export_section, code_section]

inst = mod.instantiate
puts inst.exports.add(1, 2)
DSL (experimental)

simple-dsl.rb

wasm =  mod {
          func :f1, [:i32, :i32] => [:i32] {
            i32.add arg(0), arg(1)
          }

          export "add", :f1
        }

inst = wasm.instantiate
puts inst.exports.add(1, 2)

Output:

3

Sample Codes

Global

global = WebAssembly::Context::Global.new 0
mod = loader.load "js-api-examples/global.wasm"
inst = mod.instantiate :js => {
  :global => global
}
puts inst.exports.getGlobal() # 0
global.value = 42
puts inst.exports.getGlobal() # 42
inst.exports.incGlobal()
puts inst.exports.getGlobal() # 43

Memory

mod = loader.load "js-api-examples/memory.wasm"
inst = mod.instantiate :js => {
  :mem => (0..9).to_a.pack("i*").unpack("C*")
}
puts inst.exports.accumulate(0, 10) # 45
mod = loader.load "understanding-text-format/logger2.wasm"
mem = []
inst = mod.instantiate(
  :console => {
    :log => lambda {|offset, length|
      bytes = mem[offset...(offset+length)]
      puts bytes.pack("U*")
    }
  },
  :js => {
    :mem => mem
  }
)
inst.exports.writeHi() # Hi

Table

mod = loader.load "js-api-examples/table.wasm"
inst = mod.instantiate
puts inst.exports.tbl[0].call # 13
puts inst.exports.tbl[1].call # 42
tbl = []
mod = loader.load "js-api-examples/table2.wasm"
inst = mod.instantiate :js => {
  :tbl => tbl
}
puts tbl[0].call # 42
puts tbl[1].call # 83
mod = loader.load "understanding-text-format/wasm-table.wasm"
inst = mod.instantiate
puts inst.exports.callByIndex(0) # 42
puts inst.exports.callByIndex(1) # 13
begin
  puts inst.exports.callByIndex(2) # error
rescue => e
  puts e
end

Shared

import_object = {
  :js => {
    :memory => [],
    :table => []
  }
}
mod0 = loader.load "understanding-text-format/shared0.wasm"
inst0 = mod0.instantiate import_object
mod1 = loader.load "understanding-text-format/shared1.wasm"
inst1 = mod1.instantiate import_object
puts inst1.exports.doIt() # 42

Refs.

About

WebAssembly Tools for Ruby language

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published