wardite 0.2.1 → 0.3.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.
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
 
@@ -620,13 +31,15 @@ module Wardite
620
31
 
621
32
  attr_accessor :runtime #: Runtime
622
33
 
34
+ attr_accessor :types #: Array[Type]
35
+
623
36
  attr_accessor :store #: Store
624
37
 
625
38
  attr_accessor :exports #: Exports
626
39
 
627
- attr_reader :import_object #: Hash[Symbol, Hash[Symbol, Proc]]
40
+ attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
628
41
 
629
- # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
42
+ # @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
630
43
  # @rbs &blk: (Instance) -> void
631
44
  def initialize(import_object, &blk)
632
45
  blk.call(self)
@@ -635,6 +48,15 @@ module Wardite
635
48
  @store = Store.new(self)
636
49
  @exports = Exports.new(self.export_section, store)
637
50
  @runtime = Runtime.new(self)
51
+
52
+ @types = []
53
+ type_section = self.type_section
54
+ if type_section
55
+ type_section.defined_types.each_with_index do |calltype, idx|
56
+ rettype = type_section.defined_results[idx]
57
+ @types << Type.new(calltype, rettype)
58
+ end
59
+ end
638
60
  end
639
61
 
640
62
  # @rbs return: ImportSection
@@ -671,6 +93,30 @@ module Wardite
671
93
  sec
672
94
  end
673
95
 
96
+ # @rbs return: StartSection|nil
97
+ def start_section
98
+ sec = @sections.find{|s| s.code == Const::SectionStart }
99
+ if !sec
100
+ return nil
101
+ end
102
+ if !sec.is_a?(StartSection)
103
+ raise(GenericError, "[BUG] found invalid start section")
104
+ end
105
+ sec
106
+ end
107
+
108
+ # @rbs return: GlobalSection|nil
109
+ def global_section
110
+ sec = @sections.find{|s| s.code == Const::SectionGlobal }
111
+ if !sec
112
+ return nil
113
+ end
114
+ if !sec.is_a?(GlobalSection)
115
+ raise(GenericError, "instance doesn't have required section")
116
+ end
117
+ sec
118
+ end
119
+
674
120
  # @rbs return: DataSection|nil
675
121
  def data_section
676
122
  sec = @sections.find{|s| s.code == Const::SectionData }
@@ -695,6 +141,30 @@ module Wardite
695
141
  sec
696
142
  end
697
143
 
144
+ # @rbs return: TableSection?
145
+ def table_section
146
+ sec = @sections.find{|s| s.code == Const::SectionTable }
147
+ if !sec
148
+ return nil
149
+ end
150
+ if !sec.is_a?(TableSection)
151
+ raise(GenericError, "instance doesn't have required section")
152
+ end
153
+ sec
154
+ end
155
+
156
+ # @rbs return: ElemSection?
157
+ def elem_section
158
+ sec = @sections.find{|s| s.code == Const::SectionElement }
159
+ if !sec
160
+ return nil
161
+ end
162
+ if !sec.is_a?(ElemSection)
163
+ raise(GenericError, "instance doesn't have required section")
164
+ end
165
+ sec
166
+ end
167
+
698
168
  # @rbs return: CodeSection|nil
699
169
  def code_section
700
170
  sec = @sections.find{|s| s.code == Const::SectionCode }
@@ -724,7 +194,7 @@ module Wardite
724
194
  include ValueHelper
725
195
 
726
196
  # TODO: add types of class that the stack accomodates
727
- attr_accessor :stack #: Array[I32|I64|F32|F64]
197
+ attr_accessor :stack #: Array[wasmValue]
728
198
 
729
199
  attr_accessor :call_stack #: Array[Frame]
730
200
 
@@ -735,8 +205,18 @@ module Wardite
735
205
  @stack = []
736
206
  @call_stack = []
737
207
  @instance = inst
208
+
209
+ invoke_start_section
738
210
  end
739
211
 
212
+ # @rbs return: void
213
+ def invoke_start_section
214
+ start_section = instance.start_section
215
+ if start_section
216
+ call_by_index(start_section.func_index)
217
+ end
218
+ end
219
+
740
220
  # @rbs name: String|Symbol
