wardite 0.2.0 → 0.2.2

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
@@ -13,570 +14,16 @@ module Wardite
13
14
  end
14
15
  end
15
16
  require_relative "wardite/alu_i32.generated"
17
+ require_relative "wardite/alu_i64.generated"
18
+ require_relative "wardite/alu_f32.generated"
19
+ require_relative "wardite/alu_f64.generated"
20
+ require_relative "wardite/convert.generated"
16
21
 
17
22
  require_relative "wardite/wasi"
18
23
 
19
24
  require "stringio"
20
25
 
21
26
  module Wardite
22
- class Section
23
- attr_accessor :name #: String
24
-
25
- attr_accessor :code #: Integer
26
-
27
- attr_accessor :size #: Integer
28
- end
29
-
30
- class TypeSection < Section
31
- attr_accessor :defined_types #: Array[Array[Symbol]]
32
-
33
- attr_accessor :defined_results #: Array[Array[Symbol]]
34
-
35
- # @rbs return: void
36
- def initialize
37
- self.name = "Type"
38
- self.code = 0x1
39
-
40
- @defined_types = []
41
- @defined_results = []
42
- end
43
- end
44
-
45
- class FunctionSection < Section
46
- attr_accessor :func_indices #: Array[Integer]
47
-
48
- # @rbs return: void
49
- def initialize
50
- self.name = "Function"
51
- self.code = 0x3
52
-
53
- @func_indices = []
54
- end
55
- end
56
-
57
- class MemorySection < Section
58
- attr_accessor :limits #: Array[[Integer, Integer|nil]]
59
-
60
- # @rbs return: void
61
- def initialize
62
- self.name = "Memory"
63
- self.code = 0x5
64
-
65
- @limits = []
66
- end
67
- end
68
-
69
- class CodeSection < Section
70
- class CodeBody
71
- attr_accessor :locals_count #: Array[Integer]
72
-
73
- attr_accessor :locals_type #: Array[Symbol]
74
-
75
- attr_accessor :body #: Array[Op]
76
-
77
- # @rbs &blk: (CodeBody) -> void
78
- # @rbs return: void
79
- def initialize(&blk)
80
- blk.call(self)
81
- end
82
- end
83
-
84
- attr_accessor :func_codes #:Array[CodeBody]
85
-
86
- # @rbs return: void
87
- def initialize
88
- self.name = "Code"
89
- self.code = 0xa
90
-
91
- @func_codes = []
92
- end
93
- end
94
-
95
- class DataSection < Section
96
- class Segment
97
- attr_accessor :flags #: Integer
98
-
99
- attr_accessor :offset #: Integer
100
-
101
- attr_accessor :data #: String
102
-
103
- # @rbs &blk: (Segment) -> void
104
- # @rbs return: void
105
- def initialize(&blk)
106
- blk.call(self)
107
- end
108
- end
109
-
110
- attr_accessor :segments #: Array[Segment]
111
-
112
- # @rbs return: void
113
- def initialize
114
- self.name = "Data"
115
- self.code = 0xb
116
-
117
- @segments = []
118
- end
119
- end
120
-
121
- class ExportSection < Section
122
- class ExportDesc
123
- attr_accessor :name #: String
124
-
125
- attr_accessor :kind #: Integer
126
-
127
- attr_accessor :func_index #: Integer
128
- end
129
-
130
- attr_accessor :exports #: Hash[String, ExportDesc]
131
-
132
- def initialize #: void
133
- self.name = "Export"
134
- self.code = 0x7
135
-
136
- @exports = {}
137
- end
138
-
139
- # @rbs &blk: (ExportDesc) -> void
140
- def add_desc(&blk)
141
- desc = ExportDesc.new
142
- blk.call(desc)
143
- self.exports[desc.name] = desc
144
- end
145
- end
146
-
147
- class ImportSection < Section
148
- class ImportDesc
149
- attr_accessor :module_name #: String
150
-
151
- attr_accessor :name #: String
152
-
153
- attr_accessor :kind #: Integer
154
-
155
- attr_accessor :sig_index #: Integer
156
- end
157
-
158
- attr_accessor :imports #: Array[ImportDesc]
159
-
160
- def initialize #: void
161
- self.name = "Import"
162
- self.code = 0x2
163
-
164
- @imports = []
165
- end
166
-
167
- # @rbs &blk: (ImportDesc) -> void
168
- def add_desc(&blk)
169
- desc = ImportDesc.new
170
- blk.call(desc) if blk
171
- self.imports << desc
172
- end
173
- end
174
-
175
- module BinaryLoader
176
- extend Wardite::Leb128Helper
177
- extend Wardite::ValueHelper
178
-
179
- # @rbs buf: File|StringIO
180
- # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
181
- # @rbs enable_wasi: boolish
182
- # @rbs return: Instance
183
- def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
184
- @buf = buf
185
-
186
- version = preamble
187
- sections_ = sections
188
-
189
- if enable_wasi
190
- wasi_env = Wardite::WasiSnapshotPreview1.new
191
- import_object[:wasi_snapshot_preview1] = wasi_env.to_module
192
- end
193
-
194
- return Instance.new(import_object) do |i|
195
- i.version = version
196
- i.sections = sections_
197
- end
198
- end
199
-
200
- # @rbs return: Integer
201
- def self.preamble
202
- asm = @buf.read 4
203
- if !asm
204
- raise LoadError, "buffer too short"
205
- end
206
- if asm != "\u0000asm"
207
- raise LoadError, "invalid preamble"
208
- end
209
-
210
- vstr = @buf.read(4)
211
- if !vstr
212
- raise LoadError, "buffer too short"
213
- end
214
- version = vstr.to_enum(:chars)
215
- .with_index
216
- .inject(0) {|dest, (c, i)| dest | (c.ord << i*8) }
217
- if version != 1
218
- raise LoadError, "unsupported version: #{version}"
219
- end
220
- version
221
- end
222
-
223
- # @rbs return: Array[Section]
224
- def self.sections
225
- sections = [] #: Array[Section]
226
-
227
- loop do
228
- byte = @buf.read(1)
229
- if !byte
230
- break
231
- end
232
- code = byte.ord
233
-
234
- section = case code
235
- when Wardite::SectionType
236
- type_section
237
- when Wardite::SectionImport
238
- import_section
239
- when Wardite::SectionFunction
240
- function_section
241
- when Wardite::SectionTable
242
- unimplemented_skip_section(code)
243
- when Wardite::SectionMemory
244
- memory_section
245
- when Wardite::SectionGlobal
246
- unimplemented_skip_section(code)
247
- when Wardite::SectionExport
248
- export_section
249
- when Wardite::SectionStart
250
- unimplemented_skip_section(code)
251
- when Wardite::SectionElement
252
- unimplemented_skip_section(code)
253
- when Wardite::SectionCode
254
- code_section
255
- when Wardite::SectionData
256
- data_section
257
- when Wardite::SectionCustom
258
- unimplemented_skip_section(code)
259
- else
260
- raise LoadError, "unknown code: #{code}(\"#{code.to_s 16}\")"
261
- end
262
-
263
- if section
264
- sections << section
265
- end
266
- end
267
- sections
268
- end
269
-
270
- # @rbs return: TypeSection
271
- def self.type_section
272
- dest = TypeSection.new
273
-
274
- size = fetch_uleb128(@buf)
275
- dest.size = size
276
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
277
-
278
- len = fetch_uleb128(sbuf)
279
- len.times do |i|
280
- fncode = assert_read(sbuf, 1)
281
- if fncode != "\x60"
282
- raise LoadError, "not a function definition"
283
- end
284
-
285
- arglen = fetch_uleb128(sbuf)
286
- arg = []
287
- arglen.times do
288
- case ty = assert_read(sbuf, 1)&.ord
289
- when 0x7f
290
- arg << :i32
291
- when 0x7e
292
- arg << :i64
293
- else
294
- raise NotImplementedError, "unsupported for now: #{ty.inspect}"
295
- end
296
- end
297
- dest.defined_types << arg
298
-
299
- retlen = fetch_uleb128(sbuf)
300
- ret = []
301
- retlen.times do
302
- case ty = assert_read(sbuf, 1)&.ord
303
- when 0x7f
304
- ret << :i32
305
- when 0x7e
306
- ret << :i64
307
- else
308
- raise NotImplementedError, "unsupported for now: #{ty.inspect}"
309
- end
310
- end
311
- dest.defined_results << ret
312
- end
313
-
314
- dest
315
- end
316
-
317
- # @rbs return: ImportSection
318
- def self.import_section
319
- dest = ImportSection.new
320
- size = fetch_uleb128(@buf)
321
- dest.size = size
322
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
323
-
324
- len = fetch_uleb128(sbuf)
325
- len.times do |i|
326
- mlen = fetch_uleb128(sbuf)
327
- module_name = assert_read(sbuf, mlen)
328
- nlen = fetch_uleb128(sbuf)
329
- name = assert_read(sbuf, nlen)
330
- kind_ = assert_read(sbuf, 1)
331
- kind = kind_[0]&.ord
332
- if !kind
333
- raise "[BUG] empty unpacked string" # guard rbs
334
- end
335
-
336
- index = fetch_uleb128(sbuf)
337
- dest.add_desc do |desc|
338
- desc.module_name = module_name
339
- desc.name = name
340
- desc.kind = kind
341
- desc.sig_index = index
342
- end
343
- end
344
-
345
- dest
346
- end
347
-
348
- # @rbs return: MemorySection
349
- def self.memory_section
350
- dest = MemorySection.new
351
- size = fetch_uleb128(@buf)
352
- dest.size = size
353
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
354
-
355
- len = fetch_uleb128(sbuf)
356
- if len != 1
357
- raise LoadError, "memory section has invalid size: #{len}"
358
- end
359
- len.times do |i|
360
- flags = fetch_uleb128(sbuf)
361
- min = fetch_uleb128(sbuf)
362
-
363
- max = nil
364
- if flags != 0
365
- max = fetch_uleb128(sbuf)
366
- end
367
- dest.limits << [min, max]
368
- end
369
- dest
370
- end
371
-
372
- # @rbs return: FunctionSection
373
- def self.function_section
374
- dest = FunctionSection.new
375
- size = fetch_uleb128(@buf)
376
- dest.size = size
377
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
378
-
379
- len = fetch_uleb128(sbuf)
380
- len.times do |i|
381
- index = fetch_uleb128(sbuf)
382
- dest.func_indices << index
383
- end
384
- dest
385
- end
386
-
387
- # @rbs return: CodeSection
388
- def self.code_section
389
- dest = CodeSection.new
390
- size = fetch_uleb128(@buf)
391
- dest.size = size
392
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
393
-
394
- len = fetch_uleb128(sbuf)
395
- len.times do |i|
396
- ilen = fetch_uleb128(sbuf)
397
- code = assert_read(sbuf, ilen)
398
- last_code = code[-1]
399
- if ! last_code
400
- raise "[BUG] empty code fetched" # guard for steep check
401
- end
402
- if last_code.ord != 0x0b
403
- $stderr.puts "warning: instruction not ended with inst end(0x0b): 0x0#{last_code.ord}"
404
- end
405
- cbuf = StringIO.new(code)
406
- locals_count = []
407
- locals_type = []
408
- locals_len = fetch_uleb128(cbuf)
409
- locals_len.times do
410
- type_count = fetch_uleb128(cbuf)
411
- locals_count << type_count
412
- value_type = assert_read(cbuf, 1)&.ord
413
- locals_type << Op.i2type(value_type || -1)
414
- end
415
- body = code_body(cbuf)
416
- dest.func_codes << CodeSection::CodeBody.new do |b|
417
- b.locals_count = locals_count
418
- b.locals_type = locals_type
419
- b.body = body
420
- end
421
- end
422
- dest
423
- end
424
-
425
- # @rbs buf: StringIO
426
- # @rbs return: Array[::Wardite::Op]
427
- def self.code_body(buf)
428
- dest = []
429
- while c = buf.read(1)
430
- namespace, code = Op.to_sym(c)
431
- operand_types = Op.operand_of(code)
432
- operand = [] #: Array[Integer|Float|Block]
433
- operand_types.each do |typ|
434
- case typ
435
- when :u32
436
- operand << fetch_uleb128(buf)
437
- when :i32
438
- operand << fetch_sleb128(buf)
439
- when :u8_block # :if specific
440
- block_ope = buf.read 1
441
- if ! block_ope
442
- raise "buffer too short for if"
443
- end
444
- if block_ope.ord == 0x40
445
- operand << Block.void
446
- else
447
- operand << Block.new([block_ope.ord])
448
- end
449
- else
450
- $stderr.puts "warning: unknown type #{typ.inspect}. defaulting to u32"
451
- operand << fetch_uleb128(buf)
452
- end
453
- end
454
-
455
- dest << Op.new(namespace, code, operand)
456
- end
457
-
458
- dest
459
- end
460
-
461
- # @rbs return: DataSection
462
- def self.data_section
463
- dest = DataSection.new
464
- size = fetch_uleb128(@buf)
465
- dest.size = size
466
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
467
-
468
- len = fetch_uleb128(sbuf)
469
- len.times do |i|
470
- mem_index = fetch_uleb128(sbuf)
471
- code = fetch_insn_while_end(sbuf)
472
- ops = code_body(StringIO.new(code))
473
- offset = decode_expr(ops)
474
-
475
- len = fetch_uleb128(sbuf)
476
- data = sbuf.read len
477
- if !data
478
- raise LoadError, "buffer too short"
479
- end
480
-
481
- segment = DataSection::Segment.new do |seg|
482
- seg.flags = mem_index
483
- seg.offset = offset
484
- seg.data = data
485
- end
486
- dest.segments << segment
487
- end
488
- dest
489
- end
490
-
491
- # @rbs sbuf: StringIO
492
- # @rbs return: String
493
- def self.fetch_insn_while_end(sbuf)
494
- code = String.new("")
495
- loop {
496
- c = sbuf.read 1
497
- if !c
498
- break
499
- end
500
- code << c
501
- if c == "\u000b" # :end
502
- break
503
- end
504
- }
505
- code
506
- end
507
-
508
- # @rbs ops: Array[Op]
509
- # @rbs return: Integer
510
- def self.decode_expr(ops)
511
- # sees first opcode
512
- op = ops.first
513
- if !op
514
- raise LoadError, "empty opcodes"
515
- end
516
- case op.code
517
- when :i32_const
518
- arg = op.operand[0]
519
- if !arg.is_a?(Integer)
520
- raise "Invalid definition of operand"
521
- end
522
- return arg
523
- else
524
- raise "Unimplemented offset op: #{op.code.inspect}"
525
- end
526
- end
527
-
528
- # @rbs return: ExportSection
529
- def self.export_section
530
- dest = ExportSection.new
531
- size = fetch_uleb128(@buf)
532
- dest.size = size
533
- sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
534
-
535
- len = fetch_uleb128(sbuf)
536
- len.times do |i|
537
- nlen = fetch_uleb128(sbuf)
538
- name = assert_read(sbuf, nlen)
539
- kind_ = assert_read(sbuf, 1)
540
- kind = kind_[0]&.ord
541
- if !kind
542
- raise "[BUG] empty unpacked string" # guard rbs
543
- end
544
-
545
- index = fetch_uleb128(sbuf)
546
- dest.add_desc do |desc|
547
- desc.name = name
548
- desc.kind = kind
549
- desc.func_index = index
550
- end
551
- end
552
-
553
- dest
554
- end
555
-
556
- # @rbs code: Integer
557
- # @rbs return: nil
558
- def self.unimplemented_skip_section(code)
559
- $stderr.puts "warning: unimplemented section: 0x0#{code}"
560
- size = @buf.read(1)&.ord
561
- @buf.read(size)
562
- nil
563
- end
564
-
565
- # @rbs sbuf: StringIO
566
- # @rbs n: Integer
567
- # @rbs return: String
568
- def self.assert_read(sbuf, n)
569
- ret = sbuf.read n
570
- if !ret
571
- raise LoadError, "too short section size"
572
- end
573
- if ret.size != n
574
- raise LoadError, "too short section size"
575
- end
576
- ret
577
- end
578
- end
579
-
580
27
  class Instance
