wardite 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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