741
221
  # @rbs return: bool
742
222
  def callable?(name)
@@ -777,6 +257,21 @@ module Wardite
777
257
  end
778
258
  end
779
259
 
260
+ # @rbs idx: Integer
261
+ # @rbs return: void
262
+ def call_by_index(idx)
263
+ fn = @instance.store.funcs[idx]
264
+
265
+ case fn
266
+ when WasmFunction
267
+ invoke_internal(fn)
268
+ when ExternalFunction
269
+ invoke_external(fn)
270
+ else
271
+ raise GenericError, "registered pointer is not to a function"
272
+ end
273
+ end
274
+
780
275
  # @rbs wasm_function: WasmFunction
781
276
  # @rbs return: void
782
277
  def push_frame(wasm_function)
@@ -826,7 +321,7 @@ module Wardite
826
321
  end
827
322
 
828
323
  # @rbs external_function: ExternalFunction
829
- # @rbs return: I32|I64|F32|F64|nil
324
+ # @rbs return: wasmValue|nil
830
325
  def invoke_external(external_function)
831
326
  local_start = stack.size - external_function.callsig.size
832
327
  args = stack[local_start..]
@@ -903,19 +398,80 @@ module Wardite
903
398
  when :nop
904
399
  return
905
400
 
401
+ when :br
402
+ level = insn.operand[0]
403
+ raise EvalError, "br op without level" if !level.is_a?(Integer)
404
+ pc = do_branch(frame.labels, stack, level)
405
+ frame.pc = pc
406
+
407
+ when :br_if
408
+ level = insn.operand[0]
409
+ raise EvalError, "br op without level" if !level.is_a?(Integer)
410
+ cond = stack.pop
411
+ raise EvalError, "cond not found" if !cond.is_a?(I32)
412
+ if cond.value.zero?
413
+ return
414
+ end
415
+ pc = do_branch(frame.labels, stack, level)
416
+ frame.pc = pc
417
+
418
+ when :br_table
419
+ level_vec = insn.operand[0]
420
+ raise EvalError, "no level vector" if !level_vec.is_a?(Array)
421
+ default = insn.operand[1]
422
+ raise EvalError, "no default specified" if !default.is_a?(Integer)
423
+ idx = stack.pop
424
+ raise EvalError, "idx not found" if !idx.is_a?(I32)
425
+ level = if idx.value_s < 0 || idx.value_s >= level_vec.size
426
+ default
427
+ else
428
+ level_vec[idx.value_s]
429
+ end
430
+ pc = do_branch(frame.labels, stack, level)
431
+ frame.pc = pc
432
+
433
+ when :block
434
+ block = insn.operand[0]
435
+ raise EvalError, "block op without block" if !block.is_a?(Block)
436
+ next_pc = fetch_ops_while_end(frame.body, frame.pc)
437
+ label = Label.new(:block, next_pc, stack.size, block.result_size)
438
+ frame.labels.push(label)
439
+
440
+ when :loop
441
+ block = insn.operand[0]
442
+ raise EvalError, "loop op without block" if !block.is_a?(Block)
443
+ start = frame.pc
444
+ end_pc = fetch_ops_while_end(frame.body, frame.pc)
445
+ label = Label.new(:loop, end_pc, stack.size, block.result_size, start)
446
+ frame.labels.push(label)
447
+
906
448
  when :if
907
449
  block = insn.operand[0]
908
450
  raise EvalError, "if op without block" if !block.is_a?(Block)
909
451
  cond = stack.pop
910
452
  raise EvalError, "cond not found" if !cond.is_a?(I32)
911
453
  next_pc = fetch_ops_while_end(frame.body, frame.pc)
454
+
912
455
  if cond.value.zero?
913
- frame.pc = next_pc
456
+ frame.pc = fetch_ops_while_else_or_end(frame.body, frame.pc)
457
+ end
458
+
459
+ if frame.pc == next_pc
460
+ # This means if block has no else instr.
461
+ return
914
462
  end
915
463
 
916
464
  label = Label.new(:if, next_pc, stack.size, block.result_size)