581
28
  attr_accessor :version #: Integer
582
29
 
@@ -635,6 +82,18 @@ module Wardite
635
82
  sec
636
83
  end
637
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
+
638
97
  # @rbs return: DataSection|nil
639
98
  def data_section
640
99
  sec = @sections.find{|s| s.code == Const::SectionData }
@@ -688,7 +147,7 @@ module Wardite
688
147
  include ValueHelper
689
148
 
690
149
  # TODO: add types of class that the stack accomodates
691
- attr_accessor :stack #: Array[I32|I64|F32|F64|Block]
150
+ attr_accessor :stack #: Array[I32|I64|F32|F64]
692
151
 
693
152
  attr_accessor :call_stack #: Array[Frame]
694
153
 
@@ -848,12 +307,25 @@ module Wardite
848
307
  # @rbs return: void
849
308
  def eval_insn(frame, insn)
850
309
  case insn.namespace
310
+ when :convert
311
+ return Evaluator.convert_eval_insn(self, frame, insn)
851
312
  when :i32
852
313
  return Evaluator.i32_eval_insn(self, frame, insn)
314
+ when :i64
315
+ return Evaluator.i64_eval_insn(self, frame, insn)
316
+ when :f32
317
+ return Evaluator.f32_eval_insn(self, frame, insn)
318
+ when :f64
319
+ return Evaluator.f64_eval_insn(self, frame, insn)
853
320
  end
