wardite 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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