917
465
  frame.labels.push(label)
918
466
 
467
+ when :else
468
+ if old_label = frame.labels.pop
469
+ frame.pc = old_label.pc
470
+ stack_unwind(old_label.sp, old_label.arity)
471
+ else
472
+ raise EvalError, "else should be in if block"
473
+ end
474
+
919
475
  when :call
920
476
  idx = insn.operand[0]
921
477
  raise EvalError, "[BUG] local operand not found" if !idx.is_a?(Integer)
@@ -930,6 +486,45 @@ module Wardite
930
486
  raise GenericError, "got a non-function pointer"
931
487
  end
932
488
 
489
+ when :call_indirect
490
+ table = self.instance.store.tables[0]
491
+ raise EvalError, "table required but not found" if !table
492
+ type_idx = insn.operand[0]
493
+ raise EvalError, "[BUG] index operand invalid" if !type_idx.is_a?(Integer)
494
+ nullbyte = insn.operand[1]
495
+ raise EvalError, "[BUG] invalid bytearray of call_indirect" if nullbyte != 0x0
496
+ table_idx = stack.pop
497
+ raise EvalError, "[BUG] index stack invalid" if !table_idx.is_a?(I32)
498
+ fntype = self.instance.types[type_idx]
499
+ if !fntype
500
+ raise EvalError, "undefined type index: idx=#{type_idx}"
501
+ end
502
+ refs = self.instance.store.tables[0]&.refs
503
+ if !refs
504
+ raise EvalError, "uninitialized element idx:#{table_idx}"
505
+ end
506
+
507
+ fn = refs[table_idx.value]
508
+ case fn
509
+ when WasmFunction
510
+ if table.type != :funcref
511
+ raise EvalError, "invalid type of elem; expected: #{table.type}"
512
+ end
513
+ fn = fn.clone(override_type: fntype)
514
+ push_frame(fn)
515
+ when ExternalFunction
516
+ if table.type != :externref
517
+ raise EvalError, "invalid type of elem; expected: #{table.type}"
518
+ end
519
+ fn = fn.clone(override_type: fntype)
520
+ ret = invoke_external(fn)
521
+ self.stack.push ret if ret
522
+ when nil
523
+ raise EvalError, "uninitialized element idx:#{table_idx.value}"
524
+ else
525
+ raise EvalError, "[BUG] unknwon function type #{fn}"
526
+ end
527
+
933
528
  when :return
934
529
  old_frame = call_stack.pop
935
530
  if !old_frame
@@ -985,6 +580,48 @@ module Wardite
985
580
  end
986
581
  frame.locals[idx] = value
987
582
 
583
+ when :local_tee
584
+ idx = insn.operand[0]
585
+ if !idx.is_a?(Integer)
586
+ raise EvalError, "[BUG] invalid type of operand"
587
+ end
588
+ value = stack.pop
589
+ if !value
590
+ raise EvalError, "value should be pushed"
591
+ end
592
+ frame.locals[idx] = value
593
+ stack.push value
594
+
595
+ when :global_get
596
+ idx = insn.operand[0]
597
+ if !idx.is_a?(Integer)
598
+ raise EvalError, "[BUG] invalid type of operand"
599
+ end
600
+ global = instance.store.globals[idx]
601
+ if !global
602
+ raise EvalError, "global not found"
603
+ end
604
+ stack.push(global.value)
605
+
606
+ when :global_set
607
+ idx = insn.operand[0]
608
+ if !idx.is_a?(Integer)
609
+ raise EvalError, "[BUG] invalid type of operand"
610
+ end
611
+ current_global = instance.store.globals[idx]
612
+ if !current_global
613
+ raise EvalError, "global index not valid"
614
+ end
615
+ if !current_global.mutable?
616
+ raise EvalError, "global not mutable"
617
+ end
618
+ value = stack.pop
619
+ if !value
620
+ raise EvalError, "value should be pushed"
621
+ end
622
+ current_global.value = value
623
+ instance.store.globals[idx] = current_global
624
+
988
625
  when :memory_size
989
626
  memory = instance.store.memories[0] || raise("[BUG] no memory")
