wardite 0.2.1 → 0.2.2
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 +4 -4
- data/examples/global.wat +13 -0
- data/lib/wardite/instruction.rb +1 -1
- data/lib/wardite/load.rb +679 -0
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite.rb +79 -591
- data/sig/generated/wardite/instruction.rbs +2 -2
- data/sig/generated/wardite/load.rbs +198 -0
- data/sig/generated/wardite.rbs +24 -165
- metadata +5 -2
data/lib/wardite.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative "wardite/leb128"
|
|
6
6
|
require_relative "wardite/const"
|
7
7
|
require_relative "wardite/instruction"
|
8
8
|
require_relative "wardite/value"
|
9
|
+
require_relative "wardite/load"
|
9
10
|
|
10
11
|
module Wardite
|
11
12
|
module Evaluator
|
@@ -23,596 +24,6 @@ require_relative "wardite/wasi"
|
|
23
24
|
require "stringio"
|
24
25
|
|
25
26
|
module Wardite
|
26
|
-
class Section
|
27
|
-
attr_accessor :name #: String
|
28
|
-
|
29
|
-
attr_accessor :code #: Integer
|
30
|
-
|
31
|
-
attr_accessor :size #: Integer
|
32
|
-
end
|
33
|
-
|
34
|
-
class TypeSection < Section
|
35
|
-
attr_accessor :defined_types #: Array[Array[Symbol]]
|
36
|
-
|
37
|
-
attr_accessor :defined_results #: Array[Array[Symbol]]
|
38
|
-
|
39
|
-
# @rbs return: void
|
40
|
-
def initialize
|
41
|
-
self.name = "Type"
|
42
|
-
self.code = 0x1
|
43
|
-
|
44
|
-
@defined_types = []
|
45
|
-
@defined_results = []
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class FunctionSection < Section
|
50
|
-
attr_accessor :func_indices #: Array[Integer]
|
51
|
-
|
52
|
-
# @rbs return: void
|
53
|
-
def initialize
|
54
|
-
self.name = "Function"
|
55
|
-
self.code = 0x3
|
56
|
-
|
57
|
-
@func_indices = []
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class MemorySection < Section
|
62
|
-
attr_accessor :limits #: Array[[Integer, Integer|nil]]
|
63
|
-
|
64
|
-
# @rbs return: void
|
65
|
-
def initialize
|
66
|
-
self.name = "Memory"
|
67
|
-
self.code = 0x5
|
68
|
-
|
69
|
-
@limits = []
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class CodeSection < Section
|
74
|
-
class CodeBody
|
75
|
-
attr_accessor :locals_count #: Array[Integer]
|
76
|
-
|
77
|
-
attr_accessor :locals_type #: Array[Symbol]
|
78
|
-
|
79
|
-
attr_accessor :body #: Array[Op]
|
80
|
-
|
81
|
-
# @rbs &blk: (CodeBody) -> void
|
82
|
-
# @rbs return: void
|
83
|
-
def initialize(&blk)
|
84
|
-
blk.call(self)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
attr_accessor :func_codes #:Array[CodeBody]
|
89
|
-
|
90
|
-
# @rbs return: void
|
91
|
-
def initialize
|
92
|
-
self.name = "Code"
|
93
|
-
self.code = 0xa
|
94
|
-
|
95
|
-
@func_codes = []
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class DataSection < Section
|
100
|
-
class Segment
|
101
|
-
attr_accessor :flags #: Integer
|
102
|
-
|
103
|
-
attr_accessor :offset #: Integer
|
104
|
-
|
105
|
-
attr_accessor :data #: String
|
106
|
-
|
107
|
-
# @rbs &blk: (Segment) -> void
|
108
|
-
# @rbs return: void
|
109
|
-
def initialize(&blk)
|
110
|
-
blk.call(self)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
attr_accessor :segments #: Array[Segment]
|
115
|
-
|
116
|
-
# @rbs return: void
|
117
|
-
def initialize
|
118
|
-
self.name = "Data"
|
119
|
-
self.code = 0xb
|
120
|
-
|
121
|
-
@segments = []
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class ExportSection < Section
|
126
|
-
class ExportDesc
|
127
|
-
attr_accessor :name #: String
|
128
|
-
|
129
|
-
attr_accessor :kind #: Integer
|
130
|
-
|
131
|
-
attr_accessor :func_index #: Integer
|
132
|
-
end
|
133
|
-
|
134
|
-
attr_accessor :exports #: Hash[String, ExportDesc]
|
135
|
-
|
136
|
-
def initialize #: void
|
137
|
-
self.name = "Export"
|
138
|
-
self.code = 0x7
|
139
|
-
|
140
|
-
@exports = {}
|
141
|
-
end
|
142
|
-
|
143
|
-
# @rbs &blk: (ExportDesc) -> void
|
144
|
-
def add_desc(&blk)
|
145
|
-
desc = ExportDesc.new
|
146
|
-
blk.call(desc)
|
147
|
-
self.exports[desc.name] = desc
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
class ImportSection < Section
|
152
|
-
class ImportDesc
|
153
|
-
attr_accessor :module_name #: String
|
154
|
-
|
155
|
-
attr_accessor :name #: String
|
156
|
-
|
157
|
-
attr_accessor :kind #: Integer
|
158
|
-
|
159
|
-
attr_accessor :sig_index #: Integer
|
160
|
-
end
|
161
|
-
|
162
|
-
attr_accessor :imports #: Array[ImportDesc]
|
163
|
-
|
164
|
-
def initialize #: void
|
165
|
-
self.name = "Import"
|
166
|
-
self.code = 0x2
|
167
|
-
|
168
|
-
@imports = []
|
169
|
-
end
|
170
|
-
|
171
|
-
# @rbs &blk: (ImportDesc) -> void
|
172
|
-
def add_desc(&blk)
|
173
|
-
desc = ImportDesc.new
|
174
|
-
blk.call(desc) if blk
|
175
|
-
self.imports << desc
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
module BinaryLoader
|
180
|
-
extend Wardite::Leb128Helper
|
181
|
-
extend Wardite::ValueHelper
|
182
|
-
|
183
|
-
# @rbs buf: File|StringIO
|
184
|
-
# @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
|
185
|
-
# @rbs enable_wasi: boolish
|
186
|
-
# @rbs return: Instance
|
187
|
-
def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
|
188
|
-
@buf = buf
|
189
|
-
|
190
|
-
version = preamble
|
191
|
-
sections_ = sections
|
192
|
-
|
193
|
-
if enable_wasi
|
194
|
-
wasi_env = Wardite::WasiSnapshotPreview1.new
|
195
|
-
import_object[:wasi_snapshot_preview1] = wasi_env.to_module
|
196
|
-
end
|
197
|
-
|
198
|
-
return Instance.new(import_object) do |i|
|
199
|
-
i.version = version
|
200
|
-
i.sections = sections_
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# @rbs return: Integer
|
205
|
-
def self.preamble
|
206
|
-
asm = @buf.read 4
|
207
|
-
if !asm
|
208
|
-
raise LoadError, "buffer too short"
|
209
|
-
end
|
210
|
-
if asm != "\u0000asm"
|
211
|
-
raise LoadError, "invalid preamble"
|
212
|
-
end
|
213
|
-
|
214
|
-
vstr = @buf.read(4)
|
215
|
-
if !vstr
|
216
|
-
raise LoadError, "buffer too short"
|
217
|
-
end
|
218
|
-
version = vstr.to_enum(:chars)
|
219
|
-
.with_index
|
220
|
-
.inject(0) {|dest, (c, i)| dest | (c.ord << i*8) }
|
221
|
-
if version != 1
|
222
|
-
raise LoadError, "unsupported version: #{version}"
|
223
|
-
end
|
224
|
-
version
|
225
|
-
end
|
226
|
-
|
227
|
-
# @rbs return: Array[Section]
|
228
|
-
def self.sections
|
229
|
-
sections = [] #: Array[Section]
|
230
|
-
|
231
|
-
loop do
|
232
|
-
byte = @buf.read(1)
|
233
|
-
if !byte
|
234
|
-
break
|
235
|
-
end
|
236
|
-
code = byte.ord
|
237
|
-
|
238
|
-
section = case code
|
239
|
-
when Wardite::SectionType
|
240
|
-
type_section
|
241
|
-
when Wardite::SectionImport
|
242
|
-
import_section
|
243
|
-
when Wardite::SectionFunction
|
244
|
-
function_section
|
245
|
-
when Wardite::SectionTable
|
246
|
-
unimplemented_skip_section(code)
|
247
|
-
when Wardite::SectionMemory
|
248
|
-
memory_section
|
249
|
-
when Wardite::SectionGlobal
|
250
|
-
unimplemented_skip_section(code)
|
251
|
-
when Wardite::SectionExport
|
252
|
-
export_section
|
253
|
-
when Wardite::SectionStart
|
254
|
-
unimplemented_skip_section(code)
|
255
|
-
when Wardite::SectionElement
|
256
|
-
unimplemented_skip_section(code)
|
257
|
-
when Wardite::SectionCode
|
258
|
-
code_section
|
259
|
-
when Wardite::SectionData
|
260
|
-
data_section
|
261
|
-
when Wardite::SectionCustom
|
262
|
-
unimplemented_skip_section(code)
|
263
|
-
else
|
264
|
-
raise LoadError, "unknown code: #{code}(\"#{code.to_s 16}\")"
|
265
|
-
end
|
266
|
-
|
267
|
-
if section
|
268
|
-
sections << section
|
269
|
-
end
|
270
|
-
end
|
271
|
-
sections
|
272
|
-
end
|
273
|
-
|
274
|
-
# @rbs return: TypeSection
|
275
|
-
def self.type_section
|
276
|
-
dest = TypeSection.new
|
277
|
-
|
278
|
-
size = fetch_uleb128(@buf)
|
279
|
-
dest.size = size
|
280
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
281
|
-
|
282
|
-
len = fetch_uleb128(sbuf)
|
283
|
-
len.times do |i|
|
284
|
-
fncode = assert_read(sbuf, 1)
|
285
|
-
if fncode != "\x60"
|
286
|
-
raise LoadError, "not a function definition"
|
287
|
-
end
|
288
|
-
|
289
|
-
arglen = fetch_uleb128(sbuf)
|
290
|
-
arg = []
|
291
|
-
arglen.times do
|
292
|
-
case ty = assert_read(sbuf, 1)&.ord
|
293
|
-
when 0x7f
|
294
|
-
arg << :i32
|
295
|
-
when 0x7e
|
296
|
-
arg << :i64
|
297
|
-
when 0x7d
|
298
|
-
arg << :f32
|
299
|
-
when 0x7c
|
300
|
-
arg << :f64
|
301
|
-
else
|
302
|
-
raise NotImplementedError, "unsupported for now: #{ty.inspect}"
|
303
|
-
end
|
304
|
-
end
|
305
|
-
dest.defined_types << arg
|
306
|
-
|
307
|
-
retlen = fetch_uleb128(sbuf)
|
308
|
-
ret = []
|
309
|
-
retlen.times do
|
310
|
-
case ty = assert_read(sbuf, 1)&.ord
|
311
|
-
when 0x7f
|
312
|
-
ret << :i32
|
313
|
-
when 0x7e
|
314
|
-
ret << :i64
|
315
|
-
when 0x7d
|
316
|
-
ret << :f32
|
317
|
-
when 0x7c
|
318
|
-
ret << :f64
|
319
|
-
else
|
320
|
-
raise NotImplementedError, "unsupported for now: #{ty.inspect}"
|
321
|
-
end
|
322
|
-
end
|
323
|
-
dest.defined_results << ret
|
324
|
-
end
|
325
|
-
|
326
|
-
dest
|
327
|
-
end
|
328
|
-
|
329
|
-
# @rbs return: ImportSection
|
330
|
-
def self.import_section
|
331
|
-
dest = ImportSection.new
|
332
|
-
size = fetch_uleb128(@buf)
|
333
|
-
dest.size = size
|
334
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
335
|
-
|
336
|
-
len = fetch_uleb128(sbuf)
|
337
|
-
len.times do |i|
|
338
|
-
mlen = fetch_uleb128(sbuf)
|
339
|
-
module_name = assert_read(sbuf, mlen)
|
340
|
-
nlen = fetch_uleb128(sbuf)
|
341
|
-
name = assert_read(sbuf, nlen)
|
342
|
-
kind_ = assert_read(sbuf, 1)
|
343
|
-
kind = kind_[0]&.ord
|
344
|
-
if !kind
|
345
|
-
raise "[BUG] empty unpacked string" # guard rbs
|
346
|
-
end
|
347
|
-
|
348
|
-
index = fetch_uleb128(sbuf)
|
349
|
-
dest.add_desc do |desc|
|
350
|
-
desc.module_name = module_name
|
351
|
-
desc.name = name
|
352
|
-
desc.kind = kind
|
353
|
-
desc.sig_index = index
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
dest
|
358
|
-
end
|
359
|
-
|
360
|
-
# @rbs return: MemorySection
|
361
|
-
def self.memory_section
|
362
|
-
dest = MemorySection.new
|
363
|
-
size = fetch_uleb128(@buf)
|
364
|
-
dest.size = size
|
365
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
366
|
-
|
367
|
-
len = fetch_uleb128(sbuf)
|
368
|
-
if len != 1
|
369
|
-
raise LoadError, "memory section has invalid size: #{len}"
|
370
|
-
end
|
371
|
-
len.times do |i|
|
372
|
-
flags = fetch_uleb128(sbuf)
|
373
|
-
min = fetch_uleb128(sbuf)
|
374
|
-
|
375
|
-
max = nil
|
376
|
-
if flags != 0
|
377
|
-
max = fetch_uleb128(sbuf)
|
378
|
-
end
|
379
|
-
dest.limits << [min, max]
|
380
|
-
end
|
381
|
-
dest
|
382
|
-
end
|
383
|
-
|
384
|
-
# @rbs return: FunctionSection
|
385
|
-
def self.function_section
|
386
|
-
dest = FunctionSection.new
|
387
|
-
size = fetch_uleb128(@buf)
|
388
|
-
dest.size = size
|
389
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
390
|
-
|
391
|
-
len = fetch_uleb128(sbuf)
|
392
|
-
len.times do |i|
|
393
|
-
index = fetch_uleb128(sbuf)
|
394
|
-
dest.func_indices << index
|
395
|
-
end
|
396
|
-
dest
|
397
|
-
end
|
398
|
-
|
399
|
-
# @rbs return: CodeSection
|
400
|
-
def self.code_section
|
401
|
-
dest = CodeSection.new
|
402
|
-
size = fetch_uleb128(@buf)
|
403
|
-
dest.size = size
|
404
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
405
|
-
|
406
|
-
len = fetch_uleb128(sbuf)
|
407
|
-
len.times do |i|
|
408
|
-
ilen = fetch_uleb128(sbuf)
|
409
|
-
code = assert_read(sbuf, ilen)
|
410
|
-
last_code = code[-1]
|
411
|
-
if ! last_code
|
412
|
-
raise "[BUG] empty code fetched" # guard for steep check
|
413
|
-
end
|
414
|
-
if last_code.ord != 0x0b
|
415
|
-
$stderr.puts "warning: instruction not ended with inst end(0x0b): 0x0#{last_code.ord}"
|
416
|
-
end
|
417
|
-
cbuf = StringIO.new(code)
|
418
|
-
locals_count = []
|
419
|
-
locals_type = []
|
420
|
-
locals_len = fetch_uleb128(cbuf)
|
421
|
-
locals_len.times do
|
422
|
-
type_count = fetch_uleb128(cbuf)
|
423
|
-
locals_count << type_count
|
424
|
-
value_type = assert_read(cbuf, 1)&.ord
|
425
|
-
locals_type << Op.i2type(value_type || -1)
|
426
|
-
end
|
427
|
-
body = code_body(cbuf)
|
428
|
-
dest.func_codes << CodeSection::CodeBody.new do |b|
|
429
|
-
b.locals_count = locals_count
|
430
|
-
b.locals_type = locals_type
|
431
|
-
b.body = body
|
432
|
-
end
|
433
|
-
end
|
434
|
-
dest
|
435
|
-
end
|
436
|
-
|
437
|
-
# @rbs buf: StringIO
|
438
|
-
# @rbs return: Array[::Wardite::Op]
|
439
|
-
def self.code_body(buf)
|
440
|
-
dest = []
|
441
|
-
while c = buf.read(1)
|
442
|
-
namespace, code = Op.to_sym(c)
|
443
|
-
operand_types = Op.operand_of(code)
|
444
|
-
operand = [] #: Array[Integer|Float|Block]
|
445
|
-
operand_types.each do |typ|
|
446
|
-
case typ
|
447
|
-
when :u8
|
448
|
-
ope = buf.read 1
|
449
|
-
if ! ope
|
450
|
-
raise LoadError, "buffer too short"
|
451
|
-
end
|
452
|
-
operand << ope.ord
|
453
|
-
when :u32
|
454
|
-
operand << fetch_uleb128(buf)
|
455
|
-
when :i32
|
456
|
-
operand << fetch_sleb128(buf)
|
457
|
-
when :i64
|
458
|
-
operand << fetch_sleb128(buf)
|
459
|
-
when :f32
|
460
|
-
data = buf.read 4
|
461
|
-
if !data || data.size != 4
|
462
|
-
raise LoadError, "buffer too short"
|
463
|
-
end
|
464
|
-
v = data.unpack("e")[0]
|
465
|
-
raise "String#unpack is broken" if !v.is_a?(Float)
|
466
|
-
operand << v
|
467
|
-
when :f64
|
468
|
-
data = buf.read 8
|
469
|
-
if !data || data.size != 8
|
470
|
-
raise LoadError, "buffer too short"
|
471
|
-
end
|
472
|
-
v = data.unpack("E")[0]
|
473
|
-
raise "String#unpack is broken" if !v.is_a?(Float)
|
474
|
-
operand << v
|
475
|
-
when :u8_if_block # :if specific
|
476
|
-
block_ope = buf.read 1
|
477
|
-
if ! block_ope
|
478
|
-
raise LoadError, "buffer too short for if"
|
479
|
-
end
|
480
|
-
if block_ope.ord == 0x40
|
481
|
-
operand << Block.void
|
482
|
-
else
|
483
|
-
operand << Block.new([block_ope.ord])
|
484
|
-
end
|
485
|
-
else
|
486
|
-
$stderr.puts "warning: unknown type #{typ.inspect}. defaulting to u32"
|
487
|
-
operand << fetch_uleb128(buf)
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
dest << Op.new(namespace, code, operand)
|
492
|
-
end
|
493
|
-
|
494
|
-
dest
|
495
|
-
end
|
496
|
-
|
497
|
-
# @rbs return: DataSection
|
498
|
-
def self.data_section
|
499
|
-
dest = DataSection.new
|
500
|
-
size = fetch_uleb128(@buf)
|
501
|
-
dest.size = size
|
502
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
503
|
-
|
504
|
-
len = fetch_uleb128(sbuf)
|
505
|
-
len.times do |i|
|
506
|
-
mem_index = fetch_uleb128(sbuf)
|
507
|
-
code = fetch_insn_while_end(sbuf)
|
508
|
-
ops = code_body(StringIO.new(code))
|
509
|
-
offset = decode_expr(ops)
|
510
|
-
|
511
|
-
len = fetch_uleb128(sbuf)
|
512
|
-
data = sbuf.read len
|
513
|
-
if !data
|
514
|
-
raise LoadError, "buffer too short"
|
515
|
-
end
|
516
|
-
|
517
|
-
segment = DataSection::Segment.new do |seg|
|
518
|
-
seg.flags = mem_index
|
519
|
-
seg.offset = offset
|
520
|
-
seg.data = data
|
521
|
-
end
|
522
|
-
dest.segments << segment
|
523
|
-
end
|
524
|
-
dest
|
525
|
-
end
|
526
|
-
|
527
|
-
# @rbs sbuf: StringIO
|
528
|
-
# @rbs return: String
|
529
|
-
def self.fetch_insn_while_end(sbuf)
|
530
|
-
code = String.new("")
|
531
|
-
loop {
|
532
|
-
c = sbuf.read 1
|
533
|
-
if !c
|
534
|
-
break
|
535
|
-
end
|
536
|
-
code << c
|
537
|
-
if c == "\u000b" # :end
|
538
|
-
break
|
539
|
-
end
|
540
|
-
}
|
541
|
-
code
|
542
|
-
end
|
543
|
-
|
544
|
-
# @rbs ops: Array[Op]
|
545
|
-
# @rbs return: Integer
|
546
|
-
def self.decode_expr(ops)
|
547
|
-
# sees first opcode
|
548
|
-
op = ops.first
|
549
|
-
if !op
|
550
|
-
raise LoadError, "empty opcodes"
|
551
|
-
end
|
552
|
-
case op.code
|
553
|
-
when :i32_const
|
554
|
-
arg = op.operand[0]
|
555
|
-
if !arg.is_a?(Integer)
|
556
|
-
raise "Invalid definition of operand"
|
557
|
-
end
|
558
|
-
return arg
|
559
|
-
else
|
560
|
-
raise "Unimplemented offset op: #{op.code.inspect}"
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
# @rbs return: ExportSection
|
565
|
-
def self.export_section
|
566
|
-
dest = ExportSection.new
|
567
|
-
size = fetch_uleb128(@buf)
|
568
|
-
dest.size = size
|
569
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
570
|
-
|
571
|
-
len = fetch_uleb128(sbuf)
|
572
|
-
len.times do |i|
|
573
|
-
nlen = fetch_uleb128(sbuf)
|
574
|
-
name = assert_read(sbuf, nlen)
|
575
|
-
kind_ = assert_read(sbuf, 1)
|
576
|
-
kind = kind_[0]&.ord
|
577
|
-
if !kind
|
578
|
-
raise "[BUG] empty unpacked string" # guard rbs
|
579
|
-
end
|
580
|
-
|
581
|
-
index = fetch_uleb128(sbuf)
|
582
|
-
dest.add_desc do |desc|
|
583
|
-
desc.name = name
|
584
|
-
desc.kind = kind
|
585
|
-
desc.func_index = index
|
586
|
-
end
|
587
|
-
end
|
588
|
-
|
589
|
-
dest
|
590
|
-
end
|
591
|
-
|
592
|
-
# @rbs code: Integer
|
593
|
-
# @rbs return: nil
|
594
|
-
def self.unimplemented_skip_section(code)
|
595
|
-
$stderr.puts "warning: unimplemented section: 0x0#{code}"
|
596
|
-
size = @buf.read(1)&.ord
|
597
|
-
@buf.read(size)
|
598
|
-
nil
|
599
|
-
end
|
600
|
-
|
601
|
-
# @rbs sbuf: StringIO
|
602
|
-
# @rbs n: Integer
|
603
|
-
# @rbs return: String
|
604
|
-
def self.assert_read(sbuf, n)
|
605
|
-
ret = sbuf.read n
|
606
|
-
if !ret
|
607
|
-
raise LoadError, "too short section size"
|
608
|
-
end
|
609
|
-
if ret.size != n
|
610
|
-
raise LoadError, "too short section size"
|
611
|
-
end
|
612
|
-
ret
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
27
|
class Instance
|
617
28
|
attr_accessor :version #: Integer
|
618
29
|
|
@@ -671,6 +82,18 @@ module Wardite
|
|
671
82
|
sec
|
672
83
|
end
|
673
84
|
|
85
|
+
# @rbs return: GlobalSection|nil
|
86
|
+
def global_section
|
87
|
+
sec = @sections.find{|s| s.code == Const::SectionGlobal }
|
88
|
+
if !sec
|
89
|
+
return nil
|
90
|
+
end
|
91
|
+
if !sec.is_a?(GlobalSection)
|
92
|
+
raise(GenericError, "instance doesn't have required section")
|
93
|
+
end
|
94
|
+
sec
|
95
|
+
end
|
96
|
+
|
674
97
|
# @rbs return: DataSection|nil
|
675
98
|
def data_section
|
676
99
|
sec = @sections.find{|s| s.code == Const::SectionData }
|
@@ -985,6 +408,36 @@ module Wardite
|
|
985
408
|
end
|
986
409
|
frame.locals[idx] = value
|
987
410
|
|
411
|
+
when :global_get
|
412
|
+
idx = insn.operand[0]
|
413
|
+
if !idx.is_a?(Integer)
|
414
|
+
raise EvalError, "[BUG] invalid type of operand"
|
415
|
+
end
|
416
|
+
global = instance.store.globals[idx]
|
417
|
+
if !global
|
418
|
+
raise EvalError, "global not found"
|
419
|
+
end
|
420
|
+
stack.push(global.value)
|
421
|
+
|
422
|
+
when :global_set
|
423
|
+
idx = insn.operand[0]
|
424
|
+
if !idx.is_a?(Integer)
|
425
|
+
raise EvalError, "[BUG] invalid type of operand"
|
426
|
+
end
|
427
|
+
current_global = instance.store.globals[idx]
|
428
|
+
if !current_global
|
429
|
+
raise EvalError, "global index not valid"
|
430
|
+
end
|
431
|
+
if !current_global.mutable?
|
432
|
+
raise EvalError, "global not mutable"
|
433
|
+
end
|
434
|
+
value = stack.pop
|
435
|
+
if !value
|
436
|
+
raise EvalError, "value should be pushed"
|
437
|
+
end
|
438
|
+
current_global.value = value
|
439
|
+
instance.store.globals[idx] = current_global
|
440
|
+
|
988
441
|
when :memory_size
|
989
442
|
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
990
443
|
stack.push(I32(memory.current))
|
@@ -1137,9 +590,11 @@ module Wardite
|
|
1137
590
|
attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
|
1138
591
|
|
1139
592
|
# FIXME: attr_accessor :modules
|
1140
|
-
|
593
|
+
|
1141
594
|
attr_accessor :memories #: Array[Memory]
|
1142
595
|
|
596
|
+
attr_accessor :globals #: Array[Global]
|
597
|
+
|
1143
598
|
# @rbs inst: Instance
|
1144
599
|
# @rbs return: void
|
1145
600
|
def initialize(inst)
|
@@ -1201,6 +656,19 @@ module Wardite
|
|
1201
656
|
end
|
1202
657
|
end
|
1203
658
|
end
|
659
|
+
|
660
|
+
@globals = []
|
661
|
+
global_section = inst.global_section
|
662
|
+
if global_section
|
663
|
+
global_section.globals.each do |g|
|
664
|
+
@globals << Global.new do |g2|
|
665
|
+
g2.type = g.type
|
666
|
+
g2.mutable = g.mutable
|
667
|
+
g2.shared = g.shared
|
668
|
+
g2.value = g.value
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
1204
672
|
end
|
1205
673
|
|
1206
674
|
# @rbs idx: Integer
|
@@ -1243,6 +711,26 @@ module Wardite
|
|
1243
711
|
end
|
1244
712
|
end
|
1245
713
|
|
714
|
+
class Global
|
715
|
+
attr_accessor :type #: Symbol
|
716
|
+
|
717
|
+
attr_accessor :mutable #: bool
|
718
|
+
|
719
|
+
# TODO: unused in wasm 1.0 spec?
|
720
|
+
attr_accessor :shared #: bool
|
721
|
+
|
722
|
+
attr_accessor :value #: I32|I64|F32|F64
|
723
|
+
|
724
|
+
# @rbs &blk: (Global) -> void
|
725
|
+
# @rbs return: void
|
726
|
+
def initialize(&blk)
|
727
|
+
blk.call(self)
|
728
|
+
end
|
729
|
+
|
730
|
+
alias mutable? mutable
|
731
|
+
alias shared? shared
|
732
|
+
end
|
733
|
+
|
1246
734
|
class WasmData
|
1247
735
|
attr_accessor :memory_index #: Integer
|
1248
736
|
|
@@ -24,9 +24,9 @@ module Wardite
|
|
24
24
|
# @rbs return: [Symbol, Symbol]
|
25
25
|
def self.to_sym: (String chr) -> [ Symbol, Symbol ]
|
26
26
|
|
27
|
-
# @rbs
|
27
|
+
# @rbs code: Symbol
|
28
28
|
# @rbs return: Array[Symbol]
|
29
|
-
def self.operand_of: (
|
29
|
+
def self.operand_of: (Symbol code) -> Array[Symbol]
|
30
30
|
|
31
31
|
# @see https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
|
32
32
|
# @rbs code: Integer
|