854
321
 
855
322
  # unmached namespace...
856
323
  case insn.code
324
+ when :unreachable
325
+ raise Unreachable, "unreachable op"
326
+ when :nop
327
+ return
328
+
857
329
  when :if
858
330
  block = insn.operand[0]
859
331
  raise EvalError, "if op without block" if !block.is_a?(Block)
@@ -866,78 +338,6 @@ module Wardite
866
338
 
867
339
  label = Label.new(:if, next_pc, stack.size, block.result_size)
868
340
  frame.labels.push(label)
869
-
870
- when :local_get
871
- idx = insn.operand[0]
872
- if !idx.is_a?(Integer)
873
- raise EvalError, "[BUG] invalid type of operand"
874
- end
875
- local = frame.locals[idx]
876
- if !local
877
- raise EvalError, "local not found"
878
- end
879
- stack.push(local)
880
- when :local_set
881
- idx = insn.operand[0]
882
- if !idx.is_a?(Integer)
883
- raise EvalError, "[BUG] invalid type of operand"
884
- end
885
- value = stack.pop
886
- if !value
887
- raise EvalError, "value should be pushed"
888
- end
889
- if value.is_a?(Block)
890
- raise EvalError, "block value detected"
891
- end
892
- frame.locals[idx] = value
893
-
894
- # when :i32_lts
895
- # right, left = stack.pop, stack.pop
896
- # if !right.is_a?(Integer) || !left.is_a?(Integer)
897
- # raise EvalError, "maybe empty stack"
898
- # end
899
- # value = (left < right) ? 1 : 0
900
- # stack.push(value)
901
- # when :i32_leu
902
- # right, left = stack.pop, stack.pop
903
- # if !right.is_a?(Integer) || !left.is_a?(Integer)
904
- # raise EvalError, "maybe empty stack"
905
- # end
906
- # value = (left >= right) ? 1 : 0
907
- # stack.push(value)
908
- # when :i32_add
909
- # right, left = stack.pop, stack.pop
910
- # if !right.is_a?(Integer) || !left.is_a?(Integer)
911
- # raise EvalError, "maybe empty stack"
912
- # end
913
- # stack.push(left + right)
914
- # when :i32_sub
915
- # right, left = stack.pop, stack.pop
916
- # if !right.is_a?(Integer) || !left.is_a?(Integer)
917
- # raise EvalError, "maybe empty stack"
918
- # end
919
- # stack.push(left - right)
920
- # when :i32_const
921
- # const = insn.operand[0]
922
- # if !const.is_a?(Integer)
923
- # raise EvalError, "[BUG] invalid type of operand"
924
- # end
925
- # stack.push(const)
926
- # when :i32_store
927
- # _align = insn.operand[0] # TODO: alignment support?
928
- # offset = insn.operand[1]
929
- # raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
930
-
931
- # value = stack.pop
932
- # addr = stack.pop
933
- # if !value.is_a?(Integer) || !addr.is_a?(Integer)
934
- # raise EvalError, "maybe stack too short"
935
- # end
936
-
937
- # at = addr + offset
938
- # data_end = at + 4 # sizeof(i32)
939
- # memory = self.instance.store.memories[0] || raise("[BUG] no memory")
940
- # memory.data[at...data_end] = [value].pack("I")
941
341
 