990
627
  stack.push(I32(memory.current))
@@ -1003,11 +640,69 @@ module Wardite
1003
640
 
1004
641
  rescue => e
1005
642
  require "pp"
643
+ $stderr.puts "instance:::\n#{self.instance.pretty_inspect}"
1006
644
  $stderr.puts "frame:::\n#{frame.pretty_inspect}"
1007
645
  $stderr.puts "stack:::\n#{stack.pretty_inspect}"
1008
646
  raise e
1009
647
  end
1010
648
 
649
+ # @rbs ops: Array[Op]
650
+ # @rbs pc_start: Integer
651
+ # @rbs return: Integer
652
+ def fetch_ops_while_else_or_end(ops, pc_start)
653
+ cursor = pc_start
654
+ depth = 0
655
+ loop {
656
+ cursor += 1
657
+ inst = ops[cursor]
658
+ case inst&.code
659
+ when nil
660
+ raise EvalError, "end op not found"
661
+ when :if
662
+ depth += 1
663
+ when :else
664
+ if depth == 0
665
+ return cursor
666
+ end
667
+ # do not touch depth
668
+ when :end
669
+ if depth == 0
670
+ return cursor
671
+ else
672
+ depth -= 1
673
+ end
674
+ else
675
+ # nop
676
+ end
677
+ }
678
+ raise "[BUG] unreachable"
679
+ end
680
+
681
+ # @rbs labels: Array[Label]
682
+ # @rbs stack: Array[wasmValue]
683
+ # @rbs level: Integer
684
+ # @rbs return: Integer
685
+ def do_branch(labels, stack, level)
686
+ idx = labels.size - 1 - level
687
+ label = labels[idx]
688
+ pc = if label.kind == :loop
689
+ # keep the top of labels for loop again...
690
+ while labels.size > idx + 1
691
+ labels.pop
692
+ end
693
+ stack_unwind(label.sp, 0)
694
+ label.start || raise(EvalError, "loop withour start")
695
+ else
696
+ while labels.size > idx
697
+ labels.pop
698
+ end
699
+ stack_unwind(label.sp, label.arity)
700
+ label.pc
701
+ end
702
+
703
+ pc
704
+ end
705
+
1011
706
  # @rbs ops: Array[Op]
1012
707
  # @rbs pc_start: Integer
1013
708
  # @rbs return: Integer
@@ -1020,7 +715,7 @@ module Wardite
1020
715
  case inst&.code
1021
716
  when nil
1022
717
  raise EvalError, "end op not found"
1023
- when :i
718
+ when :if, :block, :loop
1024
719
  depth += 1
1025
720
  when :end
1026
721
  if depth == 0
@@ -1056,7 +751,7 @@ module Wardite
1056
751
  end
1057
752
 
1058
753
  # @rbs finish: Integer
1059
- # @rbs return: Array[I32|I64|F32|F64]
754
+ # @rbs return: Array[wasmValue]
1060
755
  def drained_stack(finish)
1061
756
  drained = stack[0...finish]
1062
757
  if ! drained
@@ -1084,6 +779,20 @@ module Wardite
1084
779
  end
1085
780
  end
1086
781
 
782
+ class Type
783
+ attr_accessor :callsig #: Array[Symbol]
784
+
785
+ attr_accessor :retsig #: Array[Symbol]
786
+
787
+ # @rbs callsig: Array[Symbol]
788
+ # @rbs retsig: Array[Symbol]
789
+ # @rbs returb: void
790
+ def initialize(callsig, retsig)
791
+ @callsig = callsig
792
+ @retsig = retsig
793
+ end
794
+ end
795
+
1087
796
  class Frame
1088
797
  attr_accessor :pc #: Integer
1089
798
  attr_accessor :sp #: Integer
@@ -1094,13 +803,13 @@ module Wardite
1094
803
 
1095
804
  attr_accessor :labels #: Array[Label]
1096
805
 
1097
- attr_accessor :locals #: Array[I32|I64|F32|F64]
806
+ attr_accessor :locals #: Array[wasmValue]
1098
807
 
1099
808
  # @rbs pc: Integer
1100
809
  # @rbs sp: Integer
