wardite 0.5.1 → 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: 89b6c42e1a3f16c39c214eb127c5b87966c0d2933257a1da7fdc96236c6a0f9b
4
- data.tar.gz: 321d62cdddc61c8a342b966b3e4d7b6c01ffbbcb5788a6787fd3490ba96b1430
3
+ metadata.gz: bbf27d475ac9dac6a9c0f6284bf379858dfef4ee52f3a2d609f41e0a87110b46
4
+ data.tar.gz: 69d508dc6674117a0c94e8308b357e49a05952f17ac949470c53e8a3267442c2
5
5
  SHA512:
6
- metadata.gz: 4b8b67989d47775828aca0908794f6b02abdea5ed653d794fa308d437f2d1735997a91dee341cdfa51aa5829aa097ca61dd262dba8479e805d1bbfd540f90ff5
7
- data.tar.gz: 26face977ed4d76232bdee62f64208a22ec824314cb3d479979705fee327a1c9ce72ee960055a0c26db591f932c598b591651170fedf31b36533c52774f05fbe
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
 
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
data/lib/wardite/load.rb CHANGED
@@ -250,7 +250,7 @@ module Wardite
250
250
  # @rbs self.@buf: File|StringIO
251
251
 
252
252
  # @rbs buf: File|StringIO
253
- # @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
253
+ # @rbs import_object: Hash[Symbol, wasmModuleSrc]
254
254
  # @rbs enable_wasi: boolish
255
255
  # @rbs return: Instance
256
256
  def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
@@ -259,14 +259,19 @@ module Wardite
259
259
  version = preamble
260
260
  sections_ = sections
261
261
 
262
+ wasi_env = nil
262
263
  if enable_wasi
264
+ require "wardite/wasi"
263
265
  wasi_env = Wardite::WasiSnapshotPreview1.new
264
- import_object[:wasi_snapshot_preview1] = wasi_env.to_module
266
+ import_object[:wasi_snapshot_preview1] = wasi_env
265
267
  end
266
268
 
267
269
  return Instance.new(import_object) do |i|
268
270
  i.version = version
269
271
  i.sections = sections_
272
+ if enable_wasi
273
+ i.wasi = wasi_env
274
+ end
270
275
  end
271
276
  end
272
277
 
@@ -358,7 +363,7 @@ module Wardite
358
363
  end
359
364
 
360
365
  arglen = fetch_uleb128(sbuf)
361
- arg = []
366
+ arg = [] #: Array[Symbol]
362
367
  arglen.times do
363
368
  case ty = assert_read(sbuf, 1)&.ord
364
369
  when 0x7f
@@ -376,7 +381,7 @@ module Wardite
376
381
  dest.defined_types << arg
377
382
 
378
383
  retlen = fetch_uleb128(sbuf)
379
- ret = []
384
+ ret = [] #: Array[Symbol]
380
385
  retlen.times do
381
386
  case ty = assert_read(sbuf, 1)&.ord
382
387
  when 0x7f
@@ -482,7 +487,7 @@ module Wardite
482
487
  offset = decode_expr(ops)
483
488
  dest.table_offsets << offset
484
489
 
485
- elms = []
490
+ elms = [] #: Array[Integer]
486
491
  elen = fetch_uleb128(sbuf)
487
492
  elen.times do |i|
488
493
  index = fetch_uleb128(sbuf)
@@ -585,8 +590,8 @@ module Wardite
585
590
  $stderr.puts "warning: instruction not ended with inst end(0x0b): 0x0#{last_code.ord}"
586
591
  end
587
592
  cbuf = StringIO.new(code)
588
- locals_count = []
589
- locals_type = []
593
+ locals_count = [] #: Array[Integer]
594
+ locals_type = [] #: Array[Symbol]
590
595
  locals_len = fetch_uleb128(cbuf)
591
596
  locals_len.times do
592
597
  type_count = fetch_uleb128(cbuf)
@@ -610,7 +615,7 @@ module Wardite
610
615
  # @rbs buf: StringIO
611
616
  # @rbs return: Array[::Wardite::Op]
612
617
  def self.code_body(buf)
613
- dest = []
618
+ dest = [] #: Array[Op]
614
619
  while c = buf.read(1)
615
620
  namespace, code = resolve_code(c, buf)
616
621
  operand_types = Op.operand_of(code)