942
342
  when :call
943
343
  idx = insn.operand[0]
@@ -972,7 +372,93 @@ module Wardite
972
372
  end
973
373
  stack_unwind(old_frame.sp, old_frame.arity)
974
374
  end
375
+
376
+ when :drop
377
+ stack.pop
378
+
379
+ when :select
380
+ cond, right, left = stack.pop, stack.pop, stack.pop
381
+ if !cond.is_a?(I32)
382
+ raise EvalError, "invalid stack for select"
383
+ end
384
+ if !right || !left
385
+ raise EvalError, "stack too short"
386
+ end
387
+ stack.push(cond.value != 0 ? left : right)
388
+
389
+ when :local_get
390
+ idx = insn.operand[0]
391
+ if !idx.is_a?(Integer)
392
+ raise EvalError, "[BUG] invalid type of operand"
393
+ end
394
+ local = frame.locals[idx]
395
+ if !local
396
+ raise EvalError, "local not found"
397
+ end
398
+ stack.push(local)
399
+
400
+ when :local_set
401
+ idx = insn.operand[0]
402
+ if !idx.is_a?(Integer)
403
+ raise EvalError, "[BUG] invalid type of operand"
404
+ end
405
+ value = stack.pop
406
+ if !value
407
+ raise EvalError, "value should be pushed"
408
+ end
409
+ frame.locals[idx] = value
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
+
441
+ when :memory_size
442
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
443
+ stack.push(I32(memory.current))
444
+
445
+ when :memory_grow
446
+ delta = stack.pop
447
+ if !delta.is_a?(I32)
448
+ raise EvalError, "maybe stack too short"
449
+ end
450
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
451
+ stack.push(I32(memory.grow(delta.value)))
452
+
453
+ else
454
+ raise "TODO! unsupported #{insn.inspect}"
975
455
  end