1101
810
  # @rbs body: Array[Op]
1102
811
  # @rbs arity: Integer
1103
- # @rbs locals: Array[Object]
812
+ # @rbs locals: Array[wasmValue]
1104
813
  # @rbs returb: void
1105
814
  def initialize(pc, sp, body, arity, locals)
1106
815
  @pc = pc
@@ -1120,16 +829,20 @@ module Wardite
1120
829
 
1121
830
  attr_accessor :arity #: Integer
1122
831
 
832
+ attr_accessor :start #: Integer|nil
833
+
1123
834
  # @rbs kind: (:if|:loop|:block)
1124
835
  # @rbs pc: Integer
1125
836
  # @rbs sp: Integer
1126
837
  # @rbs arity: Integer
1127
- # @rbs returb: void
1128
- def initialize(kind, pc, sp, arity)
838
+ # @rbs start: Integer|nil
839
+ # @rbs return: void
840
+ def initialize(kind, pc, sp, arity, start=nil)
1129
841
  @kind = kind
1130
842
  @pc = pc
1131
843
  @sp = sp
1132
844
  @arity = arity
845
+ @start = start
1133
846
  end
1134
847
  end
1135
848
 
@@ -1137,9 +850,15 @@ module Wardite
1137
850
  attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
1138
851
 
1139
852
  # FIXME: attr_accessor :modules
1140
-
853
+
1141
854
  attr_accessor :memories #: Array[Memory]
1142
855
 
856
+ attr_accessor :globals #: Array[Global]
857
+
858
+ attr_accessor :tables #: Array[Table]
859
+
860
+ attr_accessor :elements #: Array[[Symbol, Integer, Array[Integer]]]
861
+
1143
862
  # @rbs inst: Instance
1144
863
  # @rbs return: void
1145
864
  def initialize(inst)
@@ -1201,6 +920,69 @@ module Wardite
1201
920
  end
1202
921
  end
1203
922
  end
923
+
924
+ @globals = []
925
+ global_section = inst.global_section
926
+ if global_section
927
+ global_section.globals.each do |g|
928
+ @globals << Global.new do |g2|
929
+ g2.type = g.type
930
+ g2.mutable = g.mutable
931
+ g2.shared = g.shared
932
+ g2.value = g.value
933
+ end
934
+ end
935
+ end
936
+
937
+ @tables = []
938
+ @elements = []
939
+ table_section = inst.table_section
940
+ if table_section
941
+ table_section.table_types.each_with_index do |typ, idx|
942
+ init, max = *table_section.table_limits[idx]
943
+ if !init
944
+ raise LoadError, "empty limits"
945
+ end
946
+ table = Table.new(typ, init, max)
947
+ @tables << table
948
+ end
949
+ end
950
+
951
+ elem_section = inst.elem_section
952
+ if elem_section
953
+ elem_section.table_indices.each_with_index do |tidx, idx|
954
+ table = @tables[tidx]
955
+ if !table
956
+ raise LoadError, "invalid table index #{tidx}"
957
+ end
958
+ typ = table.type
959
+ offset = elem_section.table_offsets[idx]
960
+ if !offset
961
+ raise LoadError, "invalid element index #{idx}"
962
+ end
963
+ indices = elem_section.element_indices[idx]
964
+ if !indices
965
+ raise LoadError, "invalid element index #{idx}"
966
+ end
967
+ elms = [typ, offset, indices] #: [Symbol, Integer, Array[Integer]]
968
+ @elements << elms
969
+ end
970
+ end
971
+
972
+ @elements.each_with_index do |(typ, offset, indices), idx|
973
+ table = @tables[idx]
974
+ if !table
975
+ raise LoadError, "invalid table index #{idx}"
976
+ end
977
+ indices.each_with_index do |eidx, tidx|
978
+ case typ
979
+ when :funcref
980
+ table.set(offset + tidx, @funcs[eidx])
981
+ when :externref
982
+ raise NotImplementedError, "no support :externref"
983
+ end
984
+ end
985
+ end
1204
986
  end
1205
987
 
1206
988
  # @rbs idx: Integer