@@ -855,7 +860,7 @@ module Wardite
855
860
  # @rbs code: Integer
856
861
  # @rbs return: nil
857
862
  def self.unimplemented_skip_section(code)
858
- $stderr.puts "warning: unimplemented section: 0x0#{code}"
863
+ $stderr.puts "warning: unimplemented section: 0x0#{code}" if ENV['WARN_UNIMPLEMENTED_SECTION']
859
864
  size = fetch_uleb128(@buf)
860
865
  @buf.read(size)
861
866
  nil
@@ -42,7 +42,7 @@ module Wardite
42
42
  case inst&.code
43
43
  when nil
44
44
  raise EvalError, "end op not found"
45
- when :if
45
+ when :if, :block, :loop
46
46
  depth += 1
47
47
  when :else
48
48
  if depth == 0
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.1" #: 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
data/lib/wardite/wasi.rb CHANGED
@@ -1,16 +1,161 @@
1
1
  # rbs_inline: enabled
2
+
3
+ require "wardite/wasm_module"
4
+ require "wardite/wasi/consts"
5
+ require "securerandom"
6
+ require "fcntl"
7
+
2
8
  module Wardite
3
9
  class WasiSnapshotPreview1
4
10
  include ValueHelper
11
+ include WasmModule
5
12
 
6
- attr_accessor :fd_table #: Array[IO]
13
+ attr_accessor :fd_table #: Array[(IO|File)]
14
+ attr_accessor :argv #: Array[String]
7
15
 
8
- def initialize
16
+ # @rbs argv: Array[String]
17
+ # @rbs return: void
18
+ def initialize(argv: [])
9
19
  @fd_table = [
10
20
  STDIN,
11
21
  STDOUT,
12
22
  STDERR,
13
23
  ]
