wardite 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3ca81e45a3da7f90566d465d5248bcac03981953e97c81681de900851348407
4
- data.tar.gz: 2b0952f92a92bce4d54283868fd2565b9dbaa178cc1187b2a7f6feca6225fe57
3
+ metadata.gz: bbf27d475ac9dac6a9c0f6284bf379858dfef4ee52f3a2d609f41e0a87110b46
4
+ data.tar.gz: 69d508dc6674117a0c94e8308b357e49a05952f17ac949470c53e8a3267442c2
5
5
  SHA512:
6
- metadata.gz: 8a4db779ed117465fb2c981c0b9da39dcdd001e60abf00262d04353449b5b72ad433949d6c640458fe2b61b503e84180dbf3c7709d791b48f7ed2a5ad9dbe372
7
- data.tar.gz: 7d00f04205f6ef10b21dee7067adf1f480a529cea4bf0caa404fd888547f101f3908f54863262333e2b363d2d17b28b4899ff12ddc5e226958eda975354fd954
6
+ metadata.gz: 9d1b5d0ed4b626ab9c34fd0aabedca56b48afa4e9629557e0fcc8d0c7a2e05ad57d674d630c4f4b1599ec1babf70082d2a21041890f6081d4fbe18b8e57c0789
7
+ data.tar.gz: ae55bd53d03c27a6626e320223389655adcfb67033d99bf9715171eb9bb90c718fab3eacefb2e8d9dd367f7c6d5c986f2bc956741da261d821ce102362b0898e
data/Steepfile CHANGED
@@ -4,6 +4,7 @@ target :lib do
4
4
  check "lib"
5
5
 
6
6
  library "pp"
7
+ library "securerandom"
7
8
  # configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
8
9
  end
9
10
 
@@ -0,0 +1,64 @@
1
+ #
2
+ # Usage:
3
+ # $ bundle exec ruby --yjit examples/grayscale.rb \
4
+ # --wasm-file path/to/grayscale.wasm \
5
+ # --source tmp/source.png \
6
+ # --dest tmp/result.png \
7
+ # --width 660 --height 495
8
+ #
9
+ require "wardite"
10
+ require "base64"
11
+ require "optparse"
12
+ require "ostruct"
13
+
14
+ $options = OpenStruct.new
15
+
16
+ opt = OptionParser.new
17
+ opt.on('--wasm-file [FILE]') {|v| $options.wasm_file = v }
18
+ opt.on('--source [IMAGE]') {|v| $options.source = v }
19
+ opt.on('--dest [IMAGE]') {|v| $options.dest = v }
20
+ opt.on('--width [W]') {|v| $options.width = v.to_i }
21
+ opt.on('--height [H]') {|v| $options.height = v.to_i }
22
+ opt.parse!
23
+
24
+ #require 'ruby-prof'
25
+ #profile = RubyProf::Profile.new
26
+
27
+ f = File.open($options.wasm_file)
28
+ data = IO.read($options.source)
29
+ orig = Base64.encode64(data).gsub(/(\r|\n)/, "")
30
+ data_url = "data:image/png;base64," + orig
31
+ instance = Wardite::BinaryLoader::load_from_buffer(f);
32
+ instance.store.memories[0].grow(data_url.size / (64*1024) + 1)
33
+
34
+ start = instance.exports.__heap_base.value.value
35
+ instance.store.memories[0].data[start...(start+data_url.size)] = data_url
36
+
37
+ offset = 0
38
+ result = nil
39
+ begin
40
+ # pub fn grayscale(width: i32, height: i32, memory_offset: i32, length: i32) -> *const u8
41
+ #profile.start
42
+ offset = instance.runtime.grayscale_blob($options.width, $options.height, start, data_url.size)
43
+ #result = profile.stop
44
+ rescue => e
45
+ raise "failed to execute grayscale() " + e.message
46
+ end
47
+
48
+ #printer = RubyProf::GraphPrinter.new(result)
49
+ #printer.print(STDOUT, {})
50
+
51
+ len = 0
52
+ until instance.store.memories[0].data[offset.value+len] == "\0"
53
+ len += 1
54
+ end
55
+
56
+ result_b64 = instance.store.memories[0].data[offset.value...(offset.value+len)]
57
+ result = Base64.decode64(result_b64)
58
+
59
+ dest = File.open($options.dest, "w")
60
+ dest.write result
61
+ dest.close
62
+
63
+ puts "created: #{$options.dest}"
64
+
data/exe/wardite CHANGED
@@ -1,16 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "wardite"
4
-
5
4
  path = ARGV[0]