@@ -1243,6 +1025,58 @@ module Wardite
1243
1025
  end
1244
1026
  end
1245
1027
 
1028
+ class Table
1029
+ attr_accessor :type #: Symbol
1030
+
1031
+ attr_accessor :current #: Integer
1032
+
1033
+ attr_accessor :max #: Integer|nil
1034
+
1035
+ attr_accessor :refs #: Array[WasmFunction|ExternalFunction|nil]
1036
+
1037
+ # @rbs type: Symbol
1038
+ # @rbs init: Integer
1039
+ # @rbs max: Integer|nil
1040
+ # @rbs return: void
1041
+ def initialize(type, init, max)
1042
+ @type = type
1043
+ @current = init
1044
+ @max = max
1045
+
1046
+ @refs = Array.new(3, nil)
1047
+ end
1048
+
1049
+ # @rbs idx: Integer
1050
+ # @rbs elem: WasmFunction|ExternalFunction|nil
1051
+ # @rbs return: void
1052
+ def set(idx, elem)
1053
+ if idx >= @current
1054
+ raise GenericError, "idx too large for table"
1055
+ end
1056
+ @refs[idx] = elem
1057
+ end
1058
+ end
1059
+
1060
+ class Global
1061
+ attr_accessor :type #: Symbol
1062
+
1063
+ attr_accessor :mutable #: bool
1064
+
1065
+ # TODO: unused in wasm 1.0 spec?
1066
+ attr_accessor :shared #: bool
1067
+
1068
+ attr_accessor :value #: wasmValue
1069
+
1070
+ # @rbs &blk: (Global) -> void
1071
+ # @rbs return: void
1072
+ def initialize(&blk)
1073
+ blk.call(self)
1074
+ end
1075
+
1076
+ alias mutable? mutable
1077
+ alias shared? shared
1078
+ end
1079
+
1246
1080
  class WasmData
1247
1081
  attr_accessor :memory_index #: Integer
1248
1082
 
@@ -1341,25 +1175,51 @@ module Wardite
1341
1175
  # @rbs return: Array[Integer]
1342
1176
  def locals_count
1343
1177
  code_body.locals_count
1344
- end
1178
+ end
1179
+
1180
+ # @rbs override_type: Type?
1181
+ # @rbs return: WasmFunction
1182
+ def clone(override_type: nil)
1183
+ if override_type
1184
+ # code_body is assumed to be frozen, so we can copy its ref
1185
+ WasmFunction.new(override_type.callsig, override_type.retsig, code_body)
1186
+ else
1187
+ WasmFunction.new(callsig, retsig, code_body)
1188
+ end
1189
+ end
1345
1190
  end
1346
1191
 
1192
+ # @rbs!
1193
+ # type wasmFuncReturn = Object|nil
1194
+ # type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
1195
+
1347
1196
  class ExternalFunction
1348
1197
  attr_accessor :callsig #: Array[Symbol]
1349
1198
 
1350
1199
  attr_accessor :retsig #: Array[Symbol]
1351
1200
 
1352
- attr_accessor :callable #: Proc
1201
+ attr_accessor :callable #: wasmCallable
1353
1202
 
1354
1203
  # @rbs callsig: Array[Symbol]
1355
1204
  # @rbs retsig: Array[Symbol]
1356
- # @rbs callable: Proc
1205
+ # @rbs callable: wasmCallable
1357
1206
  # @rbs return: void
1358
1207
  def initialize(callsig, retsig, callable)
1359
1208
  @callsig = callsig
1360
1209
  @retsig = retsig
1361
1210
  @callable = callable
1362
1211
  end
1212
+
1213
+ # @rbs override_type: Type?
1214
+ # @rbs return: ExternalFunction
1215
+ def clone(override_type: nil)
1216
+ if override_type
1217
+ # callable is assumed to be frozen, so we can copy its ref
1218
+ ExternalFunction.new(override_type.callsig, override_type.retsig, callable)
1219
+ else
1220
+ ExternalFunction.new(callsig, retsig, callable)
1221
+ end
1222
+ end
1363
1223
  end
1364
1224
 
1365
1225
  class GenericError < StandardError; end