wardite 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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