6
- method = ARGV[1]
7
- args = ARGV[2..-1] || []
8
5
 
9
6
  f = File.open(path)
10
7
  instance = Wardite::BinaryLoader::load_from_buffer(f);
11
- if !method && instance.runtime.respond_to?(:_start)
12
- instance.runtime._start
8
+ if instance.runtime.respond_to?(:_start) # assumed WASI
9
+ argv = ARGV[1..-1] || []
10
+ instance.wasi.argv = ["wardite"] + argv
11
+ Bundler.with_original_env do
12
+ # instance.store.memories[0].grow(128)
13
+ instance.runtime._start
14
+ end
13
15
  else
16
+ path = ARGV[0]
17
+ method = ARGV[1]
18
+ args = ARGV[2..-1] || []
19
+
14
20
  args = args.map do|a|
15
21
  if a.include? "."
16
22
  a.to_f
@@ -46,16 +46,15 @@ module Wardite
46
46
 
47
47
  # @rbs @@table: Hash[Integer, Symbol] | nil
48
48
  @@table = nil
49
- # @rbs @@table: Hash[Integer, Symbol] | nil
49
+ # @rbs @@fc_table: Hash[Integer, Symbol] | nil
50
50
  @@fc_table = nil
51
51
 
52
52
  # @rbs return: Hash[Integer, Symbol]
53
53
  def self.table
54
54
  return @@table if @@table != nil
55
- @@table = {}.tap do |ha|
56
- SYMS.each_with_index do |sym, i|
57
- ha[i] = sym
58
- end
55
+ @@table = {} #: Hash[Integer, Symbol] | nil
56
+ SYMS.each_with_index do |sym, i|
57
+ @@table[i] = sym
59
58
  end
60
59
  @@table
61
60
  end
@@ -63,10 +62,9 @@ module Wardite
63
62
  # @rbs return: Hash[Integer, Symbol]
64
63
  def self.fc_table
65
64
  return @@fc_table if @@fc_table != nil
66
- @@fc_table = {}.tap do |ha|
67
- FC_SYMS.each_with_index do |sym, i|
68
- ha[i] = sym
69
- end
65
+ @@fc_table = {} #: Hash[Integer, Symbol] | nil
66
+ FC_SYMS.each_with_index do |sym, i|
67
+ @@fc_table[i] = sym
70
68
  end
71
69
  @@fc_table
72
70
  end
@@ -78,6 +76,8 @@ module Wardite
78
76
  # TODO: add types of potential operands
79
77
  attr_accessor :operand #: Array[operandItem]
80
78
 
79
+ attr_accessor :meta #: Hash[Symbol, Integer]
80
+
81
81
  # @rbs namespace: Symbol
82
82
  # @rbs code: Symbol
83
83
  # @rbs operand: Array[operandItem]
@@ -85,6 +85,7 @@ module Wardite
85
85
  @namespace = namespace
86
86
  @code = code
87
87
  @operand = operand
88
+ @meta = {}
88
89
  end
89
90
 
90
91
  # @rbs chr: String
data/lib/wardite/load.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # rbs_inline: enabled
2
+ require "wardite/revisitor"
3
+
2
4
  module Wardite
3
5
  class Section
4
6
  attr_accessor :name #: String
@@ -248,7 +250,7 @@ module Wardite
248
250
  # @rbs self.@buf: File|StringIO
249
251
 