24
+ @argv = argv
25
+ end
26
+
27
+ # @rbs store: Store
28
+ # @rbs args: Array[wasmValue]
29
+ # @rbs return: Object
30
+ def args_get(store, args)
31
+ arg_offsets_p = args[0].value
32
+ arg_data_buf_p = args[1].value
33
+ if !arg_data_buf_p.is_a?(Integer)
34
+ raise ArgumentError, "invalid type of args: #{args.inspect}"
35
+ end
36
+
37
+ arg_offsets = [] #: Array[Integer]
38
+ arg_data_slice = [] #: Array[String]
39
+ current_offset = arg_data_buf_p
40
+ @argv.each do |arg|
41
+ arg_offsets << current_offset
42
+ arg_data_slice << arg
43
+ current_offset += arg.size + 1
44
+ end
45
+ arg_data = arg_data_slice.join("\0") + "\0"
46
+
47
+ memory = store.memories[0]
48
+ memory.data[arg_data_buf_p...(arg_data_buf_p + arg_data.size)] = arg_data
49
+
50
+ arg_offsets.each_with_index do |offset, i|
51
+ data_begin = arg_offsets_p + i * 4
52
+ memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
53
+ end
54
+
55
+ 0
56
+ end
57
+
58
+ # @rbs store: Store
59
+ # @rbs args: Array[wasmValue]
60
+ # @rbs return: Object
61
+ def args_sizes_get(store, args)
62
+ argc_p = args[0].value
63
+ arglen_p = args[1].value
64
+ argc = @argv.length
65
+ arglen = @argv.map{|arg| arg.size + 1}.sum
66
+
67
+ memory = store.memories[0]
68
+ memory.data[argc_p...(argc_p+4)] = [argc].pack("I!")
69
+ memory.data[arglen_p...(arglen_p+4)] = [arglen].pack("I!")
70
+ 0
71
+ end
72
+
73
+ # @rbs store: Store
74
+ # @rbs args: Array[wasmValue]
75
+ # @rbs return: Object
76
+ def environ_sizes_get(store, args)
77
+ envc_p = args[0].value
78
+ envlen_p = args[1].value
79
+ envc = ENV.length
80
+ envlen = ENV.map{|k,v| k.size + v.size + 1}.sum
81
+
82
+ memory = store.memories[0]
83
+ memory.data[envc_p...(envc_p+4)] = [envc].pack("I!")
84
+ memory.data[envlen_p...(envlen_p+4)] = [envlen].pack("I!")
85
+ 0
86
+ end
87
+
88
+ # @rbs store: Store
89
+ # @rbs args: Array[wasmValue]
90
+ # @rbs return: Object
91
+ def environ_get(store, args)
92
+ environ_offsets_p = args[0].value
93
+ environ_data_buf_p = args[1].value
94
+ if !environ_data_buf_p.is_a?(Integer)
95
+ raise ArgumentError, "invalid type of args: #{args.inspect}"
96
+ end
97
+
98
+ environ_offsets = [] #: Array[Integer]
99
+ environ_data_slice = [] #: Array[String]
100
+ current_offset = environ_data_buf_p
101
+ ENV.each do |k, v|
102
+ environ_offsets << current_offset
103
+ environ_data_slice << "#{k}=#{v}"
104
+ current_offset += "#{k}=#{v}".size + 1
105
+ end
106
+ environ_data = environ_data_slice.join("\0") + "\0"
107
+
108
+ memory = store.memories[0]
109
+ memory.data[environ_data_buf_p...(environ_data_buf_p + environ_data.size)] = environ_data
110
+
111
+ environ_offsets.each_with_index do |offset, i|
112
+ data_begin = environ_offsets_p + i * 4
113
+ memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
114
+ end
115
+
116
+ 0
117
+ end
118
+
119
+ # @rbs store: Store
120
+ # @rbs args: Array[wasmValue]
121
+ # @rbs return: Object
122
+ def clock_time_get(store, args)
123
+ clock_id = args[0].value
124
+ # we dont use precision...
125
+ _precision = args[1].value
126
+ timebuf64 = args[2].value
127
+ if clock_id != 0 # - CLOCKID_REALTIME
128
+ # raise NotImplementedError, "CLOCKID_REALTIME is an only supported id"
129
+ return -255
130
+ end
131
+ # timestamp in nanoseconds
132
+ now = Time.now.to_i * 1_000_000
133
+
134
+ memory = store.memories[0]
135
+ now_packed = [now].pack("Q!")
136
+ memory.data[timebuf64...(timebuf64+8)] = now_packed
137
+ 0
138
+ end
139
+
140
+ # @rbs store: Store
141
+ # @rbs args: Array[wasmValue]
142
+ # @rbs return: Object
143
+ def fd_prestat_get(store, args)
144
+ fd = args[0].value.to_i
145
+ prestat_offset = args[1].value.to_i
146
+ if fd >= @fd_table.size
147
+ return Wasi::EBADF
148
+ end
149
+ file = @fd_table[fd]
150
+ if !file.is_a?(File)
151
+ return Wasi::EBADF
152
+ end
153
+ name = file.path
154
+ memory = store.memories[0]
155
+ # Zero-value 8-bit tag, and 3-byte zero-value padding
156
+ memory.data[prestat_offset...(prestat_offset+4)] = [0].pack("I!")
157
+ memory.data[(prestat_offset+4)...(prestat_offset+8)] = [name.size].pack("I!")
158
+ 0
14
159
  end
15
160
 
16
161
  # @rbs store: Store
@@ -29,6 +174,7 @@ module Wardite
29
174
  raise Wardite::ArgumentError, "args too short"
30
175
  end
31
176
  file = self.fd_table[fd]
177
+ return Wasi::EBADF if !file
32
178
  memory = store.memories[0]
33
179
  nwritten = 0
34
180
  iovs_len.times do
@@ -45,11 +191,126 @@ module Wardite
45
191
  0
46
192
  end
47
193
 