456
+
457
+ rescue => e
458
+ require "pp"
459
+ $stderr.puts "frame:::\n#{frame.pretty_inspect}"
460
+ $stderr.puts "stack:::\n#{stack.pretty_inspect}"
461
+ raise e
976
462
  end
977
463
 
978
464
  # @rbs ops: Array[Op]
@@ -1023,7 +509,7 @@ module Wardite
1023
509
  end
1024
510
 
1025
511
  # @rbs finish: Integer
1026
- # @rbs return: Array[I32|I64|F32|F64|Block]
512
+ # @rbs return: Array[I32|I64|F32|F64]
1027
513
  def drained_stack(finish)
1028
514
  drained = stack[0...finish]
1029
515
  if ! drained
@@ -1104,9 +590,11 @@ module Wardite
1104
590
  attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
1105
591
 
1106
592
  # FIXME: attr_accessor :modules
1107
-
593
+
1108
594
  attr_accessor :memories #: Array[Memory]
1109
595
 
596
+ attr_accessor :globals #: Array[Global]
597
+
1110
598
  # @rbs inst: Instance
1111
599
  # @rbs return: void
1112
600
  def initialize(inst)
@@ -1168,6 +656,19 @@ module Wardite
1168
656
  end
1169
657
  end
1170
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
1171
672
  end