250
252
  # @rbs buf: File|StringIO
251
- # @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
253
+ # @rbs import_object: Hash[Symbol, wasmModuleSrc]
252
254
  # @rbs enable_wasi: boolish
253
255
  # @rbs return: Instance
254
256
  def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
@@ -257,14 +259,19 @@ module Wardite
257
259
  version = preamble
258
260
  sections_ = sections
259
261
 
262
+ wasi_env = nil
260
263
  if enable_wasi
264
+ require "wardite/wasi"
261
265
  wasi_env = Wardite::WasiSnapshotPreview1.new
262
- import_object[:wasi_snapshot_preview1] = wasi_env.to_module
266
+ import_object[:wasi_snapshot_preview1] = wasi_env
263
267
  end
264
268
 
265
269
  return Instance.new(import_object) do |i|
266
270
  i.version = version
267
271
  i.sections = sections_
272
+ if enable_wasi
273
+ i.wasi = wasi_env
274
+ end
268
275
  end
269
276
  end
270
277
 
@@ -356,7 +363,7 @@ module Wardite
356
363
  end
357
364
 
358
365
  arglen = fetch_uleb128(sbuf)
359
- arg = []
366
+ arg = [] #: Array[Symbol]
360
367
  arglen.times do
361
368
  case ty = assert_read(sbuf, 1)&.ord
362
369
  when 0x7f
@@ -374,7 +381,7 @@ module Wardite
374
381
  dest.defined_types << arg
375
382
 
376
383
  retlen = fetch_uleb128(sbuf)
377
- ret = []
384
+ ret = [] #: Array[Symbol]
378
385
  retlen.times do
379
386
  case ty = assert_read(sbuf, 1)&.ord
380
387
  when 0x7f
@@ -480,7 +487,7 @@ module Wardite
480
487
  offset = decode_expr(ops)
481
488
  dest.table_offsets << offset
482
489
 
483
- elms = []
490
+ elms = [] #: Array[Integer]
484
491
  elen = fetch_uleb128(sbuf)
485
492
  elen.times do |i|
486
493
  index = fetch_uleb128(sbuf)
@@ -583,8 +590,8 @@ module Wardite
583
590
  $stderr.puts "warning: instruction not ended with inst end(0x0b): 0x0#{last_code.ord}"
584
591
  end
585
592
  cbuf = StringIO.new(code)
586
- locals_count = []
587
- locals_type = []
593
+ locals_count = [] #: Array[Integer]
594
+ locals_type = [] #: Array[Symbol]
588
595
  locals_len = fetch_uleb128(cbuf)
589
596
  locals_len.times do
590
597
  type_count = fetch_uleb128(cbuf)
@@ -593,10 +600,13 @@ module Wardite
593
600
  locals_type << Op.i2type(value_type || -1)
594
601
  end
595
602
  body = code_body(cbuf)
603
+ revisitor = Revisitor.new(body)
604
+ revisitor.revisit!
605
+
596
606
  dest.func_codes << CodeSection::CodeBody.new do |b|
597
607
  b.locals_count = locals_count
598
608
  b.locals_type = locals_type
599
- b.body = body
609
+ b.body = revisitor.ops
600
610
  end
601
611
  end
602
612
  dest
@@ -605,7 +615,7 @@ module Wardite
605
615
  # @rbs buf: StringIO
606
616
  # @rbs return: Array[::Wardite::Op]
607
617
  def self.code_body(buf)
608
- dest = []
618
+ dest = [] #: Array[Op]
609
619
  while c = buf.read(1)
610
620
  namespace, code = resolve_code(c, buf)
611
621
  operand_types = Op.operand_of(code)
@@ -850,7 +860,7 @@ module Wardite
850
860
  # @rbs code: Integer
851
861
  # @rbs return: nil
852
862
  def self.unimplemented_skip_section(code)
853
- $stderr.puts "warning: unimplemented section: 0x0#{code}"
863
+ $stderr.puts "warning: unimplemented section: 0x0#{code}" if ENV['WARN_UNIMPLEMENTED_SECTION']
854
864
  size = fetch_uleb128(@buf)