48
- # @rbs return: Hash[Symbol, wasmCallable]
49
- def to_module
50
- {
51
- fd_write: lambda{|store, args| self.fd_write(store, args) },
52
- }
194
+ # @rbs store: Store
195
+ # @rbs args: Array[wasmValue]
196
+ # @rbs return: Object
197
+ def fd_read(store, args)
198
+ iargs = args.map do |elm|
199
+ if elm.is_a?(I32)
200
+ elm.value
201
+ else
202
+ raise Wardite::ArgumentError, "invalid type of args: #{args.inspect}"
203
+ end
204
+ end #: Array[Integer]
205
+ fd, iovs, iovs_len, rp = *iargs
206
+ if !fd || !iovs || !iovs_len || !rp
207
+ raise Wardite::ArgumentError, "args too short"
208
+ end
209
+ file = self.fd_table[fd]
210
+ return Wasi::EBADF if !file
211
+ memory = store.memories[0]
212
+ nread = 0
213
+
214
+ iovs_len.times do
215
+ start = unpack_le_int(memory.data[iovs...(iovs+4)])
216
+ iovs += 4
217
+ slen = unpack_le_int(memory.data[iovs...(iovs+4)])
218
+ iovs += 4
219
+ buf = file.read(slen)
220
+ if !buf
221
+ return Wasi::EFAULT
222
+ end
223
+ memory.data[start...(start+slen)] = buf
224
+ nread += slen
225
+ end
226
+
227
+ memory.data[rp...(rp+4)] = [nread].pack("I!")
228
+ 0
229
+ end
230
+
231
+ # @rbs store: Store
232
+ # @rbs args: Array[wasmValue]
233
+ # @rbs return: Object
234
+ def fd_fdstat_get(store, args)
235
+ fd = args[0].value.to_i
236
+ fdstat_offset = args[1].value.to_i
237
+ if fd >= @fd_table.size
238
+ return Wasi::EBADF
239
+ end
240
+ file = @fd_table[fd]
241
+ fdflags = 0
242
+ if file.is_a?(IO)
243
+ fdflags |= Wasi::FD_APPEND
244
+ else
245
+ if (Fcntl::O_APPEND & file.fcntl(Fcntl::F_GETFL, 0)) != 0
246
+ fdflags |= Wasi::FD_APPEND
247
+ end
248
+ end
249
+
250
+ if (Fcntl::O_NONBLOCK & file.fcntl(Fcntl::F_GETFL, 0)) != 0
251
+ fdflags |= Wasi::FD_NONBLOCK
252
+ end
253
+
254
+ stat = file.stat #: File::Stat
255
+ ftype = Wasi.to_ftype(stat.ftype)
256
+
257
+ fs_right_base = 0
258
+ fs_right_inheriting = 0
259
+
260
+ case ftype
261
+ when Wasi::FILETYPE_DIRECTORY
262
+ fs_right_base = Wasi::RIGHT_DIR_RIGHT_BASE
263
+ fs_right_inheriting = Wasi::RIGHT_FILE_RIGHT_BASE | Wasi::RIGHT_DIR_RIGHT_BASE
264
+ when Wasi::FILETYPE_CHARACTER_DEVICE
265
+ fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE & \
266
+ (~Wasi::RIGHT_FD_SEEK) & (~Wasi::RIGHT_FD_TELL)
267
+ else
268
+ fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE
269
+ end
270
+
271
+ memory = store.memories[0]
272
+
273
+ binformat = [fdflags, ftype, 0, 0, 0, 0, fs_right_base, fs_right_inheriting]
274
+ .pack("SSC4QQ")
275
+ memory.data[fdstat_offset...(fdstat_offset+binformat.size)] = binformat
276
+ 0
277
+ end
278
+
279
+ # @rbs store: Store
280
+ # @rbs args: Array[wasmValue]
281
+ # @rbs return: Object
282
+ def fd_filestat_get(store, args)
283
+ fd = args[0].value.to_i
284
+ filestat_offset = args[1].value.to_i
285
+ if fd >= @fd_table.size
286
+ return Wasi::EBADF
287
+ end
288
+ file = @fd_table[fd]
289
+ stat = file.stat #: File::Stat
290
+ memory = store.memories[0]
291
+ binformat = [stat.dev, stat.ino, Wasi.to_ftype(stat.ftype), stat.nlink, stat.size, stat.atime.to_i, stat.mtime.to_i, stat.ctime.to_i].pack("Q8")
292
+ memory.data[filestat_offset...(filestat_offset+binformat.size)] = binformat
293
+ 0
294
+ end
295
+
296
+ # @rbs store: Store
297
+ # @rbs args: Array[wasmValue]
298
+ # @rbs return: Object
299
+ def proc_exit(store, args)
300
+ exit_code = args[0].value
301
+ exit(exit_code)
302
+ end
303
+
304
+ # @rbs store: Store
305
+ # @rbs args: Array[wasmValue]
306
+ # @rbs return: Object
307
+ def random_get(store, args)
308
+ buf = args[0].value.to_i
309
+ buflen = args[1].value.to_i
310
+ randoms = SecureRandom.random_bytes(buflen) #: String
311
+ memory = store.memories[0]
312
+ memory.data[buf...(buf+buflen)] = randoms
313
+ 0
53
314
  end
54
315
 
55
316
  private