wardite 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 13e64d51eb1befe294c1ffe57e53b85cbeac7015c989e9fa88d7e3528f55c6df
4
+ data.tar.gz: ae6a11d049b3970b6f8f8f87a7fd07f1c69a367afe706296413797075c9b4c12
5
+ SHA512:
6
+ metadata.gz: 8696f7f48858528a7b8d5ba524cdeada76ffde6fad9cd9009b8e1246ab51f0be5c6b0de511d4af29eef17a211d24602977fabe4bed31f63df925368317f664c6
7
+ data.tar.gz: 8d4e5e7b2931c2e04176099ad27b6d8bb65937cdada6abaaf7827674f83800373461344c4d8c9971e8f43b65abcf785466c88034331026c96d2139b8258b85d0
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Wardite
2
+
3
+ A pure-ruby webassembly runtime.
4
+
5
+ ## Installation
6
+
7
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
16
+
17
+ ## Usage
18
+
19
+ TODO: Write usage instructions here
20
+
21
+ ## Development
22
+
23
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test-unit` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
24
+
25
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
26
+
27
+ ## Contributing
28
+
29
+ Bug reports and pull requests are welcome on GitHub at https://github.com/udzura/wardite.
30
+
31
+ ## See also
32
+
33
+ - https://github.com/technohippy/wasmrb?tab=readme-ov-file
34
+ - Referencial implementation but no support with WASI
35
+ - Wardite aims to support full WASI (previwe 1)
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ desc "Run rbs-inline and steep"
13
+ task :check do
14
+ sh "bundle exec rbs-inline --output lib/"
15
+ sh "bundle exec steep check"
16
+ end
17
+
18
+ task default: %i[test check]
19
+
data/Steepfile ADDED
@@ -0,0 +1,37 @@
1
+ # -*- mode: ruby -*-
2
+ target :lib do
3
+ signature "sig"
4
+ check "lib"
5
+
6
+ # configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
7
+ end
8
+
9
+ # D = Steep::Diagnostic
10
+ #
11
+ # target :lib do
12
+ # signature "sig"
13
+ #
14
+ # check "lib" # Directory name
15
+ # check "Gemfile" # File name
16
+ # check "app/models/**/*.rb" # Glob
17
+ # # ignore "lib/templates/*.rb"
18
+ #
19
+ # # library "pathname" # Standard libraries
20
+ # # library "strong_json" # Gems
21
+ #
22
+ # # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
23
+ # # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
24
+ # # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
25
+ # # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
26
+ # # configure_code_diagnostics do |hash| # You can setup everything yourself
27
+ # # hash[D::Ruby::NoMethod] = :information
28
+ # # end
29
+ # end
30
+
31
+ # target :test do
32
+ # signature "sig", "sig-private"
33
+ #
34
+ # check "test"
35
+ #
36
+ # # library "pathname" # Standard libraries
37
+ # end
@@ -0,0 +1 @@
1
+ *.wasm
data/examples/add.wasm ADDED
Binary file
data/examples/add.wat ADDED
@@ -0,0 +1,7 @@
1
+ (module
2
+ (func (export "add") (param $a i32) (param $b i32) (result i32)
3
+ (local.get $a)
4
+ (local.get $b)
5
+ i32.add
6
+ )
7
+ )
data/examples/call.wat ADDED
@@ -0,0 +1,11 @@
1
+ (module
2
+ (func (export "call_doubler") (param i32) (result i32)
3
+ (local.get 0)
4
+ (call $double)
5
+ )
6
+ (func $double (param i32) (result i32)
7
+ (local.get 0)
8
+ (local.get 0)
9
+ i32.add
10
+ )
11
+ )
@@ -0,0 +1,24 @@
1
+ (module
2
+ (import "wasi_snapshot_preview1" "fd_write"
3
+ (func $fd_write (param i32 i32 i32 i32) (result i32))
4
+ )
5
+ (memory 1)
6
+ (data (i32.const 0) "Hello, World!\n")
7
+
8
+ (func $helloworld (result i32)
9
+ (local $iovs i32)
10
+
11
+ (i32.store (i32.const 16) (i32.const 0))
12
+ (i32.store (i32.const 20) (i32.const 14))
13
+
14
+ (local.set $iovs (i32.const 16))
15
+
16
+ (call $fd_write
17
+ (i32.const 1)
18
+ (local.get $iovs)
19
+ (i32.const 1)
20
+ (i32.const 24)
21
+ )
22
+ )
23
+ (export "_start" (func $helloworld))
24
+ )
@@ -0,0 +1,6 @@
1
+ (module
2
+ (func $i32_const (result i32)
3
+ (i32.const 42)
4
+ )
5
+ (export "i32_const" (func $i32_const))
6
+ )
@@ -0,0 +1,9 @@
1
+ (module
2
+ (memory 1)
3
+ (func $i32_store
4
+ (i32.const 0)
5
+ (i32.const 42)
6
+ (i32.store)
7
+ )
8
+ (export "i32_store" (func $i32_store))
9
+ )
@@ -0,0 +1,8 @@
1
+ (module
2
+ (func $local_set (result i32)
3
+ (local $x i32)
4
+ (local.set $x (i32.const 42))
5
+ (local.get 0)
6
+ )
7
+ (export "local_set" (func $local_set))
8
+ )
@@ -0,0 +1,5 @@
1
+ (module
2
+ (memory 1)
3
+ (data (i32.const 0) "hello")
4
+ (data (i32.const 5) "world")
5
+ )
data/exe/wardite ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "wardite"
4
+
5
+ path = ARGV[0]
6
+ method = ARGV[1]
7
+ args = ARGV[2..-1] || []
8
+
9
+ f = File.open(path)
10
+ instance = Wardite::BinaryLoader::load_from_buffer(f);
11
+ if !method && instance.runtime.respond_to?(:_start)
12
+ instance.runtime._start
13
+ else
14
+ instance.runtime.call(method, args)
15
+ end
@@ -0,0 +1,20 @@
1
+ # rbs_inline: enabled
2
+ module Wardite
3
+ module Const
4
+ # Section Code
5
+ # @see https://www.w3.org/TR/wasm-core-1/#sections%E2%91%A0
6
+ SectionCustom = 0x0 #: Integer
7
+ SectionType = 0x1 #: Integer
8
+ SectionImport = 0x2 #: Integer
9
+ SectionFunction = 0x3 #: Integer
10
+ SectionTable = 0x4 #: Integer
11
+ SectionMemory = 0x5 #: Integer
12
+ SectionGlobal = 0x6 #: Integer
13
+ SectionExport = 0x7 #: Integer
14
+ SectionStart = 0x8 #: Integer
15
+ SectionElement = 0x9 #: Integer
16
+ SectionCode = 0xa #: Integer
17
+ SectionData = 0xb #: Integer
18
+ end
19
+ include Const
20
+ end
@@ -0,0 +1,71 @@
1
+ # rbs_inline: enabled
2
+ module Wardite
3
+ class Op
4
+ attr_accessor :code #: Symbol
5
+
6
+ attr_accessor :operand #: Array[Object]
7
+
8
+ # @rbs code: Symbol
9
+ # @rbs operand: Array[Object]
10
+ def initialize(code, operand)
11
+ @code = code
12
+ @operand = operand
13
+ end
14
+
15
+ # @rbs chr: String
16
+ # @rbs return: Symbol
17
+ def self.to_sym(chr)
18
+ case chr
19
+ when "\u000b"
20
+ :end
21
+ when "\u0010"
22
+ :call
23
+ when "\u0020"
24
+ :local_get
25
+ when "\u0021"
26
+ :local_set
27
+ when "\u0036"
28
+ :i32_store
29
+ when "\u0041"
30
+ :i32_const
31
+ when "\u006a"
32
+ :i32_add
33
+ else
34
+ raise NotImplementedError, "unimplemented: #{chr.inspect}"
35
+ end
36
+ end
37
+
38
+ # @rbs chr: Symbol
39
+ # @rbs return: Array[Symbol]
40
+ def self.operand_of(code)
41
+ case code
42
+ when :local_get, :local_set, :call
43
+ [:u32]
44
+ when :i32_const
45
+ [:i32]
46
+ when :i32_store
47
+ [:u32, :u32]
48
+ else
49
+ []
50
+ end
51
+ end
52
+
53
+ # @see https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
54
+ # @rbs code: Integer
55
+ # @rbs return: Symbol
56
+ def self.i2type(code)
57
+ case code
58
+ when 0x7f
59
+ :i32
60
+ when 0x7e
61
+ :i64
62
+ when 0x7d
63
+ :f32
64
+ when 0x7c
65
+ :f64
66
+ else
67
+ raise "unknown type code #{code}"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,58 @@
1
+ # rbs_inline: enabled
2
+ module Wardite
3
+ module Leb128Helpers
4
+ # @rbs buf: File|StringIO
5
+ # @rbs return: Integer
6
+ def fetch_uleb128(buf)
7
+ dest = 0
8
+ level = 0
9
+ while b = buf.read(1)
10
+ if b == nil
11
+ raise LoadError, "buffer too short"
12
+ end
13
+ c = b.ord
14
+
15
+ upper, lower = (c >> 7), (c & (1 << 7) - 1)
16
+ dest |= lower << (7 * level)
17
+ if upper == 0
18
+ return dest
19
+ end
20
+
21
+ if level > 6
22
+ break
23
+ end
24
+ level += 1
25
+ end
26
+ # unreachable but...
27
+ raise "unreachable! debug: dest = #{dest} level = #{level}"
28
+ end
29
+
30
+ # @rbs buf: File|StringIO
31
+ # @rbs return: Integer
32
+ def fetch_sleb128(buf)
33
+ dest = 0
34
+ level = 0
35
+ while b = buf.read(1)
36
+ if b == nil
37
+ raise LoadError, "buffer too short"
38
+ end
39
+ c = b.ord
40
+
41
+ upper, lower = (c >> 7), (c & (1 << 7) - 1)
42
+ dest |= lower << (7 * level)
43
+ if upper == 0
44
+ break
45
+ end
46
+
47
+ if level > 6
48
+ raise "unreachable! debug: dest = #{dest} level = #{level}"
49
+ end
50
+ level += 1
51
+ end
52
+ shift = 7 * (level + 1) - 1
53
+ return dest | -(dest & (1 << shift))
54
+ end
55
+
56
+ module_function :fetch_uleb128, :fetch_sleb128
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Wardite
5
+ VERSION = "0.1.0" #: String
6
+ end
@@ -0,0 +1,67 @@
1
+ # rbs_inline: enabled
2
+ module Wardite
3
+ class WasiSnapshotPreview1
4
+ attr_accessor :fd_table #: Array[IO]
5
+
6
+ def initialize
7
+ @fd_table = [
8
+ STDIN,
9
+ STDOUT,
10
+ STDERR,
11
+ ]
12
+ end
13
+
14
+ # @rbs store: Store
15
+ # @rbs args: Array[Object]
16
+ # @rbs return: Object
17
+ def fd_write(store, args)
18
+ iargs = args.map do |elm|
19
+ if elm.is_a?(Integer)
20
+ elm
21
+ else
22
+ raise Wardite::ArgumentError, "invalid type of args: #{args.inspect}"
23
+ end
24
+ end #: Array[Integer]
25
+ fd, iovs, iovs_len, rp = *iargs
26
+ if !fd || !iovs || !iovs_len || !rp
27
+ raise Wardite::ArgumentError, "args too short"
28
+ end
29
+ file = self.fd_table[fd]
30
+ memory = store.memories[0]
31
+ nwritten = 0
32
+ iovs_len.times do
33
+ start = unpack_le_int(memory.data[iovs...(iovs+4)])
34
+ iovs += 4
35
+ slen = unpack_le_int(memory.data[iovs...(iovs+4)])
36
+ iovs += 4
37
+ nwritten += file.write(memory.data[start...(start+slen)])
38
+ end
39
+
40
+ memory.data[rp...(rp+4)] = [nwritten].pack("I")
41
+
42
+ 0
43
+ end
44
+
45
+
46
+ # @rbs return: Hash[Symbol, Proc]
47
+ def to_module
48
+ {
49
+ fd_write: lambda{|store, args| self.fd_write(store, args) },
50
+ }
51
+ end
52
+
53
+ private
54
+ # @rbs buf: String|nil
55
+ # @rbs return: Integer
56
+ def unpack_le_int(buf)
57
+ if !buf
58
+ raise "empty buffer"
59
+ end
60
+ ret = buf.unpack1("I")
61
+ if !ret.is_a?(Integer)
62
+ raise "[BUG] invalid pack format"
63
+ end
64
+ ret
65
+ end
66
+ end
67
+ end