855
865
  @buf.read(size)
856
866
  nil
@@ -0,0 +1,92 @@
1
+ # rbs_inline: enabled
2
+ module Wardite
3
+ class Revisitor
4
+ attr_accessor :ops #: Array[Op]
5
+
6
+ # @rbs ops: Array[Op]
7
+ # @rbs return: void
8
+ def initialize(ops)
9
+ @ops = ops
10
+ end
11
+
12
+ # @rbs return: void
13
+ def revisit!
14
+ @ops.each_with_index do |op, idx|
15
+ case op.code
16
+ when :block
17
+ next_pc = fetch_ops_while_end(idx)
18
+ op.meta[:end_pos] = next_pc
19
+
20
+ when :loop
21
+ next_pc = fetch_ops_while_end(idx)
22
+ op.meta[:end_pos] = next_pc
23
+
24
+ when :if
25
+ next_pc = fetch_ops_while_end(idx)
26
+ else_pc = fetch_ops_while_else_or_end(idx)
27
+ op.meta[:end_pos] = next_pc
28
+ op.meta[:else_pos] = else_pc
29
+ end
30
+ end
31
+ end
32
+
33
+ # @rbs pc_start: Integer
34
+ # @rbs return: Integer
35
+ # @rbs return: void
36
+ def fetch_ops_while_else_or_end(pc_start)
37
+ cursor = pc_start
38
+ depth = 0
39
+ loop {
40
+ cursor += 1
41
+ inst = @ops[cursor]
42
+ case inst&.code
43
+ when nil
44
+ raise EvalError, "end op not found"
45
+ when :if, :block, :loop
46
+ depth += 1
47
+ when :else
48
+ if depth == 0
49
+ return cursor
50
+ end
51
+ # do not touch depth
52
+ when :end
53
+ if depth == 0
54
+ return cursor
55
+ else
56
+ depth -= 1
57
+ end
58
+ else
59
+ # nop
60
+ end
61
+ }
62
+ raise "not found corresponding end"
63
+ end
64
+
65
+ # @rbs pc_start: Integer
66
+ # @rbs return: Integer
67
+ # @rbs return: void
68
+ def fetch_ops_while_end(pc_start)
69
+ cursor = pc_start
70
+ depth = 0
71
+ loop {
72
+ cursor += 1
73
+ inst = @ops[cursor]
74
+ case inst&.code
75
+ when nil
76
+ raise EvalError, "end op not found"
77
+ when :if, :block, :loop
78
+ depth += 1
79
+ when :end
80
+ if depth == 0
81
+ return cursor
82
+ else
83
+ depth -= 1
84
+ end
85
+ else
86
+ # nop
87
+ end
88
+ }
89
+ raise "not found corresponding end"
90
+ end
91
+ end
92
+ end
data/lib/wardite/value.rb CHANGED
@@ -8,20 +8,12 @@ module Wardite
8
8
  # @rbs value: Integer
9
9
  # @rbs return: I32
10
10
  def I32(value)
11
- if value < 0
12
- # $stderr.puts "trace: negative i32 value #{value} is passed, convert to unsigned"
13
- value = as_u32(value)
14
- end
15
- I32.new.tap{|i| i.value = value & I32::I32_MAX }
11
+ I32.new(value & I32::I32_MAX)
16
12
  end
17
13
 
18
14
  # @rbs value: Integer
19
15
  # @rbs return: I64
20
16
  def I64(value)
21
- if value < 0
22
- # $stderr.puts "trace: negative i64 value #{value} is passed, convert to unsigned"
23
- value = as_u64(value)
24
- end
25
17
  I64.new.tap{|i| i.value = value & I64::I64_MAX }
26
18
  end
27
19
 
@@ -36,19 +28,6 @@ module Wardite
36
28
  def F64(value)
37
29
  F64.new.tap{|i| i.value = value }
38
30
  end
