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 +4 -4
- data/Steepfile +1 -0
- data/exe/wardite +11 -5
- data/lib/wardite/instruction.rb +7 -9
- data/lib/wardite/load.rb +14 -9
- data/lib/wardite/revisitor.rb +1 -1
- data/lib/wardite/value.rb +6 -22
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi/consts.rb +129 -0
- data/lib/wardite/wasi.rb +268 -7
- data/lib/wardite/wasm_module.rb +53 -0
- data/lib/wardite.rb +68 -40
- data/misc/proposals/rubykaigi2025.md +46 -0
- data/misc/slides/fib.c +4 -0
- data/misc/slides/fib.html +13 -0
- data/misc/slides/image-1.png +0 -0
- data/misc/slides/image-2.png +0 -0
- data/misc/slides/image.png +0 -0
- data/misc/slides/tokyo12.html +614 -0
- data/misc/slides/tokyo12.md +624 -0
- data/sig/fcntl.rbs +7 -0
- data/sig/generated/wardite/load.rbs +2 -2
- data/sig/generated/wardite/value.rbs +3 -10
- data/sig/generated/wardite/wasi/consts.rbs +137 -0
- data/sig/generated/wardite/wasi.rbs +62 -5
- data/sig/generated/wardite/wasm_module.rbs +42 -0
- data/sig/generated/wardite.rbs +24 -9
- metadata +15 -3
- data/examples/add.wasm +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbf27d475ac9dac6a9c0f6284bf379858dfef4ee52f3a2d609f41e0a87110b46
|
4
|
+
data.tar.gz: 69d508dc6674117a0c94e8308b357e49a05952f17ac949470c53e8a3267442c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d1b5d0ed4b626ab9c34fd0aabedca56b48afa4e9629557e0fcc8d0c7a2e05ad57d674d630c4f4b1599ec1babf70082d2a21041890f6081d4fbe18b8e57c0789
|
7
|
+
data.tar.gz: ae55bd53d03c27a6626e320223389655adcfb67033d99bf9715171eb9bb90c718fab3eacefb2e8d9dd367f7c6d5c986f2bc956741da261d821ce102362b0898e
|
data/Steepfile
CHANGED
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
|
12
|
-
|
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
|
data/lib/wardite/instruction.rb
CHANGED
@@ -46,16 +46,15 @@ module Wardite
|
|
46
46
|
|
47
47
|
# @rbs @@table: Hash[Integer, Symbol] | nil
|
48
48
|
@@table = nil
|
49
|
-
# @rbs @@
|
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 = {}
|
56
|
-
|
57
|
-
|
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 = {}
|
67
|
-
|
68
|
-
|
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,
|
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
|
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
|
data/lib/wardite/revisitor.rb
CHANGED
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
|
-
|
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
|
data/lib/wardite/version.rb
CHANGED
@@ -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
|
-
|
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
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|