1172
673
 
1173
674
  # @rbs idx: Integer
@@ -1179,21 +680,57 @@ module Wardite
1179
680
  class Memory
1180
681
  attr_accessor :data #: String
1181
682
 
683
+ attr_accessor :current #: Integer
684
+
1182
685
  attr_accessor :max #: Integer|nil
1183
686
 
1184
687
  # @rbs min: Integer
1185
688
  # @rbs max: Integer|nil
1186
689
  # @rbs return: void
1187
690
  def initialize(min, max)
1188
- @data = String.new("\0" * (min * 64 * 1024), capacity: min * 64 * 1024)
691
+ @data = String.new("\0" * (min * 64 * 1024))
692
+ @current = min
1189
693
  @max = max
1190
694
  end
1191
695
 
696
+ # @rbs delta: Integer
697
+ # @rbs return: Integer
698
+ def grow(delta)
699
+ prev = current
700
+ newsize = current + delta
701
+ if max && (newsize > max)
702
+ return -1
703
+ end
704
+
705
+ @data += String.new("\0" * (delta * 64 * 1024))
706
+ prev
707
+ end
708
+
1192
709
  def inspect
1193
710
  "#<Wardite::Memory initial=#{@data.size.inspect} max=#{@max.inspect} @data=#{@data[0...64].inspect}...>"
1194
711
  end
1195
712
  end
1196
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
+
1197
734
  class WasmData
1198
735
  attr_accessor :memory_index #: Integer
1199
736
 
@@ -1317,6 +854,7 @@ module Wardite
1317
854
  class LoadError < StandardError; end
1318
855
  class ArgumentError < StandardError; end
1319
856
  class EvalError < StandardError; end
857
+ class Unreachable < StandardError; end
1320
858
 
1321
859
  # @rbs path: String|nil
1322
860
  # @rbs buffer: File|StringIO|nil