39
-
40
- private
41
- # @rbs value: Integer
42
- # @rbs return: Integer
43
- def as_u32(value)
44
- ((-value) ^ I32::I32_MAX) + 1
45
- end
46
-
47
- # @rbs value: Integer
48
- # @rbs return: Integer
49
- def as_u64(value)
50
- ((-value) ^ I64::I64_MAX) + 1
51
- end
52
31
  end
53
32
 
54
33
  extend ValueHelper
@@ -61,6 +40,11 @@ module Wardite
61
40
  # when we want to access signed value, it'd be done via #value_s
62
41
  attr_accessor :value #: Integer
63
42
 
43
+ # @rbs value: Integer
44
+ def initialize(value=0)
45
+ @value = value
46
+ end
47
+
64
48
  # @rbs str: String
65
49
  # @rbs size: Integer|nil
66
50
  # @rbs signed: bool
@@ -2,5 +2,5 @@
2
2
  # rbs_inline: enabled
3
3
 
4
4
  module Wardite
5
- VERSION = "0.5.0" #: String
5
+ VERSION = "0.6.0" #: String
6
6
  end
@@ -0,0 +1,129 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Wardite
4
+ module Wasi
5
+ EACCES = 2
6
+ EAGAIN = 6
7
+ EBADF = 8
8
+ EEXIST = 20
9
+ EFAULT = 21
10
+ EINTR = 27
11
+ EINVAL = 28
12
+ EIO = 29
13
+ EISDIR = 31
14
+ ELOOP = 32
15
+ ENAMETOOLONG = 37
16
+ ENOENT = 44
17
+ ENOSYS = 52
18
+ ENOTDIR = 54
19
+ ERANGE = 68
20
+ ENOTEMPTY = 55
21
+ ENOTSOCK = 57
22
+ ENOTSUP = 58
23
+ EPERM = 63
24
+ EROFS = 69
25
+
26
+ FILETYPE_UNKNOWN = 0
27
+ FILETYPE_BLOCK_DEVICE = 1 #: Integer
28
+ FILETYPE_CHARACTER_DEVICE = 2 #: Integer
29
+ FILETYPE_DIRECTORY = 3 #: Integer
30
+ FILETYPE_REGULAR_FILE = 4 #: Integer
31
+ FILETYPE_SOCKET_DGRAM = 5 #: Integer
32
+ FILETYPE_SOCKET_STREAM = 6 #: Integer
33
+ FILETYPE_SYMBOLIC_LINK = 7 #: Integer
34
+
35
+ FD_APPEND = 1 << 0 #: Integer
36
+ FD_DSYNC = 1 << 1 #: Integer
37
+ FD_NONBLOCK = 1 << 2 #: Integer
38
+ FD_RSYNC = 1 << 3 #: Integer
39
+ FD_SYNC = 1 << 4 #: Integer
40
+
41
+ RIGHT_FD_DATASYNC = 1 << 0
42
+ RIGHT_FD_READ = 1 << 1
43
+ RIGHT_FD_SEEK = 1 << 2
44
+ RIGHT_FDSTAT_SET_FLAGS = 1 << 3
45
+ RIGHT_FD_SYNC = 1 << 4
46
+ RIGHT_FD_TELL = 1 << 5
47
+ RIGHT_FD_WRITE = 1 << 6
48
+ RIGHT_FD_ADVISE = 1 << 7
49
+ RIGHT_FD_ALLOCATE = 1 << 8
50
+ RIGHT_PATH_CREATE_DIRECTORY = 1 << 9
51
+ RIGHT_PATH_CREATE_FILE = 1 << 10
52
+ RIGHT_PATH_LINK_SOURCE = 1 << 11
53
+ RIGHT_PATH_LINK_TARGET = 1 << 12
54
+ RIGHT_PATH_OPEN = 1 << 13
55
+ RIGHT_FD_READDIR = 1 << 14
56
+ RIGHT_PATH_READLINK = 1 << 15
57
+ RIGHT_PATH_RENAME_SOURCE = 1 << 16
58
+ RIGHT_PATH_RENAME_TARGET = 1 << 17
59
+ RIGHT_PATH_FILESTAT_GET = 1 << 18
60
+ RIGHT_PATH_FILESTAT_SET_SIZE = 1 << 19
61
+ RIGHT_PATH_FILESTAT_SET_TIMES = 1 << 20
62
+ RIGHT_FD_FILESTAT_GET = 1 << 21
63
+ RIGHT_FD_FILESTAT_SET_SIZE = 1 << 22
64
+ RIGHT_FD_FILESTAT_SET_TIMES = 1 << 23
65
+ RIGHT_PATH_SYMLINK = 1 << 24
66
+ RIGHT_PATH_REMOVE_DIRECTORY = 1 << 25
67
+ RIGHT_PATH_UNLINK_FILE = 1 << 26
68
+ RIGHT_POLL_FD_READWRITE = 1 << 27
69
+ RIGHT_SOCK_SHUTDOWN = 1 << 28
70
+
71
+ RIGHT_FILE_RIGHT_BASE = RIGHT_FD_DATASYNC |
72
+ RIGHT_FD_READ |
73
+ RIGHT_FD_SEEK |
74
+ RIGHT_FDSTAT_SET_FLAGS |
75
+ RIGHT_FD_SYNC |
76
+ RIGHT_FD_TELL |
77
+ RIGHT_FD_WRITE |
78
+ RIGHT_FD_ADVISE |
79
+ RIGHT_FD_ALLOCATE |
80
+ RIGHT_FD_FILESTAT_GET |
81
+ RIGHT_FD_FILESTAT_SET_SIZE |
82
+ RIGHT_FD_FILESTAT_SET_TIMES |
83
+ RIGHT_POLL_FD_READWRITE
84
+
85
+ RIGHT_DIR_RIGHT_BASE = RIGHT_FD_DATASYNC |
86
+ RIGHT_FDSTAT_SET_FLAGS |
87
+ RIGHT_FD_SYNC |
88
+ RIGHT_PATH_CREATE_DIRECTORY |
89
+ RIGHT_PATH_CREATE_FILE |
90
+ RIGHT_PATH_LINK_SOURCE |
91
+ RIGHT_PATH_LINK_TARGET |
92
+ RIGHT_PATH_OPEN |
93
+ RIGHT_FD_READDIR |
94
+ RIGHT_PATH_READLINK |
95
+ RIGHT_PATH_RENAME_SOURCE |
96
+ RIGHT_PATH_RENAME_TARGET |
97
+ RIGHT_PATH_FILESTAT_GET |
98
+ RIGHT_PATH_FILESTAT_SET_SIZE |
99
+ RIGHT_PATH_FILESTAT_SET_TIMES |
100
+ RIGHT_FD_FILESTAT_GET |
101
+ RIGHT_FD_FILESTAT_SET_TIMES |
102
+ RIGHT_PATH_SYMLINK |
103
+ RIGHT_PATH_REMOVE_DIRECTORY |
104
+ RIGHT_PATH_UNLINK_FILE
105
+
106
+ # @rbs mode_str: String
107
+ # @rbs return: Integer
108
+ def self.to_ftype(mode_str)
109
+ case mode_str
110
+ when "file"
111
+ FILETYPE_REGULAR_FILE
112
+ when "directory"
113
+ FILETYPE_DIRECTORY
114
+ when "characterSpecial"
115
+ FILETYPE_CHARACTER_DEVICE
116
+ when "blockSpecial"
117
+ FILETYPE_BLOCK_DEVICE
118
+ when "fifo"
119
+ FILETYPE_UNKNOWN
120
+ when "link"
121
+ FILETYPE_SYMBOLIC_LINK
122
+ when "socket"
123
+ FILETYPE_SOCKET_STREAM # TODO: check UDP
124
+ else
125
+ FILETYPE_UNKNOWN
126
+ end
127
+ end
128
+ end
129
+ end