wardite 0.5.1